Hey everyone,
First of all, thank you for the great software and excellent documentation. I’m struggling with configuring the reverse proxy correctly and would appreciate some guidance.
1. The problem I’m having:
I’m using Ubuntu 24.04 LTS on DigitalOcean, without Docker. The server stack is: Caddy + FrankenPHP + MySQL.
Each system user has their own account and isolated webspace. To maintain full separation, I run a separate Caddy instance per user, in addition to a single front-facing Caddy instance.
- Front Caddy server (system-wide): handles TLS and forwards requests to backends
- Back Caddy servers (one per user): handle actual site serving
These backends are not publicly exposed and should only be accessible internally.
Example users: foo
, bar
2. Error messages and/or full log output:
Problem 1: REQUEST_SCHEME
is http
instead of https
When visiting https://foo.com
, the value of $_SERVER['REQUEST_SCHEME']
is http
.
I assume this is because the front → back request is unencrypted. I tried setting reverse_proxy https://localhost:9011
, but that broke the site (likely due to missing SSL certs on the backend).
While I know internal traffic doesn’t strictly need encryption, the incorrect scheme causes issues in app logic.
Question:
How can I preserve https
in the backend, or otherwise correctly inform PHP that the original request was HTTPS?
Problem 2: Port conflicts and exposure
Initially, both front and back Caddy servers tried to use ports 80/443, causing conflicts. I resolved this by running back servers on alternate ports (9010
, 9011
, etc.).
Question:
Is this the correct approach?
How can I ensure backends are not accessible via <server_ip>:9010
from the public internet?
3. Caddy version:
v2.10.0 h1:fonubSaQKF1YANl8TXqGcn4IbIRUDdfAkpcsfI/vX5U=
4. How I installed and ran Caddy:
Caddy:
apt update && apt install -y debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' \
| tee /usr/share/keyrings/caddy-stable-archive-keyring.gpg >/dev/null
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' \
| tee /etc/apt/sources.list.d/caddy-stable.list
apt update && apt install -y caddy
FrankenPHP:
curl -fsSL https://frankenphp.dev/install.sh | sh
mv frankenphp /usr/local/bin/
frankenphp --version
a. System environment:
- Caddy: v2.10.0 (
h1:fonubSaQKF1YANl8TXqGcn4IbIRUDdfAkpcsfI/vX5U=
) - FrankenPHP: latest
- System: 2 GB RAM / 1 vCPU / Ubuntu 24.04 LTS
b. Command:
Front server:
systemctl start caddy
Back servers: run with individual systemd
units like:
[Unit]
Description=FrankenPHP instance for foo
After=network.target
[Service]
User=foo
Group=foo
WorkingDirectory=/home/foo
UMask=007
RuntimeDirectory=frankenphp
RuntimeDirectoryMode=0755
ExecStart=/usr/local/bin/frankenphp run --config /home/foo/Caddyfile
Restart=on-failure
LimitNOFILE=1048576
[Install]
WantedBy=multi-user.target
c. Service/unit/compose file:
Not relevant.
d. My complete Caddy config:
Front Caddyfile (/etc/caddy/Caddyfile
):
# User "foo"
foo.com {
reverse_proxy http://localhost:9010
}
# User "bar"
bar.com {
reverse_proxy http://localhost:9020
}
Back Caddyfile for foo
(/home/foo/Caddyfile
):
{
admin off
http_port 9010
https_port 9011
servers {
trusted_proxies static private_ranges
}
}
http://foo.com {
encode zstd br gzip
root * /home/foo/www/foo.com/public
php_server
}
Back Caddyfile for bar
(/home/bar/Caddyfile
):
{
admin off
http_port 9020
https_port 9021
servers {
trusted_proxies static private_ranges
}
}
http://bar.com {
encode zstd br gzip
root * /home/bar/www/bar.com/public
php_server
}
Any insights are greatly appreciated. I’m especially looking for advice on how to:
- Ensure HTTPS is properly reflected in the backend.
- Keep backend ports inaccessible from the public.
Thanks in advance!