1. The problem I’m having:
I have Caddy 2.9 with the layer4 module compiled with xcaddy in one docker container and PostgreSQL 17 in another docker container on the same device. I’m trying to reverse proxy traffic coming in through the subdomain data.franzmuenzner.com
to the postgres container. When I expose port 5432 on the postgres container and use it directly, I can get in, but as soon as I try to use Caddy as the reverse proxy, with both containers in a custom docker network, the psql command just freezes and eventually times out.
2. Error messages and/or full log output:
# CADDY DOCKER LOG
Attaching to caddy
caddy | {"level":"info","ts":1741017220.100555,"msg":"using config from file","file":"/etc/caddy/Caddyfile"}
caddy | {"level":"info","ts":1741017220.1018128,"msg":"adapted config to JSON","adapter":"caddyfile"}
caddy | {"level":"warn","ts":1741017220.1018238,"msg":"Caddyfile input is not formatted; run 'caddy fmt --overwrite' to fix inconsistencies","adapter":"caddyfile","file":"/etc/caddy/Caddyfile","line":2}
caddy | {"level":"info","ts":1741017220.102782,"logger":"admin","msg":"admin endpoint started","address":"localhost:2019","enforce_origin":false,"origins":["//localhost:2019","//[::1]:2019","//127.0.0.1:2019"]}
caddy | {"level":"info","ts":1741017220.102902,"logger":"http.auto_https","msg":"server is listening only on the HTTPS port but has no TLS connection policies; adding one to enable TLS","server_name":"srv0","https_port":443}
caddy | {"level":"info","ts":1741017220.1029184,"logger":"http.auto_https","msg":"enabling automatic HTTP->HTTPS redirects","server_name":"srv0"}
caddy | {"level":"info","ts":1741017220.1038644,"logger":"http","msg":"enabling HTTP/3 listener","addr":":443"}
caddy | {"level":"info","ts":1741017220.1041534,"logger":"tls.cache.maintenance","msg":"started background certificate maintenance","cache":"0xc000192080"}
caddy | {"level":"info","ts":1741017220.104218,"logger":"http.log","msg":"server running","name":"srv0","protocols":["h1","h2","h3"]}
caddy | {"level":"warn","ts":1741017220.1043134,"logger":"http","msg":"HTTP/2 skipped because it requires TLS","network":"tcp","addr":":80"}
caddy | {"level":"warn","ts":1741017220.1043332,"logger":"http","msg":"HTTP/3 skipped because it requires TLS","network":"tcp","addr":":80"}
caddy | {"level":"info","ts":1741017220.1043365,"logger":"http.log","msg":"server running","name":"remaining_auto_https_redirects","protocols":["h1","h2","h3"]}
caddy | {"level":"info","ts":1741017220.1043396,"logger":"http","msg":"enabling automatic TLS certificate management","domains":["franzmuenzner.com","data.franzmuenzner.com","www.franzmuenzner.com"]}
caddy | {"level":"info","ts":1741017220.1057901,"msg":"autosaved config (load with --resume flag)","file":"/config/caddy/autosave.json"}
caddy | {"level":"info","ts":1741017220.1058023,"msg":"serving initial configuration"}
caddy | {"level":"info","ts":1741017220.1063685,"logger":"tls","msg":"storage cleaning happened too recently; skipping for now","storage":"FileStorage:/data/caddy","instance":"dd7f0f54-9d67-4f26-b7f6-40131cff6122","try_again":1741103620.1063673,"try_again_in":86399.99999974}
caddy | {"level":"info","ts":1741017220.1064937,"logger":"tls","msg":"finished cleaning storage units"}
# POSTGRES DOCKER LOG
Attaching to postgres
postgres | The files belonging to this database system will be owned by user "postgres".
postgres | This user must also own the server process.
postgres |
postgres | The database cluster will be initialized with locale "en_US.utf8".
postgres | The default database encoding has accordingly been set to "UTF8".
postgres | The default text search configuration will be set to "english".
postgres |
postgres | Data page checksums are disabled.
postgres |
postgres | fixing permissions on existing directory /var/lib/postgresql/data ... ok
postgres | creating subdirectories ... ok
postgres | selecting dynamic shared memory implementation ... posix
postgres | selecting default "max_connections" ... 100
postgres | selecting default "shared_buffers" ... 128MB
postgres | selecting default time zone ... Etc/UTC
postgres | creating configuration files ... ok
postgres | running bootstrap script ... ok
postgres | performing post-bootstrap initialization ... ok
postgres | initdb: warning: enabling "trust" authentication for local connections
postgres | initdb: hint: You can change this by editing pg_hba.conf or using the option -A, or --auth-local and --auth-host, the next time you run initdb.
postgres | syncing data to disk ... ok
postgres |
postgres |
postgres | Success. You can now start the database server using:
postgres |
postgres | pg_ctl -D /var/lib/postgresql/data -l logfile start
postgres |
postgres | waiting for server to start....2025-03-03 15:51:21.289 UTC [49] LOG: starting PostgreSQL 17.4 (Debian 17.4-1.pgdg120+2) on x86_64-pc-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit
postgres | 2025-03-03 15:51:21.289 UTC [49] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
postgres | 2025-03-03 15:51:21.293 UTC [52] LOG: database system was shut down at 2025-03-03 15:51:21 UTC
postgres | 2025-03-03 15:51:21.299 UTC [49] LOG: database system is ready to accept connections
postgres | done
postgres | server started
postgres |
postgres | /usr/local/bin/docker-entrypoint.sh: ignoring /docker-entrypoint-initdb.d/*
postgres |
postgres | waiting for server to shut down....2025-03-03 15:51:21.425 UTC [49] LOG: received fast shutdown request
postgres | 2025-03-03 15:51:21.427 UTC [49] LOG: aborting any active transactions
postgres | 2025-03-03 15:51:21.429 UTC [49] LOG: background worker "logical replication launcher" (PID 55) exited with exit code 1
postgres | 2025-03-03 15:51:21.431 UTC [50] LOG: shutting down
postgres | 2025-03-03 15:51:21.432 UTC [50] LOG: checkpoint starting: shutdown immediate
postgres | 2025-03-03 15:51:21.435 UTC [50] LOG: checkpoint complete: wrote 3 buffers (0.0%); 0 WAL file(s) added, 0 removed, 0 recycled; write=0.001 s, sync=0.001 s, total=0.004 s; sync files=2, longest=0.001 s, average=0.001 s; distance=0 kB, estimate=0 kB; lsn=0/14E4FA0, redo lsn=0/14E4FA0
postgres | 2025-03-03 15:51:21.440 UTC [49] LOG: database system is shut down
postgres | done
postgres | server stopped
postgres |
postgres | PostgreSQL init process complete; ready for start up.
postgres |
postgres | 2025-03-03 15:51:21.552 UTC [1] LOG: starting PostgreSQL 17.4 (Debian 17.4-1.pgdg120+2) on x86_64-pc-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit
postgres | 2025-03-03 15:51:21.552 UTC [1] LOG: listening on IPv4 address "0.0.0.0", port 5432
postgres | 2025-03-03 15:51:21.552 UTC [1] LOG: listening on IPv6 address "::", port 5432
postgres | 2025-03-03 15:51:21.556 UTC [1] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
postgres | 2025-03-03 15:51:21.560 UTC [63] LOG: database system was shut down at 2025-03-03 15:51:21 UTC
postgres | 2025-03-03 15:51:21.566 UTC [1] LOG: database system is ready to accept connections
3. Caddy version:
v2.9.1 h1:OEYiZ7DbCzAWVb6TNEkjRcSCRGHVoZsJinoDR/n9oaY=
3.1 PostgreSQL version:
PostgreSQL 17.4 (Debian 17.4-1.pgdg120+2) on x86_64-pc-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit
4. How I installed and ran Caddy:
a. System environment:
Ubuntu 24.04.2 LTS (GNU/Linux 6.8.0-54-generic x86_64)
b. Command:
psql "postgresql://####:####@data.franzmuenzner.com:5432/postgres?sslmode=require&sslnegotiation=direct"
(credentials censored)
c. Service/unit/compose file:
#POSTGRES COMPOSE FILE
services:
postgres:
image: postgres:17
container_name: postgres
restart: unless-stopped
shm_size: 128mb
environment:
POSTGRES_USER: ####
POSTGRES_PASSWORD: ####
volumes:
- ./data:/var/lib/postgresql/data
expose:
- "5432"
networks:
- proxy
volumes:
postgres:
networks:
proxy:
name: proxy
external: true
# CADDY COMPOSE FILE
services:
caddy:
build: ./build
image: jurifm/caddy
container_name: caddy
restart: unless-stopped
cap_add:
- NET_ADMIN
ports:
- "80:80"
- "443:443"
- "443:443/udp"
- "5432:5432"
volumes:
- $PWD/conf:/etc/caddy
- $PWD/site:/srv
- caddy_data:/data
- caddy_config:/config
networks:
- proxy
volumes:
caddy_data:
caddy_config:
networks:
proxy:
external: true
d. My complete Caddy config:
{
servers {
listener_wrappers {
layer4 {
@postgres tls sni data.franzmuenzner.com
route @postgres {
proxy postgres:5432
}
}
tls
}
}
}
franzmuenzner.com {
root * /srv
file_server
}
www.franzmuenzner.com {
redir "https://franzmuenzner.com/" permanent
}
5. Links to relevant resources:
https://hub.docker.com/_/caddy
https://hub.docker.com/_/postgres