#!/usr/bin/env bash set -euo pipefail ulimit -c 0 export HISTIGNORE="*openssl*:*sk-*:*PASSWORD*:*MASTER_KEY*" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SECRETS_DIR="${SCRIPT_DIR}/secrets" FORCE_FIREWALL=false ENABLE_PROXY=false INSTALL_SYSTEMD=false TARGET_PORT="4000" RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' CYAN='\033[0;36m' BOLD='\033[1m' NC='\033[0m' log_info() { echo -e "${BLUE}[INFO]${NC} $(date +'%Y-%m-%dT%H:%M:%S%z') - $1"; } log_warn() { echo -e "${YELLOW}[WARN]${NC} $(date +'%Y-%m-%dT%H:%M:%S%z') - $1"; } log_error() { echo -e "${RED}[ERROR]${NC} $(date +'%Y-%m-%dT%H:%M:%S%z') - $1" >&2; } cleanup_on_error() { local exit_code=$? if [ $exit_code -ne 0 ]; then log_error "Deployment failed unexpectedly with exit code $exit_code." fi } trap cleanup_on_error EXIT cd "${SCRIPT_DIR}" for arg in "$@"; do case $arg in --force-open-firewall) FORCE_FIREWALL=true shift ;; --enable-egress-proxy) ENABLE_PROXY=true shift ;; --install-systemd) INSTALL_SYSTEMD=true shift ;; *) ;; esac done log_info "Starting Production LiteLLM Infrastructure Deployment..." if [ "$(id -u)" -ne 0 ]; then log_error "Root privileges are required to setup secrets, systemd, and UFW rules." exit 1 fi REQUIRED_TOOLS=("docker" "openssl" "envsubst") for tool in "${REQUIRED_TOOLS[@]}"; do if ! command -v "$tool" >/dev/null 2>&1; then log_error "Required dependency '$tool' is missing." exit 1 fi done if ! docker compose version >/dev/null 2>&1; then log_error "Docker Compose V2 is missing." exit 1 fi # Firewall Check if command -v ufw >/dev/null 2>&1; then UFW_STATUS=$(ufw status | grep -i "status: active" || true) if [ -n "${UFW_STATUS}" ]; then PORT_ALLOWED=$(ufw status | grep -E "${TARGET_PORT}(/tcp)?.*ALLOW" || true) if [ -z "${PORT_ALLOWED}" ]; then if [ "${FORCE_FIREWALL}" = true ]; then log_info "Force flag enabled. Granting rule for port ${TARGET_PORT}/tcp..." ufw allow "${TARGET_PORT}/tcp" comment 'LiteLLM Proxy' else log_error "Port ${TARGET_PORT} is blocked by UFW firewall." log_error "Re-run with '--force-open-firewall' or run: ufw allow ${TARGET_PORT}/tcp" exit 1 fi fi fi fi # Provision Secrets mkdir -p -m 700 "${SECRETS_DIR}" generate_secret_file() { local file_path="$1" local secret_content="$2" if [ ! -f "${file_path}" ]; then printf "%s" "${secret_content}" > "${file_path}" chmod 600 "${file_path}" chown 101:101 "${file_path}" 2>/dev/null || true fi } DB_PASS_RAW="$(openssl rand -hex 20)" generate_secret_file "${SECRETS_DIR}/db_password.txt" "${DB_PASS_RAW}" DB_PASS_STORED="$(cat "${SECRETS_DIR}/db_password.txt")" DB_CONNECTION_URL="postgresql://llmproxy:${DB_PASS_STORED}@db:5432/litellm" generate_secret_file "${SECRETS_DIR}/db_url.txt" "${DB_CONNECTION_URL}" generate_secret_file "${SECRETS_DIR}/master_key.txt" "sk-$(openssl rand -hex 16)" generate_secret_file "${SECRETS_DIR}/salt_key.txt" "sk-$(openssl rand -hex 16)" unset DB_PASS_RAW DB_PASS_STORED DB_CONNECTION_URL # Environment File if [ ! -f ".env" ]; then cat > .env < /etc/squid/squid.conf acl SSL_ports port 443 acl Safe_ports port 80 acl Safe_ports port 443 acl CONNECT method CONNECT http_access deny !Safe_ports http_access deny CONNECT !SSL_ports http_access allow all http_port 3128 SQUIDCONF chown -R proxy:proxy /var/spool/squid /var/log/squid /etc/squid exec /sbin/entrypoint.sh networks: public-egress: aliases: - squid tmpfs: - /var/spool/squid:rw,noexec,nosuid,nodev,size=64m - /var/log/squid:rw,noexec,nosuid,nodev,size=16m healthcheck: test: ["CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/3128"] interval: 5s timeout: 3s retries: 5 start_period: 5s EOF ) export PROXY_ENV_MAPPING export LITELLM_SQUID_DEPENDENCY export SQUID_SERVICE_BLOCK else log_info "Mode: Option 1 (Direct Egress)" export PROXY_ENV_MAPPING="# egress proxy disabled" export LITELLM_SQUID_DEPENDENCY="# no squid dependency" export SQUID_SERVICE_BLOCK="# no squid service" fi # Inject variables into template envsubst '${PROXY_ENV_MAPPING} ${LITELLM_SQUID_DEPENDENCY} ${SQUID_SERVICE_BLOCK}' < compose.yaml.template > compose.yaml # Systemd Integration SERVICE_FILE="/etc/systemd/system/litellm.service" DOCKER_BIN="$(command -v docker)" if [ "${INSTALL_SYSTEMD}" = true ]; then log_info "Installing and enabling Systemd service unit..." cat > "${SERVICE_FILE}" <