docs: Add one-click installation script for PPanel with Docker support
- Introduced `install-ppanel.sh` script for automated installation of PPanel using Docker Compose. - Updated installation documentation to include one-click deployment options and detailed configuration steps. - Enhanced configuration files for MySQL and Redis with necessary parameters. - Improved Docker Compose setup with health checks and custom network configurations. - Added instructions for firewall configuration and reverse proxy setup for production environments. - Included troubleshooting tips and advanced options for non-interactive installations and proxy environments.
This commit is contained in:
Executable
+216
@@ -0,0 +1,216 @@
|
||||
#!/bin/bash
|
||||
|
||||
#######################################################
|
||||
# Docker & Docker Compose Installation Script
|
||||
# Support: Ubuntu/Debian, CentOS/RHEL
|
||||
# Usage: curl -fsSL https://ppanel.dev/scripts/en/install-docker.sh | bash
|
||||
#######################################################
|
||||
|
||||
set -e
|
||||
|
||||
# 颜色输出
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# 日志函数
|
||||
log_info() {
|
||||
echo -e "${GREEN}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
log_warn() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
# Check if running as root
|
||||
check_root() {
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
log_error "This script must be run with root privileges"
|
||||
log_info "Please use: sudo bash $0"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Detect operating system
|
||||
detect_os() {
|
||||
if [[ -f /etc/os-release ]]; then
|
||||
. /etc/os-release
|
||||
OS=$ID
|
||||
VER=$VERSION_ID
|
||||
else
|
||||
log_error "Unable to detect operating system"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_info "Detected system: $OS $VER"
|
||||
}
|
||||
|
||||
# Check if Docker is already installed
|
||||
check_docker_installed() {
|
||||
if command -v docker &> /dev/null; then
|
||||
DOCKER_VERSION=$(docker --version | cut -d ' ' -f3 | cut -d ',' -f1)
|
||||
log_warn "Docker is already installed (Version: $DOCKER_VERSION)"
|
||||
read -p "Do you want to reinstall? (y/N): " -n 1 -r
|
||||
echo
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
log_info "Skipping Docker installation"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# Install Docker - Ubuntu/Debian
|
||||
install_docker_debian() {
|
||||
log_info "Installing Docker on Ubuntu/Debian..."
|
||||
|
||||
# Update package index
|
||||
apt-get update
|
||||
|
||||
# Install dependencies
|
||||
apt-get install -y \
|
||||
ca-certificates \
|
||||
curl \
|
||||
gnupg \
|
||||
lsb-release
|
||||
|
||||
# Add Docker's official GPG key
|
||||
install -m 0755 -d /etc/apt/keyrings
|
||||
curl -fsSL https://download.docker.com/linux/$OS/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
|
||||
chmod a+r /etc/apt/keyrings/docker.gpg
|
||||
|
||||
# Set up repository
|
||||
echo \
|
||||
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/$OS \
|
||||
$(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
|
||||
|
||||
# Install Docker Engine
|
||||
apt-get update
|
||||
apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
||||
|
||||
log_info "Docker installation completed"
|
||||
}
|
||||
|
||||
# Install Docker - CentOS/RHEL
|
||||
install_docker_centos() {
|
||||
log_info "Installing Docker on CentOS/RHEL..."
|
||||
|
||||
# Install yum-utils
|
||||
yum install -y yum-utils
|
||||
|
||||
# Add Docker repository
|
||||
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
|
||||
|
||||
# Install Docker Engine
|
||||
yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
||||
|
||||
log_info "Docker installation completed"
|
||||
}
|
||||
|
||||
# Start Docker service
|
||||
start_docker() {
|
||||
log_info "Starting Docker service..."
|
||||
|
||||
systemctl start docker
|
||||
systemctl enable docker
|
||||
|
||||
log_info "Docker service started and enabled at boot"
|
||||
}
|
||||
|
||||
# Configure Docker group (optional)
|
||||
configure_docker_group() {
|
||||
log_info "Configuring Docker group..."
|
||||
|
||||
if ! getent group docker > /dev/null; then
|
||||
groupadd docker
|
||||
fi
|
||||
|
||||
if [[ -n "$SUDO_USER" ]]; then
|
||||
usermod -aG docker "$SUDO_USER"
|
||||
log_info "User $SUDO_USER has been added to docker group"
|
||||
log_warn "Please log out and log back in for group permissions to take effect"
|
||||
fi
|
||||
}
|
||||
|
||||
# Verify installation
|
||||
verify_installation() {
|
||||
log_info "Verifying Docker installation..."
|
||||
|
||||
# Check Docker version
|
||||
if docker --version &> /dev/null; then
|
||||
DOCKER_VERSION=$(docker --version)
|
||||
log_info "✓ $DOCKER_VERSION"
|
||||
else
|
||||
log_error "Docker installation failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check Docker Compose version
|
||||
if docker compose version &> /dev/null; then
|
||||
COMPOSE_VERSION=$(docker compose version)
|
||||
log_info "✓ $COMPOSE_VERSION"
|
||||
else
|
||||
log_error "Docker Compose installation failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Run test container
|
||||
log_info "Running test container..."
|
||||
if docker run --rm hello-world &> /dev/null; then
|
||||
log_info "✓ Docker is working correctly"
|
||||
else
|
||||
log_error "Docker test failed"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Main function
|
||||
main() {
|
||||
echo "========================================"
|
||||
echo " Docker & Docker Compose Installer"
|
||||
echo "========================================"
|
||||
echo ""
|
||||
|
||||
check_root
|
||||
detect_os
|
||||
|
||||
if check_docker_installed; then
|
||||
verify_installation
|
||||
exit 0
|
||||
fi
|
||||
|
||||
case $OS in
|
||||
ubuntu|debian)
|
||||
install_docker_debian
|
||||
;;
|
||||
centos|rhel|rocky|almalinux)
|
||||
install_docker_centos
|
||||
;;
|
||||
*)
|
||||
log_error "Unsupported operating system: $OS"
|
||||
log_info "Supported systems: Ubuntu, Debian, CentOS, RHEL, Rocky Linux, AlmaLinux"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
start_docker
|
||||
configure_docker_group
|
||||
verify_installation
|
||||
|
||||
echo ""
|
||||
log_info "========================================"
|
||||
log_info "Docker and Docker Compose installed successfully!"
|
||||
log_info "========================================"
|
||||
log_info "Docker version: $(docker --version)"
|
||||
log_info "Docker Compose version: $(docker compose version)"
|
||||
echo ""
|
||||
log_info "Next step: Install PPanel"
|
||||
log_info "Run: curl -fsSL https://ppanel.dev/scripts/en/install-ppanel.sh | bash"
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Executable
+415
@@ -0,0 +1,415 @@
|
||||
#!/bin/bash
|
||||
|
||||
#######################################################
|
||||
# PPanel One-Click Installation Script
|
||||
# Support: Docker Compose Deployment
|
||||
# Usage: curl -fsSL https://ppanel.dev/scripts/en/install-ppanel.sh | bash
|
||||
#######################################################
|
||||
|
||||
set -e
|
||||
|
||||
# 颜色输出
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# 配置变量
|
||||
INSTALL_DIR="${INSTALL_DIR:-$(pwd)/ppanel}"
|
||||
DOCKER_IMAGE="ppanel/ppanel:latest"
|
||||
CONTAINER_NAME="ppanel-service"
|
||||
HOST_PORT="${HOST_PORT:-8080}"
|
||||
|
||||
# 日志函数
|
||||
log_info() {
|
||||
echo -e "${GREEN}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
log_warn() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
log_step() {
|
||||
echo -e "${BLUE}[STEP]${NC} $1"
|
||||
}
|
||||
|
||||
# Check if Docker is installed
|
||||
check_docker() {
|
||||
if ! command -v docker &> /dev/null; then
|
||||
log_error "Docker is not installed"
|
||||
log_info "Please install Docker first:"
|
||||
log_info "curl -fsSL https://ppanel.dev/scripts/en/install-docker.sh | sudo bash"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! docker compose version &> /dev/null; then
|
||||
log_error "Docker Compose is not installed"
|
||||
log_info "Please install Docker Compose first"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_info "✓ Docker installed ($(docker --version))"
|
||||
log_info "✓ Docker Compose installed ($(docker compose version --short))"
|
||||
}
|
||||
|
||||
# Check if port is in use
|
||||
check_port() {
|
||||
if command -v netstat &> /dev/null; then
|
||||
if netstat -tuln | grep -q ":$HOST_PORT "; then
|
||||
log_error "Port $HOST_PORT is already in use"
|
||||
log_info "Please set another port: export HOST_PORT=8081"
|
||||
exit 1
|
||||
fi
|
||||
elif command -v ss &> /dev/null; then
|
||||
if ss -tuln | grep -q ":$HOST_PORT "; then
|
||||
log_error "Port $HOST_PORT is already in use"
|
||||
log_info "Please set another port: export HOST_PORT=8081"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
log_info "✓ Port $HOST_PORT is available"
|
||||
}
|
||||
|
||||
# Create installation directories
|
||||
create_directories() {
|
||||
log_step "Creating installation directories..."
|
||||
|
||||
mkdir -p "$INSTALL_DIR"/config
|
||||
# Set permissions to ensure container can read configuration files
|
||||
chmod -R 755 "$INSTALL_DIR"
|
||||
|
||||
log_info "✓ Directories created: $INSTALL_DIR"
|
||||
}
|
||||
|
||||
# 生成随机密钥
|
||||
generate_secret() {
|
||||
if command -v openssl &> /dev/null; then
|
||||
openssl rand -hex 32
|
||||
else
|
||||
cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 64 | head -n 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Get user input
|
||||
get_user_input() {
|
||||
log_step "Configuring PPanel..."
|
||||
echo ""
|
||||
|
||||
# MySQL configuration
|
||||
MYSQL_USER="ppanel"
|
||||
MYSQL_PASSWORD=$(generate_secret | cut -c1-16)
|
||||
MYSQL_DB="ppanel"
|
||||
MYSQL_ROOT_PASSWORD=$(generate_secret | cut -c1-16)
|
||||
|
||||
log_info "✓ MySQL password generated"
|
||||
|
||||
# Redis configuration
|
||||
REDIS_PASS=$(generate_secret | cut -c1-16)
|
||||
|
||||
log_info "✓ Redis password generated"
|
||||
|
||||
# Generate JWT secret
|
||||
JWT_SECRET=$(generate_secret)
|
||||
log_info "✓ JWT secret generated"
|
||||
}
|
||||
|
||||
# Create configuration file
|
||||
create_config() {
|
||||
log_step "Creating configuration file..."
|
||||
|
||||
cat > "$INSTALL_DIR/config/ppanel.yaml" <<EOF
|
||||
Host: 0.0.0.0
|
||||
Port: 8080
|
||||
TLS:
|
||||
Enable: false
|
||||
CertFile: ""
|
||||
KeyFile: ""
|
||||
Debug: false
|
||||
|
||||
Static:
|
||||
Admin:
|
||||
Enabled: true
|
||||
Prefix: /admin
|
||||
Path: ./static/admin
|
||||
User:
|
||||
Enabled: true
|
||||
Prefix: /
|
||||
Path: ./static/user
|
||||
|
||||
JwtAuth:
|
||||
AccessSecret: $JWT_SECRET
|
||||
AccessExpire: 604800
|
||||
|
||||
Logger:
|
||||
ServiceName: ApiService
|
||||
Mode: console
|
||||
Encoding: plain
|
||||
TimeFormat: "2006-01-02 15:04:05.000"
|
||||
Path: logs
|
||||
Level: info
|
||||
MaxContentLength: 0
|
||||
Compress: false
|
||||
Stat: true
|
||||
KeepDays: 0
|
||||
StackCooldownMillis: 100
|
||||
MaxBackups: 0
|
||||
MaxSize: 0
|
||||
Rotation: daily
|
||||
FileTimeFormat: 2006-01-02T15:04:05.000Z07:00
|
||||
|
||||
MySQL:
|
||||
Addr: mysql:3306
|
||||
Username: $MYSQL_USER
|
||||
Password: $MYSQL_PASSWORD
|
||||
Dbname: $MYSQL_DB
|
||||
Config: charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai
|
||||
MaxIdleConns: 10
|
||||
MaxOpenConns: 10
|
||||
SlowThreshold: 1000
|
||||
|
||||
Redis:
|
||||
Host: redis:6379
|
||||
Pass: $REDIS_PASS
|
||||
DB: 0
|
||||
EOF
|
||||
|
||||
log_info "✓ Configuration file created: $INSTALL_DIR/config/ppanel.yaml"
|
||||
# Create docker-compose.yml
|
||||
create_docker_compose() {
|
||||
log_step "Creating Docker Compose configuration..."
|
||||
|
||||
cat > "$INSTALL_DIR/docker-compose.yml" <<'COMPOSE_EOF'
|
||||
services:
|
||||
mysql:
|
||||
image: mysql:8.0
|
||||
container_name: ppanel-mysql
|
||||
restart: always
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
|
||||
MYSQL_DATABASE: ${MYSQL_DB}
|
||||
MYSQL_USER: ${MYSQL_USER}
|
||||
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
|
||||
TZ: Asia/Shanghai
|
||||
volumes:
|
||||
- mysql:/var/lib/mysql
|
||||
command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
|
||||
healthcheck:
|
||||
test: [
|
||||
"CMD-SHELL",
|
||||
"mysqladmin ping -h localhost -u $$MYSQL_USER -p$$MYSQL_PASSWORD || exit 1"
|
||||
]
|
||||
interval: 5s
|
||||
timeout: 3s
|
||||
retries: 10
|
||||
start_period: 30s
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
container_name: ppanel-redis
|
||||
restart: always
|
||||
command: redis-server --requirepass ${REDIS_PASS} --appendonly yes
|
||||
volumes:
|
||||
- redis:/data
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "--raw", "incr", "ping"]
|
||||
interval: 10s
|
||||
timeout: 3s
|
||||
retries: 5
|
||||
|
||||
ppanel-service:
|
||||
image: ${DOCKER_IMAGE}
|
||||
container_name: ${CONTAINER_NAME}
|
||||
restart: always
|
||||
ports:
|
||||
- "${HOST_PORT}:8080"
|
||||
volumes:
|
||||
- ./config:/app/etc:ro
|
||||
depends_on:
|
||||
mysql:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
|
||||
volumes:
|
||||
mysql:
|
||||
redis:
|
||||
COMPOSE_EOF
|
||||
|
||||
log_info "✓ Docker Compose configuration created"
|
||||
|
||||
# Create .env file
|
||||
cat > "$INSTALL_DIR/.env" <<ENV_EOF
|
||||
MYSQL_ROOT_PASSWORD=$MYSQL_ROOT_PASSWORD
|
||||
MYSQL_DB=$MYSQL_DB
|
||||
MYSQL_USER=$MYSQL_USER
|
||||
MYSQL_PASSWORD=$MYSQL_PASSWORD
|
||||
REDIS_PASS=$REDIS_PASS
|
||||
DOCKER_IMAGE=$DOCKER_IMAGE
|
||||
CONTAINER_NAME=$CONTAINER_NAME
|
||||
HOST_PORT=$HOST_PORT
|
||||
ENV_EOF
|
||||
|
||||
log_info "✓ Environment variables file created"
|
||||
}
|
||||
|
||||
# Pull Docker image
|
||||
pull_image() {
|
||||
log_step "Pulling Docker image..."
|
||||
|
||||
cd "$INSTALL_DIR"
|
||||
docker compose pull
|
||||
|
||||
log_info "✓ Image pulled successfully"
|
||||
}
|
||||
|
||||
# Start service
|
||||
start_service() {
|
||||
log_step "Starting PPanel service..."
|
||||
|
||||
cd "$INSTALL_DIR"
|
||||
docker compose up -d
|
||||
|
||||
log_info "✓ Service started"
|
||||
}
|
||||
|
||||
# Wait for service to be ready
|
||||
wait_for_service() {
|
||||
log_step "Waiting for service to be ready..."
|
||||
|
||||
local max_attempts=30
|
||||
local attempt=0
|
||||
|
||||
while [[ $attempt -lt $max_attempts ]]; do
|
||||
if command -v curl &> /dev/null; then
|
||||
if curl -s "http://localhost:$HOST_PORT" &> /dev/null; then
|
||||
log_info "✓ Service is ready"
|
||||
return 0
|
||||
fi
|
||||
elif command -v wget &> /dev/null; then
|
||||
if wget --quiet --tries=1 --spider "http://localhost:$HOST_PORT" &> /dev/null; then
|
||||
log_info "✓ Service is ready"
|
||||
return 0
|
||||
fi
|
||||
else
|
||||
# If neither curl nor wget is available, check container health directly
|
||||
if docker inspect ppanel-service --format='{{.State.Health.Status}}' 2>/dev/null | grep -q "healthy"; then
|
||||
log_info "✓ Service is ready"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
attempt=$((attempt + 1))
|
||||
echo -n "."
|
||||
sleep 2
|
||||
done
|
||||
|
||||
echo ""
|
||||
log_warn "Service startup timeout, please check logs"
|
||||
log_info "View logs: cd $INSTALL_DIR && docker compose logs -f"
|
||||
}
|
||||
|
||||
# Show access information
|
||||
show_access_info() {
|
||||
local internal_ip
|
||||
local public_ip
|
||||
|
||||
# Get internal IP
|
||||
internal_ip=$(hostname -I | awk '{print $1}')
|
||||
|
||||
# Get public IP
|
||||
public_ip=$(curl -s --max-time 5 https://api.ipify.org 2>/dev/null || curl -s --max-time 5 https://ifconfig.me 2>/dev/null || echo "Unable to get")
|
||||
|
||||
echo ""
|
||||
echo "========================================"
|
||||
log_info "PPanel installation completed!"
|
||||
echo "========================================"
|
||||
echo ""
|
||||
log_info "Access URLs:"
|
||||
echo " Internal Access (LAN):"
|
||||
echo " User Panel: http://$internal_ip:$HOST_PORT"
|
||||
echo " Admin Panel: http://$internal_ip:$HOST_PORT/admin/"
|
||||
echo ""
|
||||
if [[ "$public_ip" != "Unable to get" ]]; then
|
||||
echo " Public Access (Internet):"
|
||||
echo " User Panel: http://$public_ip:$HOST_PORT"
|
||||
echo " Admin Panel: http://$public_ip:$HOST_PORT/admin/"
|
||||
echo ""
|
||||
log_warn "Note: Public access requires firewall and router port forwarding configuration"
|
||||
else
|
||||
log_warn "Unable to get public IP, please configure manually for public access"
|
||||
fi
|
||||
echo ""
|
||||
log_info "Database Information:"
|
||||
echo " MySQL (Container Network):"
|
||||
echo " Address: mysql:3306"
|
||||
echo " User: $MYSQL_USER"
|
||||
echo " Password: $MYSQL_PASSWORD"
|
||||
echo " Database: $MYSQL_DB"
|
||||
echo " Root Password: $MYSQL_ROOT_PASSWORD"
|
||||
echo ""
|
||||
echo " Redis (Container Network):"
|
||||
echo " Address: redis:6379"
|
||||
echo " Password: $REDIS_PASS"
|
||||
echo ""
|
||||
log_warn "Note: MySQL and Redis are only accessible within the container network"
|
||||
echo " To access from host, edit docker-compose.yml to add port mappings"
|
||||
echo ""
|
||||
log_info "Installation directory: $INSTALL_DIR"
|
||||
echo ""
|
||||
log_info "Common commands:"
|
||||
echo " Check status: cd $INSTALL_DIR && docker compose ps"
|
||||
echo " View logs: cd $INSTALL_DIR && docker compose logs -f"
|
||||
echo " Restart: cd $INSTALL_DIR && docker compose restart"
|
||||
echo " Stop: cd $INSTALL_DIR && docker compose stop"
|
||||
echo " Start: cd $INSTALL_DIR && docker compose start"
|
||||
echo ""
|
||||
log_warn "Important reminders:"
|
||||
echo " 1. Please keep database password information safe"
|
||||
echo " 2. Please login to admin panel and change the default password"
|
||||
echo " 3. Configure firewall rules to restrict access"
|
||||
echo " 4. Configure reverse proxy and HTTPS for production"
|
||||
echo " 5. Backup database regularly: docker exec ppanel-mysql mysqldump -u root -p$MYSQL_ROOT_PASSWORD $MYSQL_DB > backup.sql"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Show firewall configuration info
|
||||
show_firewall_info() {
|
||||
if command -v ufw &> /dev/null; then
|
||||
log_info "Ubuntu/Debian firewall configuration:"
|
||||
echo " sudo ufw allow $HOST_PORT/tcp"
|
||||
echo " sudo ufw status"
|
||||
echo ""
|
||||
elif command -v firewall-cmd &> /dev/null; then
|
||||
log_info "CentOS/RHEL firewall configuration:"
|
||||
echo " sudo firewall-cmd --permanent --add-port=$HOST_PORT/tcp"
|
||||
echo " sudo firewall-cmd --reload"
|
||||
echo ""
|
||||
fi
|
||||
}
|
||||
|
||||
# Main function
|
||||
main() {
|
||||
echo "========================================"
|
||||
echo " PPanel One-Click Installer"
|
||||
echo "========================================"
|
||||
echo ""
|
||||
|
||||
check_docker
|
||||
check_port
|
||||
create_directories
|
||||
get_user_input
|
||||
create_config
|
||||
create_docker_compose
|
||||
pull_image
|
||||
start_service
|
||||
wait_for_service
|
||||
show_access_info
|
||||
show_firewall_info
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Executable
+216
@@ -0,0 +1,216 @@
|
||||
#!/bin/bash
|
||||
|
||||
#######################################################
|
||||
# Docker & Docker Compose 安装脚本
|
||||
# 支持: Ubuntu/Debian, CentOS/RHEL
|
||||
# 用法: curl -fsSL https://ppanel.dev/scripts/zh/install-docker.sh | bash
|
||||
#######################################################
|
||||
|
||||
set -e
|
||||
|
||||
# 颜色输出
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# 日志函数
|
||||
log_info() {
|
||||
echo -e "${GREEN}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
log_warn() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
# 检查是否为 root 用户
|
||||
check_root() {
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
log_error "此脚本必须以 root 权限运行"
|
||||
log_info "请使用: sudo bash $0"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 检测系统类型
|
||||
detect_os() {
|
||||
if [[ -f /etc/os-release ]]; then
|
||||
. /etc/os-release
|
||||
OS=$ID
|
||||
VER=$VERSION_ID
|
||||
else
|
||||
log_error "无法检测操作系统类型"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_info "检测到系统: $OS $VER"
|
||||
}
|
||||
|
||||
# 检查 Docker 是否已安装
|
||||
check_docker_installed() {
|
||||
if command -v docker &> /dev/null; then
|
||||
DOCKER_VERSION=$(docker --version | cut -d ' ' -f3 | cut -d ',' -f1)
|
||||
log_warn "Docker 已安装 (版本: $DOCKER_VERSION)"
|
||||
read -p "是否重新安装? (y/N): " -n 1 -r
|
||||
echo
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
log_info "跳过 Docker 安装"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# 安装 Docker - Ubuntu/Debian
|
||||
install_docker_debian() {
|
||||
log_info "开始在 Ubuntu/Debian 上安装 Docker..."
|
||||
|
||||
# 更新包索引
|
||||
apt-get update
|
||||
|
||||
# 安装依赖
|
||||
apt-get install -y \
|
||||
ca-certificates \
|
||||
curl \
|
||||
gnupg \
|
||||
lsb-release
|
||||
|
||||
# 添加 Docker 官方 GPG 密钥
|
||||
install -m 0755 -d /etc/apt/keyrings
|
||||
curl -fsSL https://download.docker.com/linux/$OS/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
|
||||
chmod a+r /etc/apt/keyrings/docker.gpg
|
||||
|
||||
# 设置仓库
|
||||
echo \
|
||||
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/$OS \
|
||||
$(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
|
||||
|
||||
# 安装 Docker Engine
|
||||
apt-get update
|
||||
apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
||||
|
||||
log_info "Docker 安装完成"
|
||||
}
|
||||
|
||||
# 安装 Docker - CentOS/RHEL
|
||||
install_docker_centos() {
|
||||
log_info "开始在 CentOS/RHEL 上安装 Docker..."
|
||||
|
||||
# 安装 yum-utils
|
||||
yum install -y yum-utils
|
||||
|
||||
# 添加 Docker 仓库
|
||||
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
|
||||
|
||||
# 安装 Docker Engine
|
||||
yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
||||
|
||||
log_info "Docker 安装完成"
|
||||
}
|
||||
|
||||
# 启动 Docker 服务
|
||||
start_docker() {
|
||||
log_info "启动 Docker 服务..."
|
||||
|
||||
systemctl start docker
|
||||
systemctl enable docker
|
||||
|
||||
log_info "Docker 服务已启动并设置为开机自启"
|
||||
}
|
||||
|
||||
# 配置 Docker 用户组(可选)
|
||||
configure_docker_group() {
|
||||
log_info "配置 Docker 用户组..."
|
||||
|
||||
if ! getent group docker > /dev/null; then
|
||||
groupadd docker
|
||||
fi
|
||||
|
||||
if [[ -n "$SUDO_USER" ]]; then
|
||||
usermod -aG docker "$SUDO_USER"
|
||||
log_info "用户 $SUDO_USER 已添加到 docker 组"
|
||||
log_warn "请注销并重新登录以使组权限生效"
|
||||
fi
|
||||
}
|
||||
|
||||
# 验证安装
|
||||
verify_installation() {
|
||||
log_info "验证 Docker 安装..."
|
||||
|
||||
# 检查 Docker 版本
|
||||
if docker --version &> /dev/null; then
|
||||
DOCKER_VERSION=$(docker --version)
|
||||
log_info "✓ $DOCKER_VERSION"
|
||||
else
|
||||
log_error "Docker 安装失败"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 检查 Docker Compose 版本
|
||||
if docker compose version &> /dev/null; then
|
||||
COMPOSE_VERSION=$(docker compose version)
|
||||
log_info "✓ $COMPOSE_VERSION"
|
||||
else
|
||||
log_error "Docker Compose 安装失败"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 运行测试容器
|
||||
log_info "运行测试容器..."
|
||||
if docker run --rm hello-world &> /dev/null; then
|
||||
log_info "✓ Docker 运行正常"
|
||||
else
|
||||
log_error "Docker 运行测试失败"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 主函数
|
||||
main() {
|
||||
echo "========================================"
|
||||
echo " Docker & Docker Compose 安装脚本"
|
||||
echo "========================================"
|
||||
echo ""
|
||||
|
||||
check_root
|
||||
detect_os
|
||||
|
||||
if check_docker_installed; then
|
||||
verify_installation
|
||||
exit 0
|
||||
fi
|
||||
|
||||
case $OS in
|
||||
ubuntu|debian)
|
||||
install_docker_debian
|
||||
;;
|
||||
centos|rhel|rocky|almalinux)
|
||||
install_docker_centos
|
||||
;;
|
||||
*)
|
||||
log_error "不支持的操作系统: $OS"
|
||||
log_info "支持的系统: Ubuntu, Debian, CentOS, RHEL, Rocky Linux, AlmaLinux"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
start_docker
|
||||
configure_docker_group
|
||||
verify_installation
|
||||
|
||||
echo ""
|
||||
log_info "========================================"
|
||||
log_info "Docker 和 Docker Compose 安装完成!"
|
||||
log_info "========================================"
|
||||
log_info "Docker 版本: $(docker --version)"
|
||||
log_info "Docker Compose 版本: $(docker compose version)"
|
||||
echo ""
|
||||
log_info "下一步: 安装 PPanel"
|
||||
log_info "运行: curl -fsSL https://ppanel.dev/scripts/install-ppanel.sh | bash"
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Executable
+417
@@ -0,0 +1,417 @@
|
||||
#!/bin/bash
|
||||
|
||||
#######################################################
|
||||
# PPanel 一键安装脚本
|
||||
# 支持: Docker Compose 部署
|
||||
# 用法: curl -fsSL https://ppanel.dev/scripts/zh/install-ppanel.sh | bash
|
||||
#######################################################
|
||||
|
||||
set -e
|
||||
|
||||
# 颜色输出
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# 配置变量
|
||||
INSTALL_DIR="${INSTALL_DIR:-$(pwd)/ppanel}"
|
||||
DOCKER_IMAGE="ppanel/ppanel:latest"
|
||||
CONTAINER_NAME="ppanel-service"
|
||||
HOST_PORT="${HOST_PORT:-8080}"
|
||||
|
||||
# 日志函数
|
||||
log_info() {
|
||||
echo -e "${GREEN}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
log_warn() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
log_step() {
|
||||
echo -e "${BLUE}[STEP]${NC} $1"
|
||||
}
|
||||
|
||||
# 检查 Docker 是否已安装
|
||||
check_docker() {
|
||||
if ! command -v docker &> /dev/null; then
|
||||
log_error "Docker 未安装"
|
||||
log_info "请先安装 Docker:"
|
||||
log_info "curl -fsSL https://ppanel.dev/scripts/install-docker.sh | sudo bash"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! docker compose version &> /dev/null; then
|
||||
log_error "Docker Compose 未安装"
|
||||
log_info "请先安装 Docker Compose"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_info "✓ Docker 已安装 ($(docker --version))"
|
||||
log_info "✓ Docker Compose 已安装 ($(docker compose version --short))"
|
||||
}
|
||||
|
||||
# 检查端口是否被占用
|
||||
check_port() {
|
||||
if command -v netstat &> /dev/null; then
|
||||
if netstat -tuln | grep -q ":$HOST_PORT "; then
|
||||
log_error "端口 $HOST_PORT 已被占用"
|
||||
log_info "请设置其他端口: export HOST_PORT=8081"
|
||||
exit 1
|
||||
fi
|
||||
elif command -v ss &> /dev/null; then
|
||||
if ss -tuln | grep -q ":$HOST_PORT "; then
|
||||
log_error "端口 $HOST_PORT 已被占用"
|
||||
log_info "请设置其他端口: export HOST_PORT=8081"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
log_info "✓ 端口 $HOST_PORT 可用"
|
||||
}
|
||||
|
||||
# 创建安装目录
|
||||
create_directories() {
|
||||
log_step "创建安装目录..."
|
||||
|
||||
mkdir -p "$INSTALL_DIR"/config
|
||||
# 设置权限确保容器可以读取配置文件
|
||||
chmod -R 755 "$INSTALL_DIR"
|
||||
|
||||
log_info "✓ 目录已创建: $INSTALL_DIR"
|
||||
}
|
||||
|
||||
# 生成随机密钥
|
||||
generate_secret() {
|
||||
if command -v openssl &> /dev/null; then
|
||||
openssl rand -hex 32
|
||||
else
|
||||
cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 64 | head -n 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 获取用户输入
|
||||
get_user_input() {
|
||||
log_step "配置 PPanel..."
|
||||
echo ""
|
||||
|
||||
# MySQL 配置
|
||||
MYSQL_USER="ppanel"
|
||||
MYSQL_PASSWORD=$(generate_secret | cut -c1-16)
|
||||
MYSQL_DB="ppanel"
|
||||
MYSQL_ROOT_PASSWORD=$(generate_secret | cut -c1-16)
|
||||
|
||||
log_info "✓ 已生成 MySQL 密码"
|
||||
|
||||
# Redis 配置
|
||||
REDIS_PASS=$(generate_secret | cut -c1-16)
|
||||
|
||||
log_info "✓ 已生成 Redis 密码"
|
||||
|
||||
# 生成 JWT 密钥
|
||||
JWT_SECRET=$(generate_secret)
|
||||
log_info "✓ 已生成 JWT 密钥"
|
||||
}
|
||||
|
||||
# 创建配置文件
|
||||
create_config() {
|
||||
log_step "创建配置文件..."
|
||||
|
||||
cat > "$INSTALL_DIR/config/ppanel.yaml" <<EOF
|
||||
Host: 0.0.0.0
|
||||
Port: 8080
|
||||
TLS:
|
||||
Enable: false
|
||||
CertFile: ""
|
||||
KeyFile: ""
|
||||
Debug: false
|
||||
|
||||
Static:
|
||||
Admin:
|
||||
Enabled: true
|
||||
Prefix: /admin
|
||||
Path: ./static/admin
|
||||
User:
|
||||
Enabled: true
|
||||
Prefix: /
|
||||
Path: ./static/user
|
||||
|
||||
JwtAuth:
|
||||
AccessSecret: $JWT_SECRET
|
||||
AccessExpire: 604800
|
||||
|
||||
Logger:
|
||||
ServiceName: ApiService
|
||||
Mode: console
|
||||
Encoding: plain
|
||||
TimeFormat: "2006-01-02 15:04:05.000"
|
||||
Path: logs
|
||||
Level: info
|
||||
MaxContentLength: 0
|
||||
Compress: false
|
||||
Stat: true
|
||||
KeepDays: 0
|
||||
StackCooldownMillis: 100
|
||||
MaxBackups: 0
|
||||
MaxSize: 0
|
||||
Rotation: daily
|
||||
FileTimeFormat: 2006-01-02T15:04:05.000Z07:00
|
||||
|
||||
MySQL:
|
||||
Addr: mysql:3306
|
||||
Username: $MYSQL_USER
|
||||
Password: $MYSQL_PASSWORD
|
||||
Dbname: $MYSQL_DB
|
||||
Config: charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai
|
||||
MaxIdleConns: 10
|
||||
MaxOpenConns: 10
|
||||
SlowThreshold: 1000
|
||||
|
||||
Redis:
|
||||
Host: redis:6379
|
||||
Pass: $REDIS_PASS
|
||||
DB: 0
|
||||
EOF
|
||||
|
||||
log_info "✓ 配置文件已创建: $INSTALL_DIR/config/ppanel.yaml"
|
||||
}
|
||||
|
||||
# 创建 docker-compose.yml
|
||||
create_docker_compose() {
|
||||
log_step "创建 Docker Compose 配置..."
|
||||
|
||||
cat > "$INSTALL_DIR/docker-compose.yml" <<'COMPOSE_EOF'
|
||||
services:
|
||||
mysql:
|
||||
image: mysql:8.0
|
||||
container_name: ppanel-mysql
|
||||
restart: always
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
|
||||
MYSQL_DATABASE: ${MYSQL_DB}
|
||||
MYSQL_USER: ${MYSQL_USER}
|
||||
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
|
||||
TZ: Asia/Shanghai
|
||||
volumes:
|
||||
- mysql:/var/lib/mysql
|
||||
command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
|
||||
healthcheck:
|
||||
test: [
|
||||
"CMD-SHELL",
|
||||
"mysqladmin ping -h localhost -u $$MYSQL_USER -p$$MYSQL_PASSWORD || exit 1"
|
||||
]
|
||||
interval: 5s
|
||||
timeout: 3s
|
||||
retries: 10
|
||||
start_period: 30s
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
container_name: ppanel-redis
|
||||
restart: always
|
||||
command: redis-server --requirepass ${REDIS_PASS} --appendonly yes
|
||||
volumes:
|
||||
- redis:/data
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "--raw", "incr", "ping"]
|
||||
interval: 10s
|
||||
timeout: 3s
|
||||
retries: 5
|
||||
|
||||
ppanel-service:
|
||||
image: ${DOCKER_IMAGE}
|
||||
container_name: ${CONTAINER_NAME}
|
||||
restart: always
|
||||
ports:
|
||||
- "${HOST_PORT}:8080"
|
||||
volumes:
|
||||
- ./config:/app/etc:ro
|
||||
depends_on:
|
||||
mysql:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
|
||||
volumes:
|
||||
mysql:
|
||||
redis:
|
||||
COMPOSE_EOF
|
||||
|
||||
log_info "✓ Docker Compose 配置已创建"
|
||||
|
||||
# 创建 .env 文件
|
||||
cat > "$INSTALL_DIR/.env" <<ENV_EOF
|
||||
MYSQL_ROOT_PASSWORD=$MYSQL_ROOT_PASSWORD
|
||||
MYSQL_DB=$MYSQL_DB
|
||||
MYSQL_USER=$MYSQL_USER
|
||||
MYSQL_PASSWORD=$MYSQL_PASSWORD
|
||||
REDIS_PASS=$REDIS_PASS
|
||||
DOCKER_IMAGE=$DOCKER_IMAGE
|
||||
CONTAINER_NAME=$CONTAINER_NAME
|
||||
HOST_PORT=$HOST_PORT
|
||||
ENV_EOF
|
||||
|
||||
log_info "✓ 环境变量文件已创建"
|
||||
}
|
||||
|
||||
# 拉取 Docker 镜像
|
||||
pull_image() {
|
||||
log_step "拉取 Docker 镜像..."
|
||||
|
||||
cd "$INSTALL_DIR"
|
||||
docker compose pull
|
||||
|
||||
log_info "✓ 镜像拉取完成"
|
||||
}
|
||||
|
||||
# 启动服务
|
||||
start_service() {
|
||||
log_step "启动 PPanel 服务..."
|
||||
|
||||
cd "$INSTALL_DIR"
|
||||
docker compose up -d
|
||||
|
||||
log_info "✓ 服务已启动"
|
||||
}
|
||||
|
||||
# 等待服务就绪
|
||||
wait_for_service() {
|
||||
log_step "等待服务就绪..."
|
||||
|
||||
local max_attempts=30
|
||||
local attempt=0
|
||||
|
||||
while [[ $attempt -lt $max_attempts ]]; do
|
||||
if command -v curl &> /dev/null; then
|
||||
if curl -s "http://localhost:$HOST_PORT" &> /dev/null; then
|
||||
log_info "✓ 服务已就绪"
|
||||
return 0
|
||||
fi
|
||||
elif command -v wget &> /dev/null; then
|
||||
if wget --quiet --tries=1 --spider "http://localhost:$HOST_PORT" &> /dev/null; then
|
||||
log_info "✓ 服务已就绪"
|
||||
return 0
|
||||
fi
|
||||
else
|
||||
# 如果 curl 和 wget 都不可用,直接检查容器状态
|
||||
if docker inspect ppanel-service --format='{{.State.Health.Status}}' 2>/dev/null | grep -q "healthy"; then
|
||||
log_info "✓ 服务已就绪"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
attempt=$((attempt + 1))
|
||||
echo -n "."
|
||||
sleep 2
|
||||
done
|
||||
|
||||
echo ""
|
||||
log_warn "服务启动超时,请检查日志"
|
||||
log_info "查看日志: cd $INSTALL_DIR && docker compose logs -f"
|
||||
}
|
||||
|
||||
# 显示访问信息
|
||||
show_access_info() {
|
||||
local internal_ip
|
||||
local public_ip
|
||||
|
||||
# 获取内网IP
|
||||
internal_ip=$(hostname -I | awk '{print $1}')
|
||||
|
||||
# 获取外网IP
|
||||
public_ip=$(curl -s --max-time 5 https://api.ipify.org 2>/dev/null || curl -s --max-time 5 https://ifconfig.me 2>/dev/null || echo "无法获取")
|
||||
|
||||
echo ""
|
||||
echo "========================================"
|
||||
log_info "PPanel 安装完成!"
|
||||
echo "========================================"
|
||||
echo ""
|
||||
log_info "访问地址:"
|
||||
echo " 内网访问 (局域网):"
|
||||
echo " 用户面板: http://$internal_ip:$HOST_PORT"
|
||||
echo " 管理后台: http://$internal_ip:$HOST_PORT/admin/"
|
||||
echo ""
|
||||
if [[ "$public_ip" != "无法获取" ]]; then
|
||||
echo " 外网访问 (公网):"
|
||||
echo " 用户面板: http://$public_ip:$HOST_PORT"
|
||||
echo " 管理后台: http://$public_ip:$HOST_PORT/admin/"
|
||||
echo ""
|
||||
log_warn "注意: 外网访问需要配置防火墙和路由器端口转发"
|
||||
else
|
||||
log_warn "未能获取公网IP,如需外网访问请手动配置"
|
||||
fi
|
||||
echo ""
|
||||
log_info "数据库信息:"
|
||||
echo " MySQL (容器间通信):"
|
||||
echo " 地址: mysql:3306"
|
||||
echo " 用户: $MYSQL_USER"
|
||||
echo " 密码: $MYSQL_PASSWORD"
|
||||
echo " 数据库: $MYSQL_DB"
|
||||
echo " Root 密码: $MYSQL_ROOT_PASSWORD"
|
||||
echo ""
|
||||
echo " Redis (容器间通信):"
|
||||
echo " 地址: redis:6379"
|
||||
echo " 密码: $REDIS_PASS"
|
||||
echo ""
|
||||
log_warn "注意: MySQL 和 Redis 仅在容器网络内可访问,未暴露到宿主机"
|
||||
echo " 如需从宿主机访问,请编辑 docker-compose.yml 添加端口映射"
|
||||
echo ""
|
||||
log_info "安装目录: $INSTALL_DIR"
|
||||
echo ""
|
||||
log_info "常用命令:"
|
||||
echo " 查看状态: cd $INSTALL_DIR && docker compose ps"
|
||||
echo " 查看日志: cd $INSTALL_DIR && docker compose logs -f"
|
||||
echo " 重启服务: cd $INSTALL_DIR && docker compose restart"
|
||||
echo " 停止服务: cd $INSTALL_DIR && docker compose stop"
|
||||
echo " 启动服务: cd $INSTALL_DIR && docker compose start"
|
||||
echo ""
|
||||
log_warn "重要提示:"
|
||||
echo " 1. 请妥善保管数据库密码信息"
|
||||
echo " 2. 请及时登录管理后台修改默认密码"
|
||||
echo " 3. 建议配置防火墙规则限制访问"
|
||||
echo " 4. 生产环境请配置反向代理和 HTTPS"
|
||||
echo " 5. 定期备份数据库: docker exec ppanel-mysql mysqldump -u root -p$MYSQL_ROOT_PASSWORD $MYSQL_DB > backup.sql"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# 配置防火墙提示
|
||||
show_firewall_info() {
|
||||
if command -v ufw &> /dev/null; then
|
||||
log_info "Ubuntu/Debian 防火墙配置:"
|
||||
echo " sudo ufw allow $HOST_PORT/tcp"
|
||||
echo " sudo ufw status"
|
||||
echo ""
|
||||
elif command -v firewall-cmd &> /dev/null; then
|
||||
log_info "CentOS/RHEL 防火墙配置:"
|
||||
echo " sudo firewall-cmd --permanent --add-port=$HOST_PORT/tcp"
|
||||
echo " sudo firewall-cmd --reload"
|
||||
echo ""
|
||||
fi
|
||||
}
|
||||
|
||||
# 主函数
|
||||
main() {
|
||||
echo "========================================"
|
||||
echo " PPanel 一键安装脚本"
|
||||
echo "========================================"
|
||||
echo ""
|
||||
|
||||
check_docker
|
||||
check_port
|
||||
create_directories
|
||||
get_user_input
|
||||
create_config
|
||||
create_docker_compose
|
||||
pull_image
|
||||
start_service
|
||||
wait_for_service
|
||||
show_access_info
|
||||
show_firewall_info
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user