fix: switch from nginx to Traefik for routing and SSL
Server uses Traefik (traefik-public network) with Cloudflare DNS cert resolver. Nginx not needed. Add Traefik labels to app service, connect to traefik-public + internal networks, remove nginx/certbot. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
24b01bcba3
commit
d34071f9f8
2 changed files with 28 additions and 68 deletions
75
deploy.sh
75
deploy.sh
|
|
@ -11,9 +11,7 @@ PROJECT_DIR="/opt/03-business/Axil"
|
|||
COMPOSE_FILE="$PROJECT_DIR/docker-compose.prod.yml"
|
||||
ENV_FILE="$PROJECT_DIR/.env.production"
|
||||
DEPLOY_CONFIG="$PROJECT_DIR/.deploy-config"
|
||||
NGINX_SITE="axil-accountants"
|
||||
NGINX_CONF="/etc/nginx/sites-available/$NGINX_SITE"
|
||||
NGINX_ENABLED="/etc/nginx/sites-enabled/$NGINX_SITE"
|
||||
# Routing: Traefik (traefik-public network) — no nginx needed
|
||||
|
||||
# ─── Colors ───────────────────────────────────────────────────────────────────
|
||||
GREEN='\033[0;32m'
|
||||
|
|
@ -273,75 +271,20 @@ run_migrations() {
|
|||
}
|
||||
|
||||
# =============================================================================
|
||||
# Phase 6 — Nginx setup (first run only)
|
||||
# Phase 6 — Traefik registration (automatic via Docker labels)
|
||||
# =============================================================================
|
||||
setup_nginx() {
|
||||
header "Phase 6 — Nginx setup"
|
||||
header "Phase 6 — Traefik routing"
|
||||
|
||||
# Load domain from deploy config
|
||||
if [ ! -f "$DEPLOY_CONFIG" ]; then
|
||||
warn "Deploy config not found at $DEPLOY_CONFIG — skipping Nginx setup."
|
||||
return
|
||||
fi
|
||||
# shellcheck disable=SC1090
|
||||
source "$DEPLOY_CONFIG"
|
||||
|
||||
if [ -f "$NGINX_CONF" ]; then
|
||||
log "Nginx config already exists at $NGINX_CONF — skipping creation."
|
||||
else
|
||||
log "Writing Nginx config for ${DOMAIN}..."
|
||||
cat > "$NGINX_CONF" <<NGINX
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name ${DOMAIN} www.${DOMAIN};
|
||||
|
||||
# Allow large file uploads (Payload CMS media)
|
||||
client_max_body_size 50M;
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:3000;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade \$http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host \$host;
|
||||
proxy_set_header X-Real-IP \$remote_addr;
|
||||
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto \$scheme;
|
||||
proxy_cache_bypass \$http_upgrade;
|
||||
proxy_read_timeout 60s;
|
||||
}
|
||||
}
|
||||
NGINX
|
||||
|
||||
# Enable the site
|
||||
ln -sf "$NGINX_CONF" "$NGINX_ENABLED"
|
||||
log "Nginx site enabled."
|
||||
if [ -f "$DEPLOY_CONFIG" ]; then
|
||||
# shellcheck disable=SC1090
|
||||
source "$DEPLOY_CONFIG"
|
||||
fi
|
||||
|
||||
# Start nginx if not running, otherwise reload
|
||||
nginx -t
|
||||
if systemctl is-active --quiet nginx; then
|
||||
systemctl reload nginx
|
||||
else
|
||||
systemctl start nginx
|
||||
fi
|
||||
log "Nginx is running."
|
||||
|
||||
# SSL via Certbot
|
||||
if certbot certificates 2>/dev/null | grep -q "Domains.*${DOMAIN}"; then
|
||||
log "SSL certificate for ${DOMAIN} already exists — skipping Certbot."
|
||||
else
|
||||
log "Obtaining SSL certificate for ${DOMAIN} (and www.${DOMAIN})..."
|
||||
certbot --nginx \
|
||||
-d "${DOMAIN}" \
|
||||
-d "www.${DOMAIN}" \
|
||||
--non-interactive \
|
||||
--agree-tos \
|
||||
-m "${ADMIN_EMAIL}" \
|
||||
--redirect
|
||||
log "SSL certificate obtained. HTTP → HTTPS redirect enabled."
|
||||
fi
|
||||
log "Routing handled by Traefik via Docker labels."
|
||||
log "SSL certificate will be issued automatically via Cloudflare DNS resolver."
|
||||
info "Route: https://${DOMAIN:-axil.ai-impress.com} → axil-app-1:3000"
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
|
|
|
|||
|
|
@ -4,8 +4,17 @@ services:
|
|||
context: .
|
||||
target: runner
|
||||
restart: always
|
||||
ports:
|
||||
- '127.0.0.1:3000:3000'
|
||||
networks:
|
||||
- traefik-public
|
||||
- internal
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.axil.entrypoints=websecure"
|
||||
- "traefik.http.routers.axil.rule=Host(`axil.ai-impress.com`)"
|
||||
- "traefik.http.routers.axil.tls.certresolver=cloudflare"
|
||||
- "traefik.http.routers.axil.middlewares=security-headers@file"
|
||||
- "traefik.http.services.axil.loadbalancer.server.port=3000"
|
||||
- "traefik.docker.network=traefik-public"
|
||||
env_file:
|
||||
- .env.production
|
||||
depends_on:
|
||||
|
|
@ -15,6 +24,8 @@ services:
|
|||
db:
|
||||
image: postgres:17-alpine
|
||||
restart: always
|
||||
networks:
|
||||
- internal
|
||||
environment:
|
||||
POSTGRES_USER: ${DB_USER:-axil}
|
||||
POSTGRES_PASSWORD: ${DB_PASSWORD}
|
||||
|
|
@ -27,5 +38,11 @@ services:
|
|||
timeout: 5s
|
||||
retries: 10
|
||||
|
||||
networks:
|
||||
traefik-public:
|
||||
external: true
|
||||
internal:
|
||||
driver: bridge
|
||||
|
||||
volumes:
|
||||
pgdata:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue