Sanitize codebase, reorganize docs, and add missing deploy files

Remove dead code identified in docs/SANITIZATION-REVIEW.md:
- app/blueprints/content_old.py and app/blueprints/playlist.py
- app/models/group.py, app/utils/nginx_config_reader.py
- orphaned templates (content_list, edit_content, upload_content,
  player_page) and the related group/Template references

Result: 6 blueprints, 82 routes, no dead modules or orphan templates.

Add files that deploy.sh and docker-entrypoint.sh already require but
which were never tracked:
- https_manager.py       (referenced by deploy.sh, migrate_network.sh,
                          docker-entrypoint.sh)
- Caddyfile.example      (seeded by deploy.sh; its absence aborts deploy)

Relocate generated Graphify artifacts from graphify-out/ to
docs/graphify-out/ (110 files, no content change) and archive the
superseded docs under docs/.

Ignore hygiene:
- ignore ad-hoc .env backups (.env.bak*) — they contain live secrets
- keep the pre-sanitization snapshots (docs/legacy code/,
  docs/old_code_documentation/) on disk but out of the repo

Fix .env.example: drop a duplicated config block, genericize the
hardcoded host IP, and document HOSTNAME_INTERNAL.
This commit is contained in:
2026-09-11 12:18:34 +03:00
parent 1c5186463a
commit 46602f1933
226 changed files with 3999 additions and 15737 deletions
+197 -62
View File
@@ -16,10 +16,17 @@ echo -e "${BLUE}║ DigiServer Automated Deployment
echo -e "${BLUE}╚════════════════════════════════════════════════════════════════╝${NC}"
echo ""
# Check if docker compose is available
if ! docker compose version &> /dev/null; then
# Check if docker compose is available. Accept either the modern plugin
# (`docker compose`) or the standalone v1 binary (`docker-compose`), since not
# every Docker installation ships the Compose plugin.
if docker compose version &> /dev/null; then
COMPOSE="docker compose"
elif command -v docker-compose &> /dev/null; then
COMPOSE="docker-compose"
echo -e "${YELLOW}⚠️ Using legacy 'docker-compose' (v1); the 'docker compose' plugin is unavailable.${NC}"
else
echo -e "${RED}❌ docker compose not found!${NC}"
echo "Please install docker compose first"
echo "Please install the docker compose plugin or docker-compose first"
exit 1
fi
@@ -31,67 +38,133 @@ if [ ! -f "docker-compose.yml" ]; then
fi
# ============================================================================
# INITIALIZATION: Create data directories and copy nginx configs
# INITIALIZATION: Create data directories and seed the Caddy config
# ============================================================================
echo -e "${YELLOW}📁 Initializing data directories...${NC}"
# Create necessary data directories
mkdir -p data/instance
mkdir -p data/uploads
mkdir -p data/nginx-ssl
mkdir -p data/nginx-logs
mkdir -p data/certbot
mkdir -p data/caddy-data
mkdir -p data/caddy-config
mkdir -p data/caddy-logs
# Copy nginx configuration files from repo root to data folder
if [ -f "nginx.conf" ]; then
cp nginx.conf data/nginx.conf
echo -e " ${GREEN}${NC} nginx.conf copied to data/"
# Seed the Caddyfile. It is bind-mounted as a FILE, so it MUST exist before
# `docker compose up` — otherwise Docker creates a directory in its place and
# Caddy fails to start.
if [ -f "data/Caddyfile" ]; then
echo -e " ${GREEN}${NC} data/Caddyfile present"
elif [ -f "Caddyfile.example" ]; then
cp Caddyfile.example data/Caddyfile
echo -e " ${GREEN}${NC} data/Caddyfile seeded from Caddyfile.example"
else
echo -e " ${RED}nginx.conf not found in repo root!${NC}"
exit 1
fi
if [ -f "nginx-custom-domains.conf" ]; then
cp nginx-custom-domains.conf data/nginx-custom-domains.conf
echo -e " ${GREEN}${NC} nginx-custom-domains.conf copied to data/"
else
echo -e " ${RED}❌ nginx-custom-domains.conf not found in repo root!${NC}"
echo -e " ${RED}Caddyfile.example not found in repo root!${NC}"
exit 1
fi
echo -e "${GREEN}✅ Data directories initialized${NC}"
echo ""
# ============================================================================
# CONFIGURATION VARIABLES
# ============================================================================
HOSTNAME="${HOSTNAME:-digiserver}"
DOMAIN="${DOMAIN:-digiserver.sibiusb.harting.intra}"
IP_ADDRESS="${IP_ADDRESS:-10.76.152.164}"
# NOTE: do NOT use the name HOSTNAME here — it is a bash built-in that already
# holds the machine's hostname (e.g. "development"), so `${HOSTNAME:-default}`
# would silently ignore the default and leak the OS hostname into the Caddyfile.
SERVER_HOSTNAME="${SERVER_HOSTNAME:-digiserver}"
EMAIL="${EMAIL:-admin@example.com}"
PORT="${PORT:-443}"
# Auto-detect the primary LAN IP unless one was supplied explicitly.
if [ -z "${IP_ADDRESS:-}" ]; then
IP_ADDRESS="$(ip -4 route get 1.1.1.1 2>/dev/null | grep -oP 'src \K[\d.]+' | head -1)"
if [ -z "$IP_ADDRESS" ]; then
IP_ADDRESS="$(hostname -I 2>/dev/null | awk '{print $1}')"
fi
fi
if [ -z "$IP_ADDRESS" ]; then
echo -e "${RED}❌ Could not determine the server IP. Set IP_ADDRESS=... and re-run.${NC}"
exit 1
fi
# HTTPS_MODE selects how TLS is provided:
# internal : Caddy's internal CA, IP-only. Needs NO public DNS and NO ACME.
# Correct for an intranet name such as digiserver.sibiusb.harting.intra.
# acme : Let's Encrypt — requires DOMAIN to be publicly resolvable.
# off : plain HTTP only.
HTTPS_MODE="${HTTPS_MODE:-internal}"
case "$HTTPS_MODE" in
internal)
# An empty DOMAIN is what makes CaddyConfigGenerator choose the
# internal-CA path instead of Let's Encrypt.
DOMAIN=""
;;
acme)
if [ -z "${DOMAIN:-}" ]; then
echo -e "${RED}❌ HTTPS_MODE=acme requires DOMAIN to be set.${NC}"
exit 1
fi
;;
off)
DOMAIN=""
;;
*)
echo -e "${RED}❌ Invalid HTTPS_MODE '$HTTPS_MODE' (use internal|acme|off).${NC}"
exit 1
;;
esac
# Published ports. These MUST match docker-compose.yml, which maps Caddy's
# internal 80/443 to these host ports (HTTP_PORT / HTTPS_PORT).
HTTP_PORT="${HTTP_PORT:-80}"
HTTPS_PORT="${HTTPS_PORT:-443}"
echo -e "${BLUE}Configuration:${NC}"
echo " Hostname: $HOSTNAME"
echo " Domain: $DOMAIN"
echo " Hostname: $SERVER_HOSTNAME"
echo " HTTPS mode: $HTTPS_MODE"
echo " Domain: ${DOMAIN:-(none — internal CA)}"
echo " IP Address: $IP_ADDRESS"
echo " Email: $EMAIL"
echo " Port: $PORT"
echo " HTTP port: $HTTP_PORT"
echo " HTTPS port: $HTTPS_PORT"
echo ""
# ============================================================================
# STEP 1: Start containers
# STEP 1: Build and start containers
# ============================================================================
echo -e "${YELLOW}📦 [1/6] Starting containers...${NC}"
docker compose up -d
echo -e "${YELLOW}📦 [1/6] Building and starting containers...${NC}"
# Compose v1 refuses to build unless the buildx plugin is >= 0.17:
# "compose build requires buildx 0.17.0 or later"
# Distro Packaged Docker ships older buildx (or none). Detect that and fall back
# to a plain `docker build` + `up --no-build`, which needs no buildx at all.
APP_IMAGE="digiserver-v2-digiserver-app:latest"
BUILDX_VER="$(docker buildx version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+' | head -1)"
BUILDX_OK=0
if [ -n "$BUILDX_VER" ]; then
_bx_major="${BUILDX_VER%%.*}"
_bx_minor="${BUILDX_VER##*.}"
if [ "$_bx_major" -gt 0 ] || { [ "$_bx_major" -eq 0 ] && [ "$_bx_minor" -ge 17 ]; }; then
BUILDX_OK=1
fi
fi
if [ "$BUILDX_OK" -eq 1 ]; then
echo -e " ${GREEN}${NC} buildx ${BUILDX_VER} — building via compose"
$COMPOSE up -d --build
else
echo -e " ${YELLOW}${NC} buildx ${BUILDX_VER:-not found} (< 0.17) — falling back to 'docker build'"
docker build -t "$APP_IMAGE" .
$COMPOSE up -d --no-build
fi
echo -e "${YELLOW}⏳ Waiting for containers to be healthy...${NC}"
sleep 10
sleep 15
# Verify containers are running
if ! docker compose ps | grep -q "Up"; then
if ! $COMPOSE ps | grep -q "Up"; then
echo -e "${RED}❌ Containers failed to start!${NC}"
docker compose logs
$COMPOSE logs
exit 1
fi
echo -e "${GREEN}✅ Containers started successfully${NC}"
@@ -103,15 +176,15 @@ echo ""
echo -e "${YELLOW}📊 [2/6] Running database migrations...${NC}"
echo -e " • Creating https_config table..."
docker compose exec -T digiserver-app python /app/migrations/add_https_config_table.py
$COMPOSE exec -T digiserver-app python /app/migrations/add_https_config_table.py
echo -e " • Creating player_user table..."
docker compose exec -T digiserver-app python /app/migrations/add_player_user_table.py
$COMPOSE exec -T digiserver-app python /app/migrations/add_player_user_table.py
echo -e " • Adding email to https_config..."
docker compose exec -T digiserver-app python /app/migrations/add_email_to_https_config.py
$COMPOSE exec -T digiserver-app python /app/migrations/add_email_to_https_config.py
echo -e " • Migrating player_user global settings..."
docker compose exec -T digiserver-app python /app/migrations/migrate_player_user_global.py
$COMPOSE exec -T digiserver-app python /app/migrations/migrate_player_user_global.py
echo -e " • Adding original_filename to content..."
docker compose exec -T digiserver-app python /app/migrations/add_original_filename_to_content.py
$COMPOSE exec -T digiserver-app python /app/migrations/add_original_filename_to_content.py
echo -e "${GREEN}✅ All database migrations completed${NC}"
echo ""
@@ -119,16 +192,41 @@ echo ""
# ============================================================================
# STEP 3: Configure HTTPS
# ============================================================================
echo -e "${YELLOW}🔒 [3/6] Configuring HTTPS...${NC}"
echo -e "${YELLOW}🔒 [3/6] Configuring HTTPS (mode: $HTTPS_MODE)...${NC}"
docker compose exec -T digiserver-app python /app/https_manager.py enable \
"$HOSTNAME" \
"$DOMAIN" \
"$EMAIL" \
"$IP_ADDRESS" \
"$PORT"
# https_manager.py mirrors the Admin UI code path: persist HTTPSConfig →
# regenerate the Caddyfile → hot-reload Caddy → verify the TLS listener and
# automatically fall back to HTTP if it does not come up.
#
# `bootstrap` (rather than `enable`) is used deliberately: it records provenance
# via HTTPSConfig.updated_by, so an admin's later change in the UI is not
# silently overwritten on the next restart.
#
# The values computed above are injected with -e so this run uses them instead
# of whatever happens to be in the container's .env.
#
# Exit code 2 means "config applied but Caddy did not reload" — not fatal, so it
# must not abort the deployment.
set +e
if [ "$HTTPS_MODE" = "off" ]; then
$COMPOSE exec -T digiserver-app python /app/https_manager.py disable
else
$COMPOSE exec -T \
-e HOSTNAME_INTERNAL="$SERVER_HOSTNAME" \
-e HOST_IP="$IP_ADDRESS" \
-e DOMAIN="$DOMAIN" \
-e SSL_EMAIL="$EMAIL" \
-e HTTPS_PORT="$HTTPS_PORT" \
digiserver-app python /app/https_manager.py bootstrap
fi
HTTPS_RC=$?
set -e
echo -e "${GREEN}✅ HTTPS configured successfully${NC}"
case "$HTTPS_RC" in
0) echo -e "${GREEN}✅ HTTPS configured${NC}" ;;
2) echo -e "${YELLOW}⚠️ HTTPS config applied but Caddy did not reload — restart the caddy container.${NC}" ;;
*) echo -e "${YELLOW}⚠️ HTTPS not configured (or verification failed and it fell back to HTTP); continuing.${NC}" ;;
esac
echo ""
# ============================================================================
@@ -136,20 +234,21 @@ echo ""
# ============================================================================
echo -e "${YELLOW}🔍 [4/6] Verifying database setup...${NC}"
docker compose exec -T digiserver-app python -c "
$COMPOSE exec -T digiserver-app python -c "
from app.app import create_app
from app.extensions import db
from sqlalchemy import inspect
app = create_app()
with app.app_context():
inspector = inspect(app.extensions.db.engine)
inspector = inspect(db.engine)
tables = inspector.get_table_names()
print(' Database tables:')
for table in sorted(tables):
print(f' ✓ {table}')
print(f'')
print(f' ✅ Total tables: {len(tables)}')
" 2>/dev/null || echo " ⚠️ Database verification skipped"
" || echo " ⚠️ Database verification skipped"
echo ""
# ============================================================================
@@ -157,7 +256,7 @@ echo ""
# ============================================================================
echo -e "${YELLOW}🔧 [5/6] Verifying Caddy configuration...${NC}"
docker compose exec -T caddy caddy validate --config /etc/caddy/Caddyfile >/dev/null 2>&1
$COMPOSE exec -T caddy caddy validate --config /etc/caddy/Caddyfile >/dev/null 2>&1
if [ $? -eq 0 ]; then
echo -e " ${GREEN}✅ Caddy configuration is valid${NC}"
else
@@ -171,7 +270,7 @@ echo ""
echo -e "${YELLOW}📋 [6/6] Displaying configuration summary...${NC}"
echo ""
docker compose exec -T digiserver-app python /app/https_manager.py status
$COMPOSE exec -T digiserver-app python /app/https_manager.py status
echo ""
echo -e "${GREEN}╔════════════════════════════════════════════════════════════════╗${NC}"
@@ -179,21 +278,57 @@ echo -e "${GREEN}║ 🎉 Deployment Complete!
echo -e "${GREEN}╚════════════════════════════════════════════════════════════════╝${NC}"
echo ""
# Build host:port suffixes, omitting the default ports for readability.
_http_url="http://$IP_ADDRESS"
[ "$HTTP_PORT" != "80" ] && _http_url="http://$IP_ADDRESS:$HTTP_PORT"
_https_url="https://$IP_ADDRESS"
[ "$HTTPS_PORT" != "443" ] && _https_url="https://$IP_ADDRESS:$HTTPS_PORT"
echo -e "${BLUE}📍 Access Points:${NC}"
echo " 🔒 https://$HOSTNAME"
echo " 🔒 https://$IP_ADDRESS"
echo " 🔒 https://$DOMAIN"
echo -e " 🌐 ${_http_url} (always available)"
case "$HTTPS_MODE" in
internal)
echo -e " 🔒 ${_https_url} (internal CA — see note below)"
echo -e " 🔒 https://$SERVER_HOSTNAME (needs DNS or an /etc/hosts entry)"
;;
acme)
echo -e " 🔒 https://$DOMAIN"
;;
off)
echo -e " ️ HTTPS disabled (HTTPS_MODE=off)"
;;
esac
echo ""
echo -e "${BLUE}📝 Default Credentials:${NC}"
echo " Username: admin"
echo " Password: admin123 (⚠️ CHANGE IN PRODUCTION)"
if [ "$HTTPS_MODE" = "internal" ]; then
echo -e "${YELLOW}⚠️ Internal CA certificate notice:${NC}"
echo " The TLS certificate is signed by Caddy's LOCAL CA, which is not in any"
echo " client's trust store. Browsers will warn and players will reject it"
echo " unless you either:"
echo " a) install the root CA on each device, or"
echo " b) use the plain HTTP endpoint above (simplest for players)."
echo ""
echo " Export the root CA with:"
echo " $COMPOSE cp caddy:/data/caddy/pki/authorities/local/root.crt ./caddy-root.crt"
echo ""
fi
echo -e "${BLUE}📝 Administrator Account:${NC}"
if [ -f ".deployment-credentials" ]; then
echo " Credentials are in .deployment-credentials (chmod 600)."
else
echo " Username: ${ADMIN_USERNAME:-admin}"
echo " Password: see ADMIN_PASSWORD in .env (or the container's ADMIN_PASSWORD)"
fi
if grep -qs '^ADMIN_PASSWORD=admin123' .env 2>/dev/null; then
echo -e " ${RED}⚠️ ADMIN_PASSWORD is still the default — change it now!${NC}"
fi
echo ""
echo -e "${BLUE}📚 Documentation:${NC}"
echo " • DEPLOYMENT_COMMANDS.md - Detailed docker exec commands"
echo " • HTTPS_CONFIGURATION.md - HTTPS setup details"
echo " • setup_https.sh - Manual configuration script"
echo " • docs/07-deployment.md - Deployment + HTTPS details"
echo " • docs/06-utils-services.md - Caddy / https_manager internals"
echo " • Caddyfile.example - Caddy template (seeded into data/)"
echo ""
echo -e "${YELLOW}Next Steps:${NC}"
@@ -204,5 +339,5 @@ echo "4. Configure your players and content"
echo ""
echo -e "${BLUE}📞 Support:${NC}"
echo "For troubleshooting, see DEPLOYMENT_COMMANDS.md section 7"
echo "For troubleshooting, see docs/07-deployment.md"
echo ""