diff --git a/.env.example b/.env.example index 50f00a9..9392110 100644 --- a/.env.example +++ b/.env.example @@ -15,6 +15,16 @@ HOST_LAN_IP=192.168.1.10 ENABLE_MDNS=false RCON_PASSWORD=change-me-to-something-random + +# Caddy host-published port (docker-compose.caddy.yml). Default 80 for the +# standalone LAN/air-gap path. When the machine's own nginx fronts caddy +# (nginx terminates TLS → reverse-proxies to caddy), set a high port and bind +# it to localhost so only nginx reaches it: +# CADDY_HTTP_PORT=8880 +# CADDY_HTTP_BIND=127.0.0.1 +# Then render nginx/ulicraft-caddy.conf.tmpl with CADDY_HTTP_PORT. +# CADDY_HTTP_PORT=80 +# CADDY_HTTP_BIND=0.0.0.0 # Only needed if using CurseForge-exclusive mods: # CF_API_KEY=your-curseforge-api-key diff --git a/docker-compose.caddy.yml b/docker-compose.caddy.yml index 63e91ac..0216e6c 100644 --- a/docker-compose.caddy.yml +++ b/docker-compose.caddy.yml @@ -15,8 +15,12 @@ services: image: caddy:alpine container_name: caddy restart: unless-stopped + # Host-published port. Default 80 for the standalone LAN/air-gap path; set + # CADDY_HTTP_PORT to a high localhost-only port when the machine's nginx + # fronts caddy (nginx terminates TLS, reverse-proxies here by Host header — + # see nginx/ulicraft-caddy.conf.tmpl). ports: - - "80:80" + - "${CADDY_HTTP_BIND:-0.0.0.0}:${CADDY_HTTP_PORT:-80}:80" environment: BASE_DOMAIN: ${BASE_DOMAIN} volumes: diff --git a/nginx/ulicraft-caddy.conf.tmpl b/nginx/ulicraft-caddy.conf.tmpl new file mode 100644 index 0000000..06c334a --- /dev/null +++ b/nginx/ulicraft-caddy.conf.tmpl @@ -0,0 +1,98 @@ +# ────────────────────────────────────────────────────────────────── +# Ulicraft host nginx — TLS terminator in FRONT of caddy. +# ────────────────────────────────────────────────────────────────── +# Alternative to ulicraft.conf.tmpl. Instead of nginx serving the static +# files + proxying only drasl, here caddy (the docker container) is the single +# ingress for ALL vhosts and nginx just terminates TLS and reverse-proxies +# everything to caddy by Host header. +# +# Caddy must be published on a localhost port — set in .env: +# CADDY_HTTP_PORT=8880 +# CADDY_HTTP_BIND=127.0.0.1 +# and the stack brought up with the caddy override (NOT the nginx override): +# docker compose -f docker-compose.yml -f docker-compose.caddy.yml \ +# -f docker-compose.static.yml up -d +# +# Render with BOTH vars then install: +# CADDY_HTTP_PORT=8880 BASE_DOMAIN=ulicraft.net APP_DIR=/home/ubuntu/mc/ulicraft-server-v1 \ +# envsubst '$CADDY_HTTP_PORT $BASE_DOMAIN $APP_DIR' \ +# < nginx/ulicraft-caddy.conf.tmpl | sudo tee /etc/nginx/sites-available/ulicraft.conf +# sudo ln -sf /etc/nginx/sites-available/ulicraft.conf /etc/nginx/sites-enabled/ +# sudo nginx -t && sudo systemctl reload nginx +# +# Prereqs: +# - certs issued: tooling/issue-letsencrypt.sh -> $APP_DIR/certs//{cert,key}.pem +# ────────────────────────────────────────────────────────────────── + +upstream ulicraft_caddy { + server 127.0.0.1:${CADDY_HTTP_PORT}; +} + +# HTTP -> HTTPS for every name. +server { + listen 80; + listen [::]:80; + server_name ${BASE_DOMAIN} auth.${BASE_DOMAIN} pack.${BASE_DOMAIN}; + return 301 https://$host$request_uri; +} + +# One TLS server block per name (each has its own LE cert). All proxy to caddy; +# caddy routes by the forwarded Host header (apex -> www, auth -> drasl, +# pack -> packwiz files). +server { + listen 443 ssl; + listen [::]:443 ssl; + http2 on; + server_name ${BASE_DOMAIN}; + + ssl_certificate ${APP_DIR}/certs/${BASE_DOMAIN}/cert.pem; + ssl_certificate_key ${APP_DIR}/certs/${BASE_DOMAIN}/key.pem; + + client_max_body_size 4m; # skin uploads (auth) reuse the same proxy block + + location / { + proxy_pass http://ulicraft_caddy; + 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; + } +} + +server { + listen 443 ssl; + listen [::]:443 ssl; + http2 on; + server_name auth.${BASE_DOMAIN}; + + ssl_certificate ${APP_DIR}/certs/auth.${BASE_DOMAIN}/cert.pem; + ssl_certificate_key ${APP_DIR}/certs/auth.${BASE_DOMAIN}/key.pem; + + client_max_body_size 4m; # skin uploads + + location / { + proxy_pass http://ulicraft_caddy; + 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; + } +} + +server { + listen 443 ssl; + listen [::]:443 ssl; + http2 on; + server_name pack.${BASE_DOMAIN}; + + ssl_certificate ${APP_DIR}/certs/pack.${BASE_DOMAIN}/cert.pem; + ssl_certificate_key ${APP_DIR}/certs/pack.${BASE_DOMAIN}/key.pem; + + location / { + proxy_pass http://ulicraft_caddy; + 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; + } +}