feat: add one-click deploy script + project optimization
- deploy.sh: one-click deployment (squid + venv + pip + gunicorn + systemd) - gunicorn_config.py: unified gunicorn config with env var overrides - .env.example: env var template for SECRET_KEY, port, workers, security - wsgi.py: create all runtime dirs (uploads, ssl_certs); optional dotenv loading - requirements.txt: add python-dotenv + cryptography - .gitignore: cover runtime dirs, .env, pyc files
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
# Runtime data — generated by deploy.sh, consumed by app.py
|
||||
# Copy this file to .env and adjust as needed, or export the vars before starting.
|
||||
|
||||
# Flask session secret — MUST be changed in production!
|
||||
# Generate with: python3 -c "import secrets; print(secrets.token_urlsafe(48))"
|
||||
SECRET_KEY=change-me-in-production
|
||||
|
||||
# Bind address / port (gunicorn)
|
||||
SQUIDMGR_HOST=0.0.0.0
|
||||
SQUIDMGR_PORT=5200
|
||||
SQUIDMGR_WORKERS=2
|
||||
SQUIDMGR_TIMEOUT=120
|
||||
|
||||
# Squid paths (override if squid is in a non-standard location)
|
||||
# SQUID_BINARY=squid
|
||||
# SQUID_CONF=/etc/squid/squid.conf
|
||||
# SQUID_ACCESS_LOG=/var/log/squid/access.log
|
||||
# SQUID_CACHE_LOG=/var/log/squid/cache.log
|
||||
|
||||
# Session / security
|
||||
SQUIDMGR_IDLE_TO=1800
|
||||
SQUIDMGR_ABS_TO=28800
|
||||
SQUIDMGR_THROTTLE_WIN=300
|
||||
SQUIDMGR_THROTTLE_MAX=5
|
||||
SQUIDMGR_THROTTLE_LOCK=900
|
||||
SQUIDMGR_CSRF=1
|
||||
+7
-53
@@ -1,57 +1,11 @@
|
||||
# Python
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
*.so
|
||||
.Python
|
||||
*.egg
|
||||
*.egg-info/
|
||||
dist/
|
||||
build/
|
||||
.eggs/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
|
||||
# Virtual envs
|
||||
venv/
|
||||
env/
|
||||
.venv/
|
||||
ENV/
|
||||
|
||||
# pytest / coverage
|
||||
.pytest_cache/
|
||||
.coverage
|
||||
htmlcov/
|
||||
.tox/
|
||||
|
||||
# IDE
|
||||
.idea/
|
||||
.vscode/
|
||||
*.swp
|
||||
*.swo
|
||||
.DS_Store
|
||||
|
||||
# Logs
|
||||
*.log
|
||||
|
||||
# Local instance (sqlite db, uploaded files, generated certs)
|
||||
# runtime data
|
||||
instance/
|
||||
uploads/
|
||||
backups/
|
||||
uploads/
|
||||
ssl_certs/
|
||||
alerts/
|
||||
instances/
|
||||
log_storage/
|
||||
security/
|
||||
|
||||
# Sample artifacts
|
||||
*.pid
|
||||
*.sock
|
||||
*.pid.lock
|
||||
|
||||
# Local config overrides
|
||||
*.pyc
|
||||
__pycache__/
|
||||
*.pyc
|
||||
*.pyo
|
||||
.env
|
||||
.env.local
|
||||
|
||||
# OS
|
||||
Thumbs.db
|
||||
*.log
|
||||
|
||||
@@ -0,0 +1,425 @@
|
||||
#!/usr/bin/env bash
|
||||
# =============================================================================
|
||||
# Squid Manager - 一键部署脚本
|
||||
# =============================================================================
|
||||
# 功能:
|
||||
# 1. 安装系统依赖 (squid, python3, pip, gcc 等)
|
||||
# 2. 创建 Python 虚拟环境并安装 pip 依赖
|
||||
# 3. 初始化数据库 & 默认管理员
|
||||
# 4. 生成 gunicorn + systemd 服务文件并启动
|
||||
# 5. 配置 squid (放行 localnet + 基本安全设置)
|
||||
#
|
||||
# 用法:
|
||||
# bash deploy.sh # 全自动部署 (默认 /opt/squid-manager)
|
||||
# INSTALL_DIR=/opt/sm bash deploy.sh # 自定义安装目录
|
||||
# bash deploy.sh --no-squid # 不安装/配置 squid
|
||||
# bash deploy.sh --no-start # 不启动服务 (仅生成文件)
|
||||
# =============================================================================
|
||||
set -euo pipefail
|
||||
|
||||
# ---- 配置 -------------------------------------------------------------------
|
||||
INSTALL_DIR="${INSTALL_DIR:-/opt/squid-manager}"
|
||||
SERVICE_NAME="${SERVICE_NAME:-squid-manager}"
|
||||
GUNICORN_HOST="${SQUIDMGR_HOST:-0.0.0.0}"
|
||||
GUNICORN_PORT="${SQUIDMGR_PORT:-5200}"
|
||||
GUNICORN_WORKERS="${SQUIDMGR_WORKERS:-2}"
|
||||
ADMIN_USER="${ADMIN_USER:-admin}"
|
||||
ADMIN_PASS="${ADMIN_PASS:-admin123}"
|
||||
|
||||
INSTALL_SQUID=true
|
||||
START_SERVICE=true
|
||||
SKIP_EXISTING=false # 若服务已存在是否跳过
|
||||
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--no-squid) INSTALL_SQUID=false ;;
|
||||
--no-start) START_SERVICE=false ;;
|
||||
--skip-existing) SKIP_EXISTING=true ;;
|
||||
-h|--help)
|
||||
sed -n '2,20p' "$0"
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "未知参数: $arg" >&2; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# ---- 工具函数 ---------------------------------------------------------------
|
||||
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m'
|
||||
info() { echo -e "${GREEN}[INFO]${NC} $*"; }
|
||||
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
|
||||
error() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
|
||||
|
||||
_generate_minimal_squid_conf() {
|
||||
# 生成一份最小可用的 Squid 5.x 配置
|
||||
local out="$1"
|
||||
cat > "$out" << 'SQUIDEOF'
|
||||
# Minimal Squid 5.x configuration — generated by Squid Manager deploy.sh
|
||||
# 可通过 Web UI (/config/raw) 继续编辑和扩展。
|
||||
|
||||
http_port 3128
|
||||
icp_port 3130
|
||||
|
||||
# Cache
|
||||
cache_mem 256 MB
|
||||
maximum_object_size 4096 KB
|
||||
cache_dir ufs /var/spool/squid 100 16 256
|
||||
|
||||
# ACLs
|
||||
acl localhost src 127.0.0.1/32 ::1
|
||||
acl to_localhost dst 127.0.0.0/8 0.0.0.0/32 ::1
|
||||
acl localnet src 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 169.254.0.0/16 fc00::/7 fe80::/10
|
||||
acl Safe_ports port 80 443 21 70 210 1025-65535
|
||||
acl SSL_ports port 443 563
|
||||
acl CONNECT method CONNECT
|
||||
|
||||
# Refresh patterns
|
||||
refresh_pattern ^ftp: 1440 20% 10080
|
||||
refresh_pattern ^gopher: 1440 0% 1440
|
||||
refresh_pattern -i (/cgi-bin/|\?) 0 0% 0
|
||||
refresh_pattern . 0 20% 4320
|
||||
|
||||
# Access rules
|
||||
http_access allow manager localhost
|
||||
http_access deny manager
|
||||
http_access deny !Safe_ports
|
||||
http_access deny CONNECT !SSL_ports
|
||||
http_access allow localhost
|
||||
http_access allow localnet
|
||||
http_access deny all
|
||||
|
||||
# Logging
|
||||
access_log /var/log/squid/access.log squid
|
||||
cache_log /var/log/squid/cache.log
|
||||
|
||||
# Misc
|
||||
coredump_dir /var/spool/squid
|
||||
visible_hostname squid-manager
|
||||
SQUIDEOF
|
||||
}
|
||||
|
||||
must_run_as_root() {
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
error "此脚本必须以 root 运行 (sudo $0)"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
detect_os() {
|
||||
if [[ -f /etc/os-release ]]; then
|
||||
. /etc/os-release
|
||||
OS_ID="$ID"
|
||||
OS_VER="$VERSION_ID"
|
||||
elif command -v apt-get &>/dev/null; then
|
||||
OS_ID="debian"
|
||||
elif command -v yum &>/dev/null; then
|
||||
OS_ID="centos"
|
||||
else
|
||||
error "无法识别操作系统"
|
||||
exit 1
|
||||
fi
|
||||
info "操作系统: $OS_ID $OS_VER"
|
||||
}
|
||||
|
||||
pkg_install() {
|
||||
info "安装系统包: $*"
|
||||
case "$OS_ID" in
|
||||
debian|ubuntu)
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt-get update -qq
|
||||
apt-get install -y -qq "$@"
|
||||
;;
|
||||
centos|rhel|rocky|almalinux|ol)
|
||||
yum install -y -q "$@"
|
||||
;;
|
||||
*)
|
||||
error "不支持的包管理器: $OS_ID"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# ---- 1. 前置检查 ------------------------------------------------------------
|
||||
must_run_as_root
|
||||
detect_os
|
||||
|
||||
info "安装目录: $INSTALL_DIR"
|
||||
info "服务名: $SERVICE_NAME"
|
||||
info "监听: $GUNICORN_HOST:$GUNICORN_PORT"
|
||||
|
||||
# ---- 2. 安装系统依赖 --------------------------------------------------------
|
||||
SYS_PACKAGES=(
|
||||
python3 python3-pip python3-venv python3-dev
|
||||
gcc libffi-dev libssl-dev
|
||||
curl
|
||||
)
|
||||
|
||||
if $INSTALL_SQUID; then
|
||||
SYS_PACKAGES+=(squid squidclient)
|
||||
fi
|
||||
|
||||
pkg_install "${SYS_PACKAGES[@]}"
|
||||
|
||||
# 确保 python3 / pip3 可用
|
||||
PYTHON_BIN="$(command -v python3)"
|
||||
PIP_BIN="$(command -v pip3 || command -v pip)"
|
||||
info "Python: $PYTHON_BIN"
|
||||
info "Pip: $PIP_BIN"
|
||||
|
||||
# ---- 3. 部署项目文件 --------------------------------------------------------
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
if [[ "$SCRIPT_DIR" != "$INSTALL_DIR" ]]; then
|
||||
if [[ -d "$INSTALL_DIR" ]] && $SKIP_EXISTING; then
|
||||
warn "安装目录已存在且 --skip-existing,跳过文件复制"
|
||||
else
|
||||
info "复制项目文件到 $INSTALL_DIR"
|
||||
mkdir -p "$INSTALL_DIR"
|
||||
# 复制源码(排除 .git / instance / backups 等运行时目录)
|
||||
rsync -a --delete \
|
||||
--exclude='.git/' \
|
||||
--exclude='__pycache__/' \
|
||||
--exclude='*.pyc' \
|
||||
--exclude='instance/*.db' \
|
||||
--exclude='backups/' \
|
||||
--exclude='uploads/' \
|
||||
--exclude='ssl_certs/*.pem' \
|
||||
--exclude='.env' \
|
||||
"$SCRIPT_DIR/" "$INSTALL_DIR/"
|
||||
fi
|
||||
fi
|
||||
|
||||
cd "$INSTALL_DIR"
|
||||
|
||||
# 确保运行时目录存在
|
||||
mkdir -p instance backups uploads ssl_certs
|
||||
chmod 700 instance ssl_certs
|
||||
|
||||
# ---- 4. 创建虚拟环境 + 安装 pip 依赖 ----------------------------------------
|
||||
VENV_DIR="$INSTALL_DIR/.venv"
|
||||
|
||||
if [[ -d "$VENV_DIR" ]] && $SKIP_EXISTING; then
|
||||
warn "虚拟环境已存在且 --skip-existing,跳过依赖安装"
|
||||
else
|
||||
info "创建 Python 虚拟环境: $VENV_DIR"
|
||||
$PYTHON_BIN -m venv "$VENV_DIR"
|
||||
|
||||
info "升级 pip + 安装 Python 依赖"
|
||||
"$VENV_DIR/bin/pip" install --upgrade pip setuptools wheel
|
||||
"$VENV_DIR/bin/pip" install -r requirements.txt
|
||||
fi
|
||||
|
||||
PYTHON="$VENV_DIR/bin/python"
|
||||
GUNICORN="$VENV_DIR/bin/gunicorn"
|
||||
|
||||
# ---- 5. 生成 .env 配置 ------------------------------------------------------
|
||||
ENV_FILE="$INSTALL_DIR/.env"
|
||||
if [[ ! -f "$ENV_FILE" ]] || ! $SKIP_EXISTING; then
|
||||
info "生成 .env 配置文件"
|
||||
SECRET_KEY="$($PYTHON -c "import secrets; print(secrets.token_urlsafe(48))")"
|
||||
cat > "$ENV_FILE" <<EOF
|
||||
# Squid Manager - 自动生成于 $(date -Iseconds)
|
||||
SECRET_KEY=$SECRET_KEY
|
||||
SQUIDMGR_HOST=$GUNICORN_HOST
|
||||
SQUIDMGR_PORT=$GUNICORN_PORT
|
||||
SQUIDMGR_WORKERS=$GUNICORN_WORKERS
|
||||
SQUIDMGR_TIMEOUT=120
|
||||
EOF
|
||||
chmod 600 "$ENV_FILE"
|
||||
fi
|
||||
|
||||
# ---- 6. 初始化数据库 & 默认管理员 ------------------------------------------
|
||||
info "初始化数据库"
|
||||
$PYTHON -c "
|
||||
import os, sys
|
||||
os.environ.setdefault('SECRET_KEY', 'deploy-init')
|
||||
sys.path.insert(0, '$INSTALL_DIR')
|
||||
from wsgi import app, db
|
||||
from app import User
|
||||
with app.app_context():
|
||||
db.create_all()
|
||||
# 种子管理员
|
||||
u = User.query.filter_by(username='$ADMIN_USER').first()
|
||||
if u is None:
|
||||
u = User(username='$ADMIN_USER', role='admin')
|
||||
u.set_password('$ADMIN_PASS')
|
||||
db.session.add(u)
|
||||
db.session.commit()
|
||||
print(f'[init] 创建管理员: $ADMIN_USER / $ADMIN_PASS')
|
||||
else:
|
||||
u.set_password('$ADMIN_PASS')
|
||||
db.session.commit()
|
||||
print(f'[init] 管理员密码已更新: $ADMIN_USER')
|
||||
"
|
||||
|
||||
# ---- 7. 配置 Squid (如果需要) ----------------------------------------------
|
||||
if $INSTALL_SQUID; then
|
||||
SQUID_CONF="/etc/squid/squid.conf"
|
||||
|
||||
# 如果现有配置无法通过语法校验(升级后废弃指令等),用最小可用配置兜底
|
||||
if [[ -f "$SQUID_CONF" ]]; then
|
||||
if ! squid -k parse -f "$SQUID_CONF" &>/dev/null; then
|
||||
warn "现有 squid.conf 语法校验失败,备份后用最小可用配置替换"
|
||||
cp "$SQUID_CONF" "${SQUID_CONF}.broken.$(date +%s)"
|
||||
_generate_minimal_squid_conf "$SQUID_CONF"
|
||||
fi
|
||||
else
|
||||
info "squid.conf 不存在,生成最小可用配置"
|
||||
mkdir -p "$(dirname "$SQUID_CONF")"
|
||||
_generate_minimal_squid_conf "$SQUID_CONF"
|
||||
fi
|
||||
|
||||
if [[ -f "$SQUID_CONF" ]]; then
|
||||
info "配置 Squid"
|
||||
|
||||
# 备份原始配置
|
||||
if [[ ! -f "${SQUID_CONF}.orig" ]]; then
|
||||
cp "$SQUID_CONF" "${SQUID_CONF}.orig"
|
||||
info "已备份原始配置到 ${SQUID_CONF}.orig"
|
||||
fi
|
||||
|
||||
# 放行内网 (localnet)
|
||||
# 1) 确保 localnet ACL 存在
|
||||
if grep -qE '^acl[[:space:]]+localnet' "$SQUID_CONF"; then
|
||||
info "localnet ACL 已存在"
|
||||
else
|
||||
_localnet_def="acl localnet src 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 169.254.0.0/16 fc00::/7 fe80::/10"
|
||||
# 找到第一个 http_access 行之前插入
|
||||
if grep -n '^http_access' "$SQUID_CONF" | head -1 | cut -d: -f1 >/dev/null; then
|
||||
_insert_line=$(grep -n '^http_access' "$SQUID_CONF" | head -1 | cut -d: -f1)
|
||||
sed -i "${_insert_line}i${_localnet_def}" "$SQUID_CONF"
|
||||
else
|
||||
echo "$_localnet_def" >> "$SQUID_CONF"
|
||||
fi
|
||||
info "已添加 localnet ACL 定义"
|
||||
fi
|
||||
|
||||
# 2) 确保 http_access allow localnet 在 deny all 之前
|
||||
if grep -q '^http_access allow localnet' "$SQUID_CONF"; then
|
||||
info "http_access allow localnet 已存在"
|
||||
else
|
||||
if grep -q '^http_access deny all' "$SQUID_CONF"; then
|
||||
sed -i '/^http_access deny all/i http_access allow localnet' "$SQUID_CONF"
|
||||
else
|
||||
echo "http_access allow localnet" >> "$SQUID_CONF"
|
||||
echo "http_access deny all" >> "$SQUID_CONF"
|
||||
fi
|
||||
info "已添加 http_access allow localnet"
|
||||
fi
|
||||
|
||||
# 3) 处理注释掉的老配置
|
||||
if grep -q '^# http_access allow localnet' "$SQUID_CONF"; then
|
||||
sed -i 's/^# http_access allow localnet/http_access allow localnet/' "$SQUID_CONF"
|
||||
fi
|
||||
|
||||
# visible_hostname
|
||||
if ! grep -q '^visible_hostname' "$SQUID_CONF"; then
|
||||
echo "visible_hostname $(hostname -f 2>/dev/null || hostname)" >> "$SQUID_CONF"
|
||||
fi
|
||||
|
||||
# 语法校验
|
||||
if squid -k parse -f "$SQUID_CONF" &>/dev/null; then
|
||||
info "Squid 配置语法校验通过"
|
||||
else
|
||||
warn "Squid 配置语法校验有警告,请检查 squid -k parse 输出"
|
||||
squid -k parse -f "$SQUID_CONF" 2>&1 | tail -10
|
||||
fi
|
||||
|
||||
# 初始化缓存目录 (首次启动需要 squid -z)
|
||||
if [[ ! -d /var/spool/squid/00 ]]; then
|
||||
info "初始化 Squid 缓存目录"
|
||||
squid -z 2>/dev/null || true
|
||||
chown -R proxy:proxy /var/spool/squid 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# 启动 squid 服务
|
||||
if command -v systemctl &>/dev/null; then
|
||||
systemctl enable --now squid 2>/dev/null || {
|
||||
warn "squid 服务启动失败,请手动检查 (systemctl status squid)"
|
||||
}
|
||||
if systemctl is-active --quiet squid; then
|
||||
info "Squid 服务运行正常 ✓"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
warn "未生成 squid.conf,跳过 squid 配置"
|
||||
fi
|
||||
fi
|
||||
|
||||
# ---- 8. 生成 systemd 服务文件 ----------------------------------------------
|
||||
SERVICE_FILE="/etc/systemd/system/${SERVICE_NAME}.service"
|
||||
|
||||
info "生成 systemd 服务文件: $SERVICE_FILE"
|
||||
cat > "$SERVICE_FILE" <<EOF
|
||||
[Unit]
|
||||
Description=Squid Web Manager
|
||||
After=network.target squid.service
|
||||
Wants=squid.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=root
|
||||
Group=root
|
||||
WorkingDirectory=$INSTALL_DIR
|
||||
EnvironmentFile=$INSTALL_DIR/.env
|
||||
ExecStart=$GUNICORN -c gunicorn_config.py wsgi:app
|
||||
ExecReload=/bin/kill -s HUP \$MAINPID
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
TimeoutStopSec=30
|
||||
# 安全加固
|
||||
NoNewPrivileges=yes
|
||||
ProtectSystem=full
|
||||
ProtectHome=true
|
||||
ReadWritePaths=$INSTALL_DIR /etc/squid /var/log/squid /var/spool/squid /run
|
||||
PrivateTmp=yes
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl enable "$SERVICE_NAME"
|
||||
info "systemd 服务已注册并设为开机自启"
|
||||
|
||||
# ---- 9. 启动服务 ------------------------------------------------------------
|
||||
if $START_SERVICE; then
|
||||
info "启动 $SERVICE_NAME 服务"
|
||||
systemctl restart "$SERVICE_NAME"
|
||||
sleep 2
|
||||
|
||||
if systemctl is-active --quiet "$SERVICE_NAME"; then
|
||||
info "$SERVICE_NAME 服务运行正常 ✓"
|
||||
else
|
||||
error "$SERVICE_NAME 服务启动失败!"
|
||||
echo "---------- journalctl 最后 30 行 ----------"
|
||||
journalctl -u "$SERVICE_NAME" --no-pager -n 30
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 健康检查
|
||||
if curl -sf -o /dev/null "http://127.0.0.1:${GUNICORN_PORT}/login"; then
|
||||
info "HTTP 健康检查通过 ✓ (http://127.0.0.1:${GUNICORN_PORT}/login)"
|
||||
else
|
||||
warn "HTTP 健康检查失败,请检查防火墙或端口配置"
|
||||
fi
|
||||
fi
|
||||
|
||||
# ---- 10. 输出汇总 -----------------------------------------------------------
|
||||
echo ""
|
||||
echo "================================================================"
|
||||
echo " Squid Manager 部署完成!"
|
||||
echo "================================================================"
|
||||
echo " Web UI: http://<服务器IP>:${GUNICORN_PORT}"
|
||||
echo " 账号: ${ADMIN_USER} / ${ADMIN_PASS}"
|
||||
echo " 安装目录: ${INSTALL_DIR}"
|
||||
echo " 服务名: ${SERVICE_NAME}"
|
||||
echo " 配置文件: ${INSTALL_DIR}/.env"
|
||||
echo ""
|
||||
echo " 常用命令:"
|
||||
echo " systemctl status $SERVICE_NAME # 查看状态"
|
||||
echo " systemctl restart $SERVICE_NAME # 重启服务"
|
||||
echo " journalctl -u $SERVICE_NAME -f # 实时日志"
|
||||
echo ""
|
||||
echo " ⚠️ 请立即登录后修改默认密码!"
|
||||
echo "================================================================"
|
||||
@@ -0,0 +1,34 @@
|
||||
"""Gunicorn configuration for Squid Manager.
|
||||
|
||||
Usage:
|
||||
gunicorn -c gunicorn_config.py wsgi:app
|
||||
|
||||
All values can be overridden via environment variables:
|
||||
SQUIDMGR_HOST bind address (default: 0.0.0.0)
|
||||
SQUIDMGR_PORT bind port (default: 5200)
|
||||
SQUIDMGR_WORKERS worker count (default: 2)
|
||||
SQUIDMGR_TIMEOUT worker timeout (default: 120)
|
||||
"""
|
||||
import multiprocessing
|
||||
import os
|
||||
|
||||
_host = os.environ.get("SQUIDMGR_HOST", "0.0.0.0")
|
||||
_port = os.environ.get("SQUIDMGR_PORT", "5200")
|
||||
_workers = int(os.environ.get("SQUIDMGR_WORKERS", 2))
|
||||
_timeout = int(os.environ.get("SQUIDMGR_TIMEOUT", 120))
|
||||
|
||||
bind = f"{_host}:{_port}"
|
||||
workers = _workers
|
||||
timeout = _timeout
|
||||
worker_class = "sync"
|
||||
|
||||
# Logging
|
||||
accesslog = "-" # stdout → journald
|
||||
errorlog = "-" # stderr → journald
|
||||
loglevel = "info"
|
||||
|
||||
# Preload app to share memory & fail fast on import errors
|
||||
preload_app = True
|
||||
|
||||
# PID file (for health-check scripts)
|
||||
pidfile = os.path.join(os.path.dirname(os.path.abspath(__file__)), "instance", "gunicorn.pid")
|
||||
+3
-1
@@ -3,6 +3,8 @@ Flask-SQLAlchemy==3.1.1
|
||||
SQLAlchemy==2.0.30
|
||||
Werkzeug==3.0.3
|
||||
gunicorn==22.0.0
|
||||
# P3-3: WebSSH terminal
|
||||
python-dotenv>=1.0.0
|
||||
paramiko>=2.10.0
|
||||
flask-sock>=0.7.0
|
||||
# TLS cert management / ssl_certs module
|
||||
cryptography>=41.0.0
|
||||
|
||||
@@ -7,10 +7,19 @@ Or via systemd unit.
|
||||
"""
|
||||
import os
|
||||
|
||||
# Ensure instance dir exists before app imports (it references the SQLite path)
|
||||
# Ensure runtime dirs exist before app imports (it references SQLite path etc.)
|
||||
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
os.makedirs(os.path.join(BASE_DIR, "instance"), exist_ok=True)
|
||||
os.makedirs(os.path.join(BASE_DIR, "backups"), exist_ok=True)
|
||||
for _d in ("instance", "backups", "uploads", "ssl_certs"):
|
||||
os.makedirs(os.path.join(BASE_DIR, _d), exist_ok=True)
|
||||
|
||||
# Optional: load .env file if python-dotenv is available
|
||||
try:
|
||||
from dotenv import load_dotenv
|
||||
_env_path = os.path.join(BASE_DIR, ".env")
|
||||
if os.path.isfile(_env_path):
|
||||
load_dotenv(_env_path)
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
from app import app, db, seed_admin
|
||||
|
||||
|
||||
Reference in New Issue
Block a user