Add traefik-gimini3.sh
bash -c "$(curl -fsSL http://192.168.1.43:3000/maq/helper-scripts/raw/branch/main/traefik-gimini3.sh)"
This commit is contained in:
498
traefik-gimini3.sh
Normal file
498
traefik-gimini3.sh
Normal file
@@ -0,0 +1,498 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Robust Traefik Install Script for Proxmox VE with Proxmox Provider Plugin
|
||||
# Includes comprehensive error handling and testing.
|
||||
|
||||
set -Eeuo pipefail
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Global variables for cleanup
|
||||
TEMP_FILES=()
|
||||
CLEANUP_CTID=""
|
||||
|
||||
# Default configuration variables
|
||||
CTID=""
|
||||
HOSTNAME="traefik"
|
||||
CORES=1
|
||||
MEMORY=512
|
||||
SWAP=512
|
||||
DISK=2
|
||||
UNPRIVILEGED=1
|
||||
FEATURES="keyctl=1,nesting=1"
|
||||
PASSWORD=""
|
||||
IP=""
|
||||
GATEWAY=""
|
||||
DNS="1.1.1.1"
|
||||
BRIDGE="vmbr0"
|
||||
START_CT=1
|
||||
TAG=""
|
||||
CLOUDFLARE_API_TOKEN=""
|
||||
CLOUDFLARE_EMAIL=""
|
||||
DOMAIN=""
|
||||
PROXMOX_API_URL="https://$(hostname):8006"
|
||||
PROXMOX_API_USER=""
|
||||
PROXMOX_API_TOKEN=""
|
||||
|
||||
# Plugin variables
|
||||
PROXMOX_PLUGIN_VERSION="v0.1.0"
|
||||
PROXMOX_PLUGIN_URL="https://plugins.traefik.io/public/plugins/67dd8d209fc1afd96d902040/traefik-proxmox-provider_${PROXMOX_PLUGIN_VERSION}_linux_amd64.zip"
|
||||
|
||||
# --- Function Definitions ---
|
||||
|
||||
# Cleanup function to remove temp files and handle incomplete containers
|
||||
cleanup() {
|
||||
local exit_code=$?
|
||||
echo -e "\n${BLUE}[INFO]${NC} Performing cleanup..."
|
||||
|
||||
# Remove temporary files
|
||||
for file in "${TEMP_FILES[@]}"; do
|
||||
if [[ -f "$file" ]]; then
|
||||
rm -f "$file" && echo "Removed temp file: $file"
|
||||
fi
|
||||
done
|
||||
|
||||
# If script fails before container is finalized, try to clean up the partial container
|
||||
if [[ -n "$CLEANUP_CTID" ]] && pct status "$CLEANUP_CTID" &>/dev/null; then
|
||||
if pct status "$CLEANUP_CTID" | grep -q "stopped"; then
|
||||
pct destroy "$CLEANUP_CTID" && echo "Destroyed incomplete container $CLEANUP_CTID"
|
||||
elif pct status "$CLEANUP_CTID" | grep -q "running"; then
|
||||
pct stop "$CLEANUP_CTID" && sleep 2
|
||||
pct destroy "$CLEANUP_CTID" && echo "Destroyed incomplete container $CLEANUP_CTID"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ $exit_code -ne 0 ]]; then
|
||||
echo -e "${RED}[ERROR]${NC} Script exited with error (code: $exit_code). Cleanup performed."
|
||||
fi
|
||||
exit $exit_code
|
||||
}
|
||||
|
||||
# Register the cleanup function to run on script exit or interruption
|
||||
trap cleanup EXIT INT TERM
|
||||
|
||||
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
|
||||
log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; }
|
||||
log_warning() { echo -e "${YELLOW}[WARNING]${NC} $1"; }
|
||||
log_error() { echo -e "${RED}[ERROR]${NC} $1" >&2; }
|
||||
|
||||
# Check if command exists
|
||||
command_exists() {
|
||||
command -v "$1" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
# Check if running as root
|
||||
check_root() {
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
log_error "This script must be run as root. Try: sudo bash $0"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Validate CTID is available
|
||||
validate_ctid() {
|
||||
local id=$1
|
||||
if [[ ! "$id" =~ ^[0-9]+$ ]]; then
|
||||
log_error "Invalid CTID: $id. Must be a number."
|
||||
return 1
|
||||
fi
|
||||
if pct status "$id" 2>/dev/null | grep -q "running\|stopped"; then
|
||||
log_error "CTID $id is already in use. Please choose another."
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Validate IP address format (simple validation)
|
||||
validate_ip() {
|
||||
local ip=$1
|
||||
if [[ "$ip" == "dhcp" ]]; then
|
||||
return 0
|
||||
fi
|
||||
# Check for CIDR format (e.g., 192.168.1.100/24)
|
||||
if [[ ! "$ip" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/[0-9]{1,2}$ ]]; then
|
||||
log_error "Invalid IP format: $ip. Must be in CIDR format (e.g., 192.168.1.100/24) or 'dhcp'."
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
show_menu() {
|
||||
echo -e "\n${BLUE}==== Proxmox VE Traefik Installer ====${NC}"
|
||||
echo "1) Default Setup (Quick Install)"
|
||||
echo "2) Custom Setup (Configure Options)"
|
||||
echo "3) Add Cloudflare DNS Challenge"
|
||||
echo "4) Configure Proxmox Provider"
|
||||
echo "5) Exit"
|
||||
read -rp "Please choose an option [1-5]: " main_choice
|
||||
}
|
||||
|
||||
custom_setup() {
|
||||
echo -e "\n${YELLOW}--- Custom Container Configuration ---${NC}"
|
||||
while true; do
|
||||
read -rp "Enter CTID (e.g., 200): " CTID
|
||||
if validate_ctid "$CTID"; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
read -rp "Enter Hostname [traefik]: " HOSTNAME_INPUT
|
||||
HOSTNAME="${HOSTNAME_INPUT:-$HOSTNAME}"
|
||||
read -rp "Enter Cores [1]: " CORES_INPUT
|
||||
CORES="${CORES_INPUT:-$CORES}"
|
||||
read -rp "Enter Memory (MB) [512]: " MEMORY_INPUT
|
||||
MEMORY="${MEMORY_INPUT:-$MEMORY}"
|
||||
read -rp "Enter Swap (MB) [512]: " SWAP_INPUT
|
||||
SWAP="${SWAP_INPUT:-$SWAP}"
|
||||
read -rp "Enter Disk Size (GB) [2]: " DISK_INPUT
|
||||
DISK="${DISK_INPUT:-$DISK}"
|
||||
|
||||
while true; do
|
||||
read -rp "Enter IP Address (CIDR format, e.g., 192.168.1.100/24) or 'dhcp': " IP
|
||||
if validate_ip "$IP"; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ "$IP" != "dhcp" ]]; then
|
||||
read -rp "Enter Gateway [192.168.1.1]: " GATEWAY_INPUT
|
||||
GATEWAY="${GATEWAY_INPUT:-$GATEWAY}"
|
||||
read -rp "Enter DNS Server [1.1.1.1]: " DNS_INPUT
|
||||
DNS="${DNS_INPUT:-$DNS}"
|
||||
fi
|
||||
|
||||
read -rp "Enter Bridge [vmbr0]: " BRIDGE_INPUT
|
||||
BRIDGE="${BRIDGE_INPUT:-$BRIDGE}"
|
||||
read -srp "Enter Root Password for Container: " PASSWORD
|
||||
echo
|
||||
read -rp "Start container after creation? (y/n) [y]: " START_CT_INPUT
|
||||
START_CT_INPUT="${START_CT_INPUT:-y}"
|
||||
[[ $START_CT_INPUT == "n" ]] && START_CT=0
|
||||
read -rp "Enter Proxmox VE Tag (optional): " TAG
|
||||
}
|
||||
|
||||
setup_cloudflare() {
|
||||
echo -e "\n${YELLOW}--- Cloudflare DNS Challenge Setup ---${NC}"
|
||||
log_info "This will configure Traefik to use Cloudflare DNS for wildcard certificates."
|
||||
log_info "Ensure your domain's nameservers are pointed to Cloudflare."
|
||||
read -rp "Enter your domain (e.g., example.com): " DOMAIN
|
||||
read -rp "Enter your Cloudflare Email: " CLOUDFLARE_EMAIL
|
||||
read -srp "Enter your Cloudflare API Token: " CLOUDFLARE_API_TOKEN
|
||||
echo
|
||||
}
|
||||
|
||||
setup_proxmox_provider() {
|
||||
echo -e "\n${YELLOW}--- Proxmox Provider Configuration ---${NC}"
|
||||
log_info "The Traefik Proxmox Provider will automatically discover services in your containers/VMs."
|
||||
log_warning "You need to create an API Token in the Proxmox web UI first."
|
||||
echo
|
||||
read -rp "Enter the Proxmox API User (e.g., 'traefik-api@pve'): " PROXMOX_API_USER
|
||||
read -srp "Enter the Proxmox API Token Secret: " PROXMOX_API_TOKEN
|
||||
echo
|
||||
read -rp "Enter Proxmox API URL [${PROXMOX_API_URL}]: " PROXMOX_API_URL_INPUT
|
||||
PROXMOX_API_URL="${PROXMOX_API_URL_INPUT:-$PROXMOX_API_URL}"
|
||||
}
|
||||
|
||||
create_container() {
|
||||
local id=$1
|
||||
local TEMPLATE_NAME="debian-12-standard_12.7-1_amd64.tar.zst"
|
||||
|
||||
# Check and download template if it doesn't exist
|
||||
if ! pveam list local | grep -q "$TEMPLATE_NAME"; then
|
||||
log_info "LXC template '$TEMPLATE_NAME' not found locally. Downloading..."
|
||||
if ! pveam download local "$TEMPLATE_NAME"; then
|
||||
log_error "Failed to download the required LXC template. Please check your internet connection or Proxmox template mirrors."
|
||||
return 1
|
||||
fi
|
||||
log_success "Template downloaded successfully."
|
||||
fi
|
||||
|
||||
log_info "Creating LXC container (ID: $id)..."
|
||||
local CREATE_CMD="pct create $id \
|
||||
\"local:vztmpl/$TEMPLATE_NAME\" \
|
||||
--arch amd64 \
|
||||
--cores $CORES \
|
||||
--memory $MEMORY \
|
||||
--swap $SWAP \
|
||||
--rootfs local-lvm:${DISK} \
|
||||
--hostname $HOSTNAME \
|
||||
--password \"$PASSWORD\" \
|
||||
--features \"$FEATURES\" \
|
||||
--unprivileged $UNPRIVILEGED \
|
||||
--onboot 1"
|
||||
|
||||
if [[ "$IP" == "dhcp" ]]; then
|
||||
CREATE_CMD="$CREATE_CMD --net0 name=eth0,bridge=$BRIDGE,ip=dhcp"
|
||||
else
|
||||
CREATE_CMD="$CREATE_CMD --net0 name=eth0,bridge=$BRIDGE,ip=$IP,gw=$GATEWAY"
|
||||
CREATE_CMD="$CREATE_CMD --nameserver \"$DNS\""
|
||||
fi
|
||||
|
||||
if ! eval "$CREATE_CMD"; then
|
||||
log_error "Failed to create container $id. Check parameters and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
CLEANUP_CTID="$id" # Set global for cleanup after successful creation
|
||||
|
||||
if [[ -n "$TAG" ]]; then
|
||||
if ! pct set "$id" --tags "$TAG"; then
|
||||
log_warning "Failed to apply tag '$TAG' to container $id. Continuing..."
|
||||
else
|
||||
log_info "Tag '$TAG' applied to container $id."
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ $START_CT -eq 1 ]]; then
|
||||
if ! pct start "$id"; then
|
||||
log_error "Failed to start container $id. Check 'pct status $id' for details."
|
||||
return 1
|
||||
fi
|
||||
log_info "Starting container $id..."
|
||||
for i in {1..10}; do
|
||||
if pct status "$id" | grep -q "running"; then
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
if ! pct status "$id" | grep -q "running"; then
|
||||
log_warning "Container $id may not be fully ready. Proceeding with caution..."
|
||||
fi
|
||||
else
|
||||
log_info "Container $id created but not started."
|
||||
fi
|
||||
|
||||
CLEANUP_CTID="" # Clear cleanup ID since container was created successfully
|
||||
return 0
|
||||
}
|
||||
|
||||
safe_container_exec() {
|
||||
local id=$1
|
||||
shift
|
||||
local command="$*"
|
||||
local max_retries=3
|
||||
local retry_count=0
|
||||
|
||||
while [[ $retry_count -lt $max_retries ]]; do
|
||||
if pct exec "$id" -- bash -c "$command"; then
|
||||
return 0
|
||||
else
|
||||
((retry_count++))
|
||||
if [[ $retry_count -eq $max_retries ]]; then
|
||||
log_warning "Command failed after $max_retries attempts: $command"
|
||||
return 1
|
||||
fi
|
||||
sleep 2
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
install_traefik() {
|
||||
local id=$1
|
||||
log_info "Installing Traefik in container $id..."
|
||||
|
||||
if ! safe_container_exec "$id" "apt-get update"; then
|
||||
log_warning "apt-get update had issues. Network might be slow. Continuing..."
|
||||
fi
|
||||
|
||||
if ! safe_container_exec "$id" "apt-get install -y curl wget sudo unzip"; then
|
||||
log_error "Failed to install essential packages in container $id."
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_info "Installing Traefik binary and service..."
|
||||
if ! safe_container_exec "$id" "wget -qO- https://raw.githubusercontent.com/traefik/traefik/master/install.sh | bash -s -- --version v2.11 --daemon"; then
|
||||
log_error "Failed to install Traefik binary. Please check for errors."
|
||||
return 1
|
||||
fi
|
||||
log_success "Traefik binary installed."
|
||||
|
||||
if ! safe_container_exec "$id" "mkdir -p /etc/traefik/conf.d"; then
|
||||
log_warning "Could not create conf.d directory. This might cause issues later."
|
||||
fi
|
||||
|
||||
# Install Proxmox Provider plugin if configured
|
||||
if [[ -n "$PROXMOX_API_USER" && -n "$PROXMOX_API_TOKEN" ]]; then
|
||||
log_info "Downloading and installing Traefik Proxmox Provider plugin version ${PROXMOX_PLUGIN_VERSION}..."
|
||||
if ! safe_container_exec "$id" "wget --timeout=30 -O /tmp/proxmox-plugin.zip ${PROXMOX_PLUGIN_URL}"; then
|
||||
log_warning "Failed to download Proxmox Provider plugin. Check internet connection."
|
||||
else
|
||||
if ! safe_container_exec "$id" "unzip -o /tmp/proxmox-plugin.zip -d /tmp/ && install -m 755 /tmp/traefik-proxmox-provider /usr/local/bin/ && rm -f /tmp/proxmox-plugin.zip /tmp/traefik-proxmox-provider"; then
|
||||
log_warning "Failed to install Proxmox Provider plugin properly."
|
||||
else
|
||||
log_success "Proxmox Provider plugin installed."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Configure Traefik
|
||||
log_info "Configuring Traefik..."
|
||||
if ! safe_container_exec "$id" "cat > /etc/traefik/traefik.yml <<EOF
|
||||
global:
|
||||
sendAnonymousUsage: false
|
||||
|
||||
api:
|
||||
dashboard: true
|
||||
insecure: false
|
||||
|
||||
entryPoints:
|
||||
web:
|
||||
address: :80
|
||||
websecure:
|
||||
address: :443
|
||||
|
||||
providers:
|
||||
docker:
|
||||
endpoint: \"unix:///var/run/docker.sock\"
|
||||
exposedByDefault: false
|
||||
file:
|
||||
directory: /etc/traefik/conf.d
|
||||
watch: true
|
||||
EOF"; then
|
||||
log_error "Failed to write base Traefik configuration."
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Cloudflare configuration
|
||||
if [[ -n "$CLOUDFLARE_API_TOKEN" && -n "$DOMAIN" ]]; then
|
||||
log_info "Adding Cloudflare configuration..."
|
||||
if ! safe_container_exec "$id" "cat >> /etc/traefik/traefik.yml <<EOF
|
||||
|
||||
certificatesResolvers:
|
||||
cloudflare:
|
||||
acme:
|
||||
email: $CLOUDFLARE_EMAIL
|
||||
storage: /etc/traefik/acme.json
|
||||
dnsChallenge:
|
||||
provider: cloudflare
|
||||
delayBeforeCheck: 30
|
||||
resolvers:
|
||||
- \"1.1.1.1:53\"
|
||||
- \"1.0.0.1:53\"
|
||||
EOF"; then
|
||||
log_warning "Failed to append Cloudflare configuration to Traefik config."
|
||||
fi
|
||||
|
||||
if ! safe_container_exec "$id" "echo \"CF_API_EMAIL=$CLOUDFLARE_EMAIL\" > /etc/traefik/cloudflare.env && echo \"CF_DNS_API_TOKEN=$CLOUDFLARE_API_TOKEN\" >> /etc/traefik/cloudflare.env && chmod 600 /etc/traefik/cloudflare.env"; then
|
||||
log_warning "Failed to create Cloudflare environment file."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Proxmox Provider configuration
|
||||
if [[ -n "$PROXMOX_API_USER" && -n "$PROXMOX_API_TOKEN" ]]; then
|
||||
log_info "Adding Proxmox Provider configuration..."
|
||||
if ! safe_container_exec "$id" "cat >> /etc/traefik/traefik.yml <<EOF
|
||||
plugin:
|
||||
proxmox:
|
||||
apiURL: \"$PROXMOX_API_URL\"
|
||||
insecure: false
|
||||
user: \"$PROXMOX_API_USER\"
|
||||
token: \"$PROXMOX_API_TOKEN\"
|
||||
tls:
|
||||
ca: /etc/traefik/proxmox-ca.pem
|
||||
refreshInterval: 30s
|
||||
exposedByDefault: false
|
||||
EOF"; then
|
||||
log_warning "Failed to append Proxmox Provider configuration to Traefik config."
|
||||
fi
|
||||
|
||||
# Try to get Proxmox CA certificate
|
||||
log_info "Attempting to retrieve Proxmox CA certificate automatically..."
|
||||
if ! safe_container_exec "$id" "curl -s --insecure \"$PROXMOX_API_URL/json/nodes/\" 2>&1 | awk 'BEGIN {cert=0} /^.*SSL certificate problem/ {cert=1} {if(cert==1) print}' | sed -n '/-----BEGIN CERTIFICATE-----/,/-----END CERTIFICATE-----/p' > /etc/traefik/proxmox-ca.pem"; then
|
||||
log_warning "Could not automatically retrieve Proxmox CA certificate. The certificate download attempt was made using an insecure method, and it is recommended to transfer the certificate manually for enhanced security. You may need to add it manually to /etc/traefik/proxmox-ca.pem in the container."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Restart Traefik
|
||||
log_info "Restarting Traefik to apply configuration..."
|
||||
if ! safe_container_exec "$id" "systemctl restart traefik"; then
|
||||
log_error "Failed to restart Traefik service. Check configuration manually."
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_success "Traefik installation and configuration complete in container $id."
|
||||
return 0
|
||||
}
|
||||
|
||||
main() {
|
||||
check_root
|
||||
|
||||
# Test for required commands
|
||||
if ! command_exists pct; then
|
||||
log_error "Proxmox CLI tools (pct) not found. Are you running this on a Proxmox node?"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
while true; do
|
||||
show_menu
|
||||
case $main_choice in
|
||||
1)
|
||||
CTID=$(( 200 + RANDOM % 100 ))
|
||||
if ! validate_ctid "$CTID"; then
|
||||
CTID=$(( CTID + 1 )) # Simple retry
|
||||
validate_ctid "$CTID" || exit 1
|
||||
fi
|
||||
IP="dhcp"
|
||||
GATEWAY=""
|
||||
DNS="1.1.1.1"
|
||||
PASSWORD=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 16 ; echo '')
|
||||
log_info "Generated random CTID: $CTID"
|
||||
log_info "Generated random password: $PASSWORD"
|
||||
log_warning "SECURITY WARNING: The password above is for initial access only. It is strongly recommended that you log in and change it immediately."
|
||||
if create_container "$CTID"; then
|
||||
if install_traefik "$CTID"; then
|
||||
log_success "Default setup completed successfully!"
|
||||
else
|
||||
log_error "Traefik installation had issues. Check container logs."
|
||||
fi
|
||||
fi
|
||||
break
|
||||
;;
|
||||
2)
|
||||
custom_setup
|
||||
if [[ -z "$CTID" || -z "$PASSWORD" || ( "$IP" != "dhcp" && -z "$IP" ) ]]; then
|
||||
log_error "Missing required parameters (CTID, Password, or IP)."
|
||||
else
|
||||
if create_container "$CTID"; then
|
||||
if install_traefik "$CTID"; then
|
||||
log_success "Custom setup completed successfully!"
|
||||
else
|
||||
log_error "Traefik installation had issues. Check container logs."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
break
|
||||
;;
|
||||
3)
|
||||
setup_cloudflare
|
||||
log_info "Cloudflare settings saved."
|
||||
;;
|
||||
4)
|
||||
setup_proxmox_provider
|
||||
log_info "Proxmox Provider settings saved."
|
||||
;;
|
||||
5)
|
||||
log_info "Exiting. Nothing was installed."
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
log_error "Invalid option. Please choose 1, 2, 3, 4, or 5."
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
log_success "Script execution finished!"
|
||||
log_info "Container ID: $CTID"
|
||||
log_info "Hostname: $HOSTNAME"
|
||||
[[ -n "$PASSWORD" ]] && log_info "Root Password: $PASSWORD"
|
||||
[[ -n "$PROXMOX_API_USER" ]] && log_info "Proxmox Provider is CONFIGURED for auto-discovery."
|
||||
[[ -n "$DOMAIN" ]] && log_info "Cloudflare DNS challenge configured for domain: $DOMAIN"
|
||||
log_info "You can access the container: pct enter $CTID"
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user