Production Usage
Frankenstack defaults to local-friendly HTTP (SERVER_NAME=:80) and does not enable production TLS unless you opt in.
Use this guide when you want to run on a real domain with HTTPS.
Option 1: Let’s Encrypt (automatic certificates)
Section titled “Option 1: Let’s Encrypt (automatic certificates)”Use this when your domain points to your server and Cloudflare (if enabled) can reach your origin on ports 80 and 443.
services: app: image: ghcr.io/adiachenko/frankenstack environment: PHP_ENV: production SERVER_NAME: app.example.com CADDY_TLS_MODE: auto CADDY_ACME_EMAIL: ops@example.com ports: - 80:80 - 443:443 volumes: - ./:/opt/project - ./storage/frankenstack/caddy/data:/data - ./storage/frankenstack/caddy/config:/configNotes:
CADDY_TLS_MODE=autoenables Caddy-managed ACME issuance and renewal.- Keep
/datapersisted or certificates/accounts will be lost on container recreation. - Port
80is still required for common ACME HTTP validation flows.
Option 2: Cloudflare Origin Certificate (file-based certificates)
Section titled “Option 2: Cloudflare Origin Certificate (file-based certificates)”Use this when Cloudflare terminates visitor TLS and encrypts traffic to your origin with a Cloudflare Origin CA certificate.
Generate the certificate/key pair (PEM format) in Cloudflare and save both files on the host into
./storage/frankenstack/certsbefore starting the container.
services: app: image: ghcr.io/adiachenko/frankenstack environment: PHP_ENV: production SERVER_NAME: app.example.com CADDY_TLS_MODE: file CADDY_TLS_CERT_FILE: /certs/origin.crt CADDY_TLS_KEY_FILE: /certs/origin.key ports: - 80:80 - 443:443 volumes: - ./:/opt/project - ./storage/frankenstack/certs:/certs:ro - ./storage/frankenstack/caddy/data:/data - ./storage/frankenstack/caddy/config:/configNotes:
- In Cloudflare, set SSL/TLS mode to
Full (strict). - Cert/key files are external inputs in this mode. Frankenstack validates they exist and are readable at startup.
Restrict Origin To Cloudflare Only
Section titled “Restrict Origin To Cloudflare Only”To keep origin access limited to Cloudflare:
- Set Cloudflare SSL/TLS mode to
Full (strict). - At firewall/security-group level, allow inbound
80and443only from Cloudflare IP ranges. - Deny all other source IPs to
80/443.
References:
Optional hardening: add Authenticated Origin Pulls on top of IP allowlisting.
Certificate Storage And Persistence
Section titled “Certificate Storage And Persistence”To avoid multiple root-level folders, keep runtime TLS/Caddy assets under one Laravel-style subtree:
storage/frankenstack/ caddy/ data/ config/ certs/These files are runtime secrets/state and should not be committed. Add this to your app .gitignore:
/storage/frankenstack/- Persist
/datato keep Caddy certificate state across container restarts/recreates. - Persist
/configas recommended for Caddy runtime state. - For
filemode, mount certificate files from host storage as read-only. - A practical Laravel convention is
./storage/frankenstack/...for all three mounts.
Renewal Expectations
Section titled “Renewal Expectations”automode: Caddy renews certificates automatically as long as domain validation can reach the origin.filemode: renewal is external to the container. Rotate files based on your policy, then restart/redeploy the container.
Cloudflare Origin CA supports long validity periods, but you can still rotate more frequently (for example, yearly or every 90 days).
Running Multiple Projects On One Host
Section titled “Running Multiple Projects On One Host”If multiple containers on the same host all map host ports 80:80 and 443:443, only one can start successfully.
Use one of these patterns:
- Single edge proxy (recommended): run one public entrypoint on host
80/443(for example, Caddy/Traefik/Nginx) and route each hostname to app containers on internal/private ports. In this model, TLS is terminated at the edge, so backend app containers should typically useCADDY_TLS_MODE=offand should not bind host80/443. - Cloudflare origin routing: keep DNS records proxied in Cloudflare and use Origin Rules destination-port overrides to route each hostname to a different origin port on the host. In this model, use Cloudflare SSL mode
Full (strict)and configure app containers withCADDY_TLS_MODE=file(Cloudflare Origin CA cert/key mounted into the container).
Cloudflare Origin Rules Recipe (Multiple Projects)
Section titled “Cloudflare Origin Rules Recipe (Multiple Projects)”First make sure that both apps are mapped to different ports on the host.
Then in Cloudflare:
- Ensure both DNS records (
app1.example.com,app2.example.com) are proxied (orange cloud). - Go to Rules -> Overview -> Create rule -> Origin Rule.
- Create one rule per hostname:
- Rule name:
app1-origin-port - Expression:
(http.host == "app1.example.com") - Action: override Destination port to
8443(assuming app1 is mapped to port 8443 on the host) - Rule name:
app2-origin-port - Expression:
(http.host == "app2.example.com") - Action: override Destination port to
9443(assuming app2 is mapped to port 9443 on the host)
- Rule name:
- Deploy rules and keep hostname-specific rules above any broad catch-all rules.
- In firewall rules on your origin host, accept inbound traffic on ports 8443/9443 only when the source IP is in Cloudflare’s IP ranges (see https://www.cloudflare.com/ips-v4 and https://www.cloudflare.com/ips-v6); block all other source IPs on those ports. You can also remove rules for allowing inbound traffic on ports 80/443 since they are not needed anymore.
Bind-Mount Permissions On Native Linux Hosts
Section titled “Bind-Mount Permissions On Native Linux Hosts”See Linux Permissions for ACL setup on native Linux Docker Engine hosts.