1. The problem I’m having:
I am trying to set up a web server with Caddy and other apps running in rootless Podman containers. However, I’m having trouble with making sure the source IP address is preserved, and I’m not sure if this is a Podman issue or a Caddy issue since I’m new to all of this.
The simplest way I can think to describe the problem is that when I output
<h1><?php echo $_SERVER['REMOTE_ADDR'] . ", " . $_SERVER['HTTP_X_FORWARDED_FOR']?></h1>
on my PHP app, both of the IP addresses match the container that Caddy is running in. However, based on Caddy’s logs, I think it might be seeing the source IP address.
Because I am new to containers and web servers, I don’t fully understand how all the pieces fit together. I don’t expect people here to help debug Podman, so what might be helpful is to learn a reliable way to understand what Caddy is doing so that I can either debug it or move on to debugging other parts of the setup.
2. Error messages and/or full log output:
Here is the output from curl:
gaufde@MacBook-Pro % curl -vL localhost
* Trying [::1]:80...
* Connected to localhost (::1) port 80
> GET / HTTP/1.1
> Host: localhost
> User-Agent: curl/8.4.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Connection: close
< Location: https://localhost/
< Server: Caddy
< Date: Mon, 02 Sep 2024 17:53:44 GMT
< Content-Length: 0
<
* Closing connection
* Clear auth, redirects to port from 80 to 443
* Issue another request to this URL: 'https://localhost/'
* Trying [::1]:443...
* Connected to localhost (::1) port 443
* ALPN: curl offers h2,http/1.1
* (304) (OUT), TLS handshake, Client hello (1):
* CAfile: /etc/ssl/cert.pem
* CApath: none
* (304) (IN), TLS handshake, Server hello (2):
* (304) (IN), TLS handshake, Unknown (8):
* (304) (IN), TLS handshake, Certificate (11):
* (304) (IN), TLS handshake, CERT verify (15):
* (304) (IN), TLS handshake, Finished (20):
* (304) (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / AEAD-CHACHA20-POLY1305-SHA256
* ALPN: server accepted h2
* Server certificate:
* subject: [NONE]
* start date: Sep 2 17:27:03 2024 GMT
* expire date: Sep 3 05:27:03 2024 GMT
* subjectAltName: host "localhost" matched cert's "localhost"
* issuer: CN=Caddy Local Authority - ECC Intermediate
* SSL certificate verify ok.
* using HTTP/2
* [HTTP/2] [1] OPENED stream for https://localhost/
* [HTTP/2] [1] [:method: GET]
* [HTTP/2] [1] [:scheme: https]
* [HTTP/2] [1] [:authority: localhost]
* [HTTP/2] [1] [:path: /]
* [HTTP/2] [1] [user-agent: curl/8.4.0]
* [HTTP/2] [1] [accept: */*]
> GET / HTTP/2
> Host: localhost
> User-Agent: curl/8.4.0
> Accept: */*
>
< HTTP/2 200
< alt-svc: h3=":443"; ma=2592000
< content-type: text/html; charset=UTF-8
< server: Caddy
< x-powered-by: PHP/8.3.10
< content-length: 35
< date: Mon, 02 Sep 2024 17:53:44 GMT
<
* Connection #1 to host localhost left intact
<h1>192.168.55.5, 192.168.55.5</h1>%
Here are the logs from Caddy:
{"level":"info","ts":1725299930.0155766,"logger":"admin","msg":"admin endpoint started","address":"localhost:2019","enforce_origin":false,"origins":["//localhost:2019","//[::1]:2019","//127.0.0.1:2019"]}
{"level":"info","ts":1725299930.0165663,"logger":"tls.cache.maintenance","msg":"started background certificate maintenance","cache":"0x4000502c80"}
{"level":"info","ts":1725299930.0180442,"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}
{"level":"info","ts":1725299930.0181675,"logger":"http.auto_https","msg":"enabling automatic HTTP->HTTPS redirects","server_name":"srv0"}
{"level":"debug","ts":1725299930.0182993,"logger":"http.auto_https","msg":"adjusted config","tls":{"automation":{"policies":[{"subjects":["localhost"]},{}]}},"http":{"servers":{"remaining_auto_https_redirects":{"listen":[":80"],"routes":[{},{}]},"srv0":{"listen":[":443"],"routes":[{"handle":[{"handler":"subroute","routes":[{"handle":[{"handler":"vars","root":"/usr/share/caddy"}]},{"handle":[{"handler":"static_response","headers":{"Location":["/"]},"status_code":302}],"match":[{"path":["*.txt","*.md","*.mdown","/content/*","/site/*","/kirby/*"]}]},{"handle":[{"handler":"static_response","headers":{"Location":["{http.request.orig_uri.path}/"]},"status_code":308}],"match":[{"file":{"try_files":["{http.request.uri.path}/index.php"]},"not":[{"path":["*/"]}]}]},{"handle":[{"handler":"rewrite","uri":"{http.matchers.file.relative}"}],"match":[{"file":{"split_path":[".php"],"try_files":["{http.request.uri.path}","{http.request.uri.path}/index.php","index.php"]}}]},{"handle":[{"handler":"reverse_proxy","transport":{"protocol":"fastcgi","split_path":[".php"]},"upstreams":[{"dial":"phppod:9000"}]}],"match":[{"path":["*.php"]}]},{"handle":[{"handler":"file_server","hide":[".*","/etc/caddy/Caddyfile"]}]}]}],"terminal":true}],"tls_connection_policies":[{}],"automatic_https":{}}}}}
{"level":"info","ts":1725299930.018634,"logger":"pki.ca.local","msg":"root certificate is already trusted by system","path":"storage:pki/authorities/local/root.crt"}
{"level":"info","ts":1725299930.018916,"logger":"http","msg":"enabling HTTP/3 listener","addr":":443"}
{"level":"debug","ts":1725299930.0192504,"logger":"http","msg":"starting server loop","address":"[::]:443","tls":true,"http3":true}
{"level":"info","ts":1725299930.0193887,"logger":"http.log","msg":"server running","name":"srv0","protocols":["h1","h2","h3"]}
{"level":"debug","ts":1725299930.0195847,"logger":"http","msg":"starting server loop","address":"[::]:80","tls":false,"http3":false}
{"level":"info","ts":1725299930.0197492,"logger":"http.log","msg":"server running","name":"remaining_auto_https_redirects","protocols":["h1","h2","h3"]}
{"level":"info","ts":1725299930.0199049,"logger":"http","msg":"enabling automatic TLS certificate management","domains":["localhost"]}
{"level":"info","ts":1725299930.0203476,"logger":"tls","msg":"storage cleaning happened too recently; skipping for now","storage":"FileStorage:/data/caddy","instance":"1a7f331d-8ef6-423a-97c4-13c2d8cbd1f4","try_again":1725386330.0203469,"try_again_in":86399.999999791}
{"level":"info","ts":1725299930.0206177,"logger":"tls","msg":"finished cleaning storage units"}
{"level":"warn","ts":1725299930.0213974,"logger":"tls","msg":"stapling OCSP","error":"no OCSP stapling for [localhost]: no OCSP server specified in certificate","identifiers":["localhost"]}
{"level":"debug","ts":1725299930.0214927,"logger":"tls.cache","msg":"added certificate to cache","subjects":["localhost"],"expiration":1725341224,"managed":true,"issuer_key":"local","hash":"9b2b592ce145600131b94ec95612a32d001178fb26d2c6f975b7d78b2fc0af54","cache_size":1,"cache_capacity":10000}
{"level":"debug","ts":1725299930.021589,"logger":"events","msg":"event","name":"cached_managed_cert","id":"b31eb8c8-e57a-4ec3-9503-d0851dd6540b","origin":"tls","data":{"sans":["localhost"]}}
{"level":"info","ts":1725299930.0218549,"msg":"autosaved config (load with --resume flag)","file":"/config/caddy/autosave.json"}
{"level":"info","ts":1725299930.022059,"msg":"serving initial configuration"}
{"level":"debug","ts":1725299949.8536317,"logger":"events","msg":"event","name":"tls_get_certificate","id":"fa9e8695-475f-4cd0-a56b-7e68ac531783","origin":"tls","data":{"client_hello":{"CipherSuites":[4867,4866,4865,52393,52392,52394,49200,49196,49192,49188,49172,49162,159,107,57,65413,196,136,129,157,61,53,192,132,49199,49195,49191,49187,49171,49161,158,103,51,190,69,156,60,47,186,65,49169,49159,5,4,49170,49160,22,10,255],"ServerName":"localhost","SupportedCurves":[29,23,24,25],"SupportedPoints":"AA==","SignatureSchemes":[2054,1537,1539,2053,1281,1283,2052,1025,1027,513,515],"SupportedProtos":["h2","http/1.1"],"SupportedVersions":[772,771,770,769],"RemoteAddr":{"IP":"192.168.55.5","Port":47322,"Zone":""},"LocalAddr":{"IP":"192.168.55.5","Port":443,"Zone":""}}}}
{"level":"debug","ts":1725299949.8554409,"logger":"tls.handshake","msg":"choosing certificate","identifier":"localhost","num_choices":1}
{"level":"debug","ts":1725299949.8559809,"logger":"tls.handshake","msg":"default certificate selection results","identifier":"localhost","subjects":["localhost"],"managed":true,"issuer_key":"local","hash":"9b2b592ce145600131b94ec95612a32d001178fb26d2c6f975b7d78b2fc0af54"}
{"level":"debug","ts":1725299949.8565166,"logger":"tls.handshake","msg":"matched certificate in cache","remote_ip":"192.168.55.5","remote_port":"47322","subjects":["localhost"],"managed":true,"expiration":1725341224,"hash":"9b2b592ce145600131b94ec95612a32d001178fb26d2c6f975b7d78b2fc0af54"}
{"level":"debug","ts":1725299949.897513,"logger":"http.handlers.rewrite","msg":"rewrote request","request":{"remote_ip":"192.168.55.5","remote_port":"47322","client_ip":"192.168.55.5","proto":"HTTP/2.0","method":"GET","host":"localhost","uri":"/","headers":{"Accept":["*/*"],"User-Agent":["curl/8.4.0"]},"tls":{"resumed":false,"version":772,"cipher_suite":4867,"proto":"h2","server_name":"localhost"}},"method":"GET","uri":"/index.php"}
{"level":"debug","ts":1725299949.8985724,"logger":"http.handlers.reverse_proxy","msg":"selected upstream","dial":"phppod:9000","total_upstreams":1}
{"level":"debug","ts":1725299949.8993998,"logger":"http.reverse_proxy.transport.fastcgi","msg":"roundtrip","request":{"remote_ip":"192.168.55.5","remote_port":"47322","client_ip":"192.168.55.5","proto":"HTTP/2.0","method":"GET","host":"localhost","uri":"/index.php","headers":{"Accept":["*/*"],"X-Forwarded-For":["192.168.55.5"],"X-Forwarded-Proto":["https"],"X-Forwarded-Host":["localhost"],"User-Agent":["curl/8.4.0"]},"tls":{"resumed":false,"version":772,"cipher_suite":4867,"proto":"h2","server_name":"localhost"}},"env":{"CONTENT_LENGTH":"","PATH_INFO":"","REMOTE_HOST":"192.168.55.5","REQUEST_SCHEME":"https","HTTPS":"on","HTTP_USER_AGENT":"curl/8.4.0","AUTH_TYPE":"","GATEWAY_INTERFACE":"CGI/1.1","REMOTE_ADDR":"192.168.55.5","DOCUMENT_URI":"/index.php","SCRIPT_FILENAME":"/usr/share/caddy/index.php","SSL_CIPHER":"TLS_CHACHA20_POLY1305_SHA256","REMOTE_IDENT":"","QUERY_STRING":"","REQUEST_METHOD":"GET","HTTP_X_FORWARDED_FOR":"192.168.55.5","HTTP_X_FORWARDED_PROTO":"https","SERVER_NAME":"localhost","REQUEST_URI":"/","DOCUMENT_ROOT":"/usr/share/caddy","SCRIPT_NAME":"/index.php","SSL_PROTOCOL":"TLSv1.3","CONTENT_TYPE":"","REMOTE_PORT":"47322","REMOTE_USER":"","SERVER_PROTOCOL":"HTTP/2.0","HTTP_HOST":"localhost","SERVER_PORT":"443","SERVER_SOFTWARE":"Caddy/v2.8.4","HTTP_ACCEPT":"*/*","HTTP_X_FORWARDED_HOST":"localhost"},"dial":"phppod:9000","env":{"SCRIPT_NAME":"/index.php","DOCUMENT_ROOT":"/usr/share/caddy","SSL_PROTOCOL":"TLSv1.3","REMOTE_PORT":"47322","REMOTE_USER":"","SERVER_PROTOCOL":"HTTP/2.0","HTTP_HOST":"localhost","SERVER_PORT":"443","CONTENT_TYPE":"","HTTP_ACCEPT":"*/*","HTTP_X_FORWARDED_HOST":"localhost","SERVER_SOFTWARE":"Caddy/v2.8.4","PATH_INFO":"","REMOTE_HOST":"192.168.55.5","REQUEST_SCHEME":"https","HTTPS":"on","CONTENT_LENGTH":"","GATEWAY_INTERFACE":"CGI/1.1","REMOTE_ADDR":"192.168.55.5","DOCUMENT_URI":"/index.php","SCRIPT_FILENAME":"/usr/share/caddy/index.php","SSL_CIPHER":"TLS_CHACHA20_POLY1305_SHA256","HTTP_USER_AGENT":"curl/8.4.0","AUTH_TYPE":"","QUERY_STRING":"","REQUEST_METHOD":"GET","HTTP_X_FORWARDED_FOR":"192.168.55.5","HTTP_X_FORWARDED_PROTO":"https","REMOTE_IDENT":"","REQUEST_URI":"/","SERVER_NAME":"localhost"},"request":{"remote_ip":"192.168.55.5","remote_port":"47322","client_ip":"192.168.55.5","proto":"HTTP/2.0","method":"GET","host":"localhost","uri":"/index.php","headers":{"X-Forwarded-Host":["localhost"],"User-Agent":["curl/8.4.0"],"Accept":["*/*"],"X-Forwarded-For":["192.168.55.5"],"X-Forwarded-Proto":["https"]},"tls":{"resumed":false,"version":772,"cipher_suite":4867,"proto":"h2","server_name":"localhost"}}}
{"level":"debug","ts":1725299949.9903283,"logger":"http.handlers.reverse_proxy","msg":"upstream roundtrip","upstream":"phppod:9000","duration":0.091183966,"request":{"remote_ip":"192.168.55.5","remote_port":"47322","client_ip":"192.168.55.5","proto":"HTTP/2.0","method":"GET","host":"localhost","uri":"/index.php","headers":{"User-Agent":["curl/8.4.0"],"Accept":["*/*"],"X-Forwarded-For":["192.168.55.5"],"X-Forwarded-Proto":["https"],"X-Forwarded-Host":["localhost"]},"tls":{"resumed":false,"version":772,"cipher_suite":4867,"proto":"h2","server_name":"localhost"}},"headers":{"X-Powered-By":["PHP/8.3.10"],"Content-Type":["text/html; charset=UTF-8"]},"status":200}
3. Caddy version:
gaufde@MacBook-Pro % podman exec web caddy --version
v2.8.4 h1:q3pe0wpBj1OcHFZ3n/1nl4V4bxBrYoSoab7rL9BMYNk=
4. How I installed and ran Caddy:
a. System environment:
I am using Podman which comes with a machine :
gaufde@MacBook-Pro % podman machine info
host:
arch: arm64
currentmachine: podman-machine-default
defaultmachine: podman-machine-default
eventsdir: /var/folders/7m/z_f3vkmd6t30fhydp4z513gw0000gn/T/storage-run-501/podman
machineconfigdir: /Users/gaufde/.config/containers/podman/machine/applehv
machineimagedir: /Users/gaufde/.local/share/containers/podman/machine/applehv
machinestate: Running
numberofmachines: 1
os: darwin
vmtype: applehv
version:
apiversion: 5.2.1
version: 5.2.1
goversion: go1.23.0
gitcommit: d0582c9e1e6c80cc08c3f042b91993c853ddcbc6
builttime: Wed Aug 14 11:10:32 2024
built: 1723659032
osarch: darwin/arm64
os: darwin
b. Command:
podman network create --subnet 192.168.55.0/24 --gateway 192.168.55.3 --subnet fd52:2a5a:747e:3acd::/64 --gateway fd52:2a5a:747e:3acd::10 kirbynetwork
podman pod create \
--name caddypod \
--publish 80:80 \
--publish 443:443 \
--network kirbynetwork
podman run --detach \
--name php \
--pod new:phppod \
--volume "$(pwd)"/starterkit:/usr/share/caddy:z \
--network kirbynetwork \
7553a1b4ba55
podman run --detach \
--volume "$(pwd)"/Caddyfile:/etc/caddy/Caddyfile \
--volume "$(pwd)"/caddy-data:/data \
--name web \
--pod caddypod \
--volumes-from php \
6fe3572f7c4f
c. Service/unit/compose file:
d. My complete Caddy config:
{
debug
log {
output file /data/log.json
}
}
(common) {
php_fastcgi phppod:9000
tls internal
file_server {
hide .*
}
}
(kirby) {
@blocked {
path *.txt *.md *.mdown /content/* /site/* /kirby/*
}
redir @blocked /
}
localhost {
import common
import kirby
root * /usr/share/caddy
}
5. Links to relevant resources:
This person has a very helpful guide to networking with rootless Podman. Based on this info, I believe that the way I have the Podman network set up should work: GitHub - eriksjolund/podman-networking-docs: rootless Podman networking documentation with examples
FYI, the default network mode for rootless Podman is pasta since Podman 5.0. Though, I do have a bit of uncertainty about what using podman network create
does.