- proxmox-lxc-argocd.sh: ArgoCD 설치 스크립트 - proxmox-lxc-traefik.sh: Traefik 설치 스크립트 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
407 lines
12 KiB
Bash
Executable File
407 lines
12 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
# Traefik LXC Installation Script
|
|
# Description: Traefik reverse proxy with Docker
|
|
# OS: Debian 12 (Bookworm)
|
|
# Ports: HTTP: 80, HTTPS: 443, Dashboard: 8080
|
|
# Last Updated: 2026-01-01
|
|
|
|
set -euo pipefail
|
|
|
|
#################################################################
|
|
# Configuration Variables
|
|
#################################################################
|
|
|
|
# Container Configuration
|
|
CT_ID=${CT_ID:-10004}
|
|
CT_HOSTNAME=${CT_HOSTNAME:-"eunha-traefik"}
|
|
CT_CORES=${CT_CORES:-2}
|
|
CT_MEMORY=${CT_MEMORY:-1024}
|
|
CT_SWAP=${CT_SWAP:-512}
|
|
CT_DISK_SIZE=${CT_DISK_SIZE:-8}
|
|
|
|
# Network Configuration
|
|
CT_IP=${CT_IP:-"dhcp"}
|
|
CT_GATEWAY=${CT_GATEWAY:-""}
|
|
CT_BRIDGE=${CT_BRIDGE:-"vmbr0"}
|
|
CT_NAMESERVER=${CT_NAMESERVER:-"8.8.8.8"}
|
|
|
|
# Storage Configuration
|
|
CT_STORAGE=${CT_STORAGE:-"local-lvm"}
|
|
TEMPLATE_STORAGE=${TEMPLATE_STORAGE:-"local"}
|
|
|
|
# Debian Template
|
|
DEBIAN_VERSION="12"
|
|
TEMPLATE_NAME=""
|
|
|
|
# Traefik Configuration
|
|
TRAEFIK_VERSION=${TRAEFIK_VERSION:-"v3.2"}
|
|
TRAEFIK_DASHBOARD_PORT=${TRAEFIK_DASHBOARD_PORT:-8080}
|
|
TRAEFIK_HTTP_PORT=${TRAEFIK_HTTP_PORT:-80}
|
|
TRAEFIK_HTTPS_PORT=${TRAEFIK_HTTPS_PORT:-443}
|
|
TRAEFIK_ADMIN_USER=${TRAEFIK_ADMIN_USER:-"admin"}
|
|
TRAEFIK_ADMIN_PASSWORD=${TRAEFIK_ADMIN_PASSWORD:-"Fkslrhenfk1@"}
|
|
|
|
# Container Options
|
|
CT_ONBOOT=${CT_ONBOOT:-1}
|
|
CT_UNPRIVILEGED=${CT_UNPRIVILEGED:-0} # Privileged for Docker
|
|
CT_FEATURES=${CT_FEATURES:-"keyctl=1,nesting=1"}
|
|
|
|
#################################################################
|
|
# Color Output Functions
|
|
#################################################################
|
|
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m'
|
|
|
|
info() { echo -e "${BLUE}[INFO]${NC} $1"; }
|
|
success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; }
|
|
warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
|
error() { echo -e "${RED}[ERROR]${NC} $1"; }
|
|
|
|
#################################################################
|
|
# Validation Functions
|
|
#################################################################
|
|
|
|
check_root() {
|
|
if [[ $EUID -ne 0 ]]; then
|
|
error "This script must be run as root"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
check_proxmox() {
|
|
if ! command -v pct &> /dev/null; then
|
|
error "This script must be run on a Proxmox VE host"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
check_container_exists() {
|
|
if pct status "$CT_ID" &> /dev/null; then
|
|
error "Container ID $CT_ID already exists"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
detect_and_download_template() {
|
|
info "Updating template database..."
|
|
pveam update 2>&1 || true
|
|
|
|
info "Detecting available Debian ${DEBIAN_VERSION} template..."
|
|
local available_template
|
|
available_template=$(pveam available --section system 2>/dev/null | grep "debian-${DEBIAN_VERSION}" | grep "standard" | tail -1 | awk '{print $2}')
|
|
|
|
if [[ -z "$available_template" ]]; then
|
|
error "No Debian ${DEBIAN_VERSION} template found"
|
|
exit 1
|
|
fi
|
|
|
|
TEMPLATE_NAME="$available_template"
|
|
info "Found template: $TEMPLATE_NAME"
|
|
|
|
if pveam list "$TEMPLATE_STORAGE" 2>/dev/null | grep -q "$TEMPLATE_NAME"; then
|
|
success "Template already downloaded"
|
|
return 0
|
|
fi
|
|
|
|
warn "Downloading Debian template..."
|
|
pveam download "$TEMPLATE_STORAGE" "$TEMPLATE_NAME" || {
|
|
error "Failed to download template"
|
|
exit 1
|
|
}
|
|
success "Template downloaded"
|
|
}
|
|
|
|
#################################################################
|
|
# Container Creation Functions
|
|
#################################################################
|
|
|
|
create_container() {
|
|
info "Creating LXC container $CT_ID ($CT_HOSTNAME)..."
|
|
|
|
local net_config="name=eth0,bridge=${CT_BRIDGE},ip=${CT_IP}"
|
|
if [[ "$CT_IP" != "dhcp" ]] && [[ -n "$CT_GATEWAY" ]]; then
|
|
net_config="${net_config},gw=${CT_GATEWAY}"
|
|
fi
|
|
|
|
pct create "$CT_ID" \
|
|
"${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE_NAME}" \
|
|
--hostname "$CT_HOSTNAME" \
|
|
--cores "$CT_CORES" \
|
|
--memory "$CT_MEMORY" \
|
|
--swap "$CT_SWAP" \
|
|
--rootfs "${CT_STORAGE}:${CT_DISK_SIZE}" \
|
|
--net0 "$net_config" \
|
|
--nameserver "$CT_NAMESERVER" \
|
|
--onboot "$CT_ONBOOT" \
|
|
--unprivileged "$CT_UNPRIVILEGED" \
|
|
--features "$CT_FEATURES" \
|
|
--ostype debian || {
|
|
error "Failed to create container"
|
|
exit 1
|
|
}
|
|
|
|
success "Container $CT_ID created"
|
|
}
|
|
|
|
start_container() {
|
|
info "Starting container $CT_ID..."
|
|
pct start "$CT_ID" || {
|
|
error "Failed to start container"
|
|
exit 1
|
|
}
|
|
info "Waiting for container to boot..."
|
|
sleep 5
|
|
success "Container started"
|
|
}
|
|
|
|
configure_autologin() {
|
|
info "Configuring automatic console login..."
|
|
pct exec "$CT_ID" -- bash -c "mkdir -p /etc/systemd/system/container-getty@1.service.d"
|
|
pct exec "$CT_ID" -- bash -c 'cat > /etc/systemd/system/container-getty@1.service.d/override.conf << EOF
|
|
[Service]
|
|
ExecStart=
|
|
ExecStart=-/sbin/agetty --autologin root --noclear --keep-baud tty%I 115200,38400,9600 \$TERM
|
|
EOF'
|
|
pct exec "$CT_ID" -- bash -c "systemctl daemon-reload"
|
|
success "Autologin configured"
|
|
}
|
|
|
|
#################################################################
|
|
# Docker & Traefik Installation
|
|
#################################################################
|
|
|
|
install_docker() {
|
|
info "Installing Docker..."
|
|
|
|
pct exec "$CT_ID" -- bash -c "apt-get update -qq"
|
|
pct exec "$CT_ID" -- bash -c "DEBIAN_FRONTEND=noninteractive apt-get install -y -qq curl ca-certificates gnupg apache2-utils"
|
|
|
|
# Install Docker
|
|
pct exec "$CT_ID" -- bash -c "curl -fsSL https://get.docker.com | sh"
|
|
|
|
# Enable Docker
|
|
pct exec "$CT_ID" -- bash -c "systemctl enable docker"
|
|
pct exec "$CT_ID" -- bash -c "systemctl start docker"
|
|
|
|
success "Docker installed"
|
|
}
|
|
|
|
install_traefik() {
|
|
info "Setting up Traefik..."
|
|
|
|
# Create directories
|
|
pct exec "$CT_ID" -- bash -c "mkdir -p /opt/traefik/{config,certs,logs}"
|
|
|
|
# Generate htpasswd for dashboard auth
|
|
local hashed_password
|
|
hashed_password=$(pct exec "$CT_ID" -- bash -c "echo '$TRAEFIK_ADMIN_PASSWORD' | htpasswd -niB '$TRAEFIK_ADMIN_USER'" | sed 's/\$/\$\$/g')
|
|
|
|
# Create static configuration
|
|
pct exec "$CT_ID" -- bash -c "cat > /opt/traefik/traefik.yml << 'EOF'
|
|
api:
|
|
dashboard: true
|
|
insecure: false
|
|
|
|
entryPoints:
|
|
web:
|
|
address: \":80\"
|
|
http:
|
|
redirections:
|
|
entryPoint:
|
|
to: websecure
|
|
scheme: https
|
|
websecure:
|
|
address: \":443\"
|
|
traefik:
|
|
address: \":8080\"
|
|
|
|
providers:
|
|
docker:
|
|
endpoint: \"unix:///var/run/docker.sock\"
|
|
exposedByDefault: false
|
|
network: traefik
|
|
file:
|
|
directory: /config
|
|
watch: true
|
|
|
|
certificatesResolvers:
|
|
letsencrypt:
|
|
acme:
|
|
email: devops@eunha.net
|
|
storage: /certs/acme.json
|
|
httpChallenge:
|
|
entryPoint: web
|
|
|
|
log:
|
|
level: INFO
|
|
filePath: /logs/traefik.log
|
|
|
|
accessLog:
|
|
filePath: /logs/access.log
|
|
EOF"
|
|
|
|
# Create dynamic configuration for dashboard
|
|
pct exec "$CT_ID" -- bash -c "cat > /opt/traefik/config/dashboard.yml << EOF
|
|
http:
|
|
routers:
|
|
dashboard:
|
|
rule: \"PathPrefix(\\\`/api\\\`) || PathPrefix(\\\`/dashboard\\\`)\"
|
|
entryPoints:
|
|
- traefik
|
|
service: api@internal
|
|
middlewares:
|
|
- dashboard-auth
|
|
|
|
middlewares:
|
|
dashboard-auth:
|
|
basicAuth:
|
|
users:
|
|
- \"${hashed_password}\"
|
|
EOF"
|
|
|
|
# Create ACME storage file
|
|
pct exec "$CT_ID" -- bash -c "touch /opt/traefik/certs/acme.json && chmod 600 /opt/traefik/certs/acme.json"
|
|
|
|
# Create Docker network
|
|
pct exec "$CT_ID" -- bash -c "docker network create traefik 2>/dev/null || true"
|
|
|
|
# Create docker-compose.yml
|
|
pct exec "$CT_ID" -- bash -c "cat > /opt/traefik/docker-compose.yml << 'EOF'
|
|
version: '3.8'
|
|
|
|
services:
|
|
traefik:
|
|
image: traefik:${TRAEFIK_VERSION}
|
|
container_name: traefik
|
|
restart: unless-stopped
|
|
security_opt:
|
|
- no-new-privileges:true
|
|
ports:
|
|
- \"80:80\"
|
|
- \"443:443\"
|
|
- \"8080:8080\"
|
|
volumes:
|
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
|
- ./traefik.yml:/traefik.yml:ro
|
|
- ./config:/config:ro
|
|
- ./certs:/certs
|
|
- ./logs:/logs
|
|
networks:
|
|
- traefik
|
|
labels:
|
|
- \"traefik.enable=true\"
|
|
|
|
networks:
|
|
traefik:
|
|
external: true
|
|
EOF"
|
|
|
|
# Start Traefik
|
|
pct exec "$CT_ID" -- bash -c "cd /opt/traefik && docker compose up -d"
|
|
|
|
sleep 5
|
|
success "Traefik installed and running"
|
|
}
|
|
|
|
add_container_notes() {
|
|
info "Adding container notes..."
|
|
|
|
local container_ip
|
|
container_ip=$(pct exec "$CT_ID" -- hostname -I 2>/dev/null | awk '{print $1}')
|
|
|
|
local notes="Traefik Reverse Proxy
|
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
|
|
Container ID: ${CT_ID}
|
|
Hostname: ${CT_HOSTNAME}
|
|
IP Address: ${container_ip}
|
|
CPU Cores: ${CT_CORES}
|
|
Memory: ${CT_MEMORY}MB
|
|
|
|
ACCESS
|
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
Dashboard: http://${container_ip}:${TRAEFIK_DASHBOARD_PORT}/dashboard/
|
|
Username: ${TRAEFIK_ADMIN_USER}
|
|
Password: ${TRAEFIK_ADMIN_PASSWORD}
|
|
HTTP: ${container_ip}:${TRAEFIK_HTTP_PORT}
|
|
HTTPS: ${container_ip}:${TRAEFIK_HTTPS_PORT}
|
|
|
|
MANAGEMENT
|
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
Logs: pct exec ${CT_ID} -- docker logs traefik -f
|
|
Restart: pct exec ${CT_ID} -- docker restart traefik
|
|
Config: /opt/traefik/
|
|
|
|
CONTAINER
|
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
Enter: pct enter ${CT_ID}
|
|
Stop: pct stop ${CT_ID}
|
|
Start: pct start ${CT_ID}"
|
|
|
|
pct set "$CT_ID" -description "$notes" 2>/dev/null || true
|
|
success "Notes added"
|
|
}
|
|
|
|
display_info() {
|
|
local container_ip
|
|
container_ip=$(pct exec "$CT_ID" -- hostname -I | awk '{print $1}')
|
|
|
|
echo ""
|
|
echo "================================================================="
|
|
success "Traefik LXC Container Setup Complete!"
|
|
echo "================================================================="
|
|
echo ""
|
|
echo "Container Details:"
|
|
echo " Container ID: $CT_ID"
|
|
echo " Hostname: $CT_HOSTNAME"
|
|
echo " IP Address: $container_ip"
|
|
echo ""
|
|
echo "Traefik Access:"
|
|
echo " Dashboard: http://${container_ip}:${TRAEFIK_DASHBOARD_PORT}/dashboard/"
|
|
echo " Username: $TRAEFIK_ADMIN_USER"
|
|
echo " Password: $TRAEFIK_ADMIN_PASSWORD"
|
|
echo ""
|
|
echo "Ports:"
|
|
echo " HTTP: ${container_ip}:${TRAEFIK_HTTP_PORT}"
|
|
echo " HTTPS: ${container_ip}:${TRAEFIK_HTTPS_PORT}"
|
|
echo " Dashboard: ${container_ip}:${TRAEFIK_DASHBOARD_PORT}"
|
|
echo ""
|
|
echo "Management:"
|
|
echo " Logs: pct exec $CT_ID -- docker logs traefik -f"
|
|
echo " Config: /opt/traefik/"
|
|
echo " Enter: pct enter $CT_ID"
|
|
echo ""
|
|
echo "================================================================="
|
|
}
|
|
|
|
#################################################################
|
|
# Main Execution
|
|
#################################################################
|
|
|
|
main() {
|
|
info "Starting Traefik LXC container creation..."
|
|
echo ""
|
|
|
|
check_root
|
|
check_proxmox
|
|
check_container_exists
|
|
detect_and_download_template
|
|
|
|
create_container
|
|
start_container
|
|
configure_autologin
|
|
|
|
install_docker
|
|
install_traefik
|
|
|
|
add_container_notes
|
|
display_info
|
|
}
|
|
|
|
main "$@"
|