-
Notifications
You must be signed in to change notification settings - Fork 4
Description
I'm trying to do the same Systemd Socket Activation Approach as I did with Traefik, now with Caddy.
I had some learnings with Traefik, mainly that I needed to create one .socket File for each IP Address Type (IPv4 or IPv6) AND for each different Port Number. Actually I would have to duplicate everything for every different IP Address I want to bind to and for every different Port Number I want to expose.
The only Exception (to Duplication) are if the TCP and UDP Port Number are the same and bound to the same Address. Best Example for this is HTTPS3 HTTP2 TCP 443 and HTTPS HTTP3 / QUIC UDP 443 which can both be described together in a single .socket File.
Anyways, these are my Configuration Files.
Maybe Caddy just doesn't support Systemd Socket Activation the same Way that Traefik does π ?
/home/podman/.config/systemd/user/example-http-80-ipv4.socket:
[Socket]
# TCP Connection
ListenStream=192.168.1.254:80
FileDescriptorName=example-http-80-ipv4
Service=example-caddy.service
[Install]
WantedBy=sockets.target
/home/podman/.config/systemd/user/example-http-80-ipv6.socket:
[Socket]
ListenStream=[2a0X:XXXX:XXXX:XXXX:0000:0000:0001:0254]:80
FileDescriptorName=example-http-80-ipv6
Service=example-caddy.service
[Install]
WantedBy=sockets.target
/home/podman/.config/systemd/user/example-https-443-ipv4.socket:
[Socket]
# TCP Connection
ListenStream=192.168.1.254:443
# UDP Connection
ListenDatagram=192.168.1.254:443
FileDescriptorName=example-https-443-ipv4
Service=example-caddy.service
[Install]
WantedBy=sockets.target
/home/podman/.config/systemd/user/example-https-443-ipv6.socket:
[Socket]
# TCP Connection
ListenStream=[2a0X:XXXX:XXXX:XXXX:0000:0000:0001:0254]:443
# UDP Connection
ListenDatagram=[2a0X:XXXX:XXXX:XXXX:0000:0000:0001:0254]:443
FileDescriptorName=example-https-443-ipv6
Service=example-caddy.service
[Install]
WantedBy=sockets.target
example-caddy.network:
[Network]
NetworkName=example-caddy
Options=isolate=true
# Internal=true
example-caddy.container:
# If using within a Pod disable this
[Install]
WantedBy=default.target
[Unit]
Description=Example Caddy
# After=caddy.socket
# Requires=caddy.socket
After=example-http-80-ipv4.socket example-https-443-ipv4.socket example-http-80-ipv6.socket example-https-443-ipv6.socket
[Service]
Restart=always
Sockets=example-http-80-ipv4.socket example-https-443-ipv4.socket example-http-80-ipv6.socket example-https-443-ipv6.socket
[Container]
ContainerName=example-caddy
# If using in a Pod enable this
# Pod=example.pod
# StartWithPod=true
Environment=CADDY_DOCKER_CADDYFILE_PATH=/etc/caddy/Caddyfile
EnvironmentFile=.env.caddy
Image=docker.io/library/caddy:latest
Pull=missing
# Network (Bridge)
# Network=example-caddy
# Network (Socket Activation)
Network=example-caddy.network
# Security Configuration
NoNewPrivileges=true
# Volumes
Volume=./Caddyfile:/etc/caddy/Caddyfile:ro,z
Volume=/home/podman/containers/data/example/caddy:/data/caddy:z
Volume=/home/podman/containers/log/example/caddy:/var/log:z
Volume=/home/podman/containers/config/example/caddy:/config/caddy:z
Volume=/home/podman/containers/certificates/letsencrypt:/certificates:ro,z
# Ports accessible from Remote
# PublishPort=[2a0X:XXXX:XXXX:XXXX:0000:0000:0001:0254]:80:80/tcp
# PublishPort=[2a0X:XXXX:XXXX:XXXX:0000:0000:0001:0254]:443:443/tcp
# PublishPort=[2a0X:XXXX:XXXX:XXXX:0000:0000:0001:0254]:443:443/udp
# PublishPort=192.168.1.254:80:80/tcp
# PublishPort=192.168.1.254:443:443/tcp
# PublishPort=192.168.1.254:443:443/udp
# Do NOT use API for reloading
Exec=/bin/sh -c 'caddy run --config "/etc/caddy/Caddyfile" --adapter "caddyfile"'
Caddyfile:
# Example and Guide
# https://caddyserver.com/docs/caddyfile/options
# General Options
{
# (Optional) Debug Mode
# debug
# Disable Admin API
# admin off
# Systemd Socket Activation
admin unix//run/admin.sock
# TLS Options
# (Optional) Disable Certificates Management (only if SSL/TLS Certificates are managed by certbot or other external Tools)
auto_https disable_certs
}
# localhost {
# reverse_proxy /api/* localhost:9001
# }
# (Optional) Only if SSL/TLS Certificates are managed by certbot or other external Tools and Custom Logging is required
{$APPLICATION_HOSTNAME} {
tls /certificates/{$APPLICATION_CERTIFICATE_DOMAIN}/{$APPLICATION_CERTIFICATE_CERT_FILE:fullchain.pem} /certificates/{$APPLICATION_CERTIFICATE_DOMAIN}/{$APPLICATION_CERTIFICATE_KEY_FILE:privkey.pem}
log {
output file /var/log/{$APPLICATION_HOSTNAME}/http/access.json {
roll_size 100MiB
roll_keep 5000
roll_keep_for 720h
roll_uncompressed
}
format json
}
# Reverse Proxy to example-application (unencrypted)
# reverse_proxy http://example-application:{$APPLICATION_PORT}
# Reverse Proxy to example-application (TLS)
# reverse_proxy https://example-application:{$APPLICATION_PORT} {
reverse_proxy https://example-application.MYDOMAIN.TLD:{$APPLICATION_PORT} {
transport http {
# Use TLS when connecting to Upstream
tls
# Skip upstream TLS Certificate Verification
# tls_insecure_skip_verify
}
}
}
I am able to start up the Container Stack.
However, Caddy isn't getting the Connections "through" Systemd Socket.
Very likely it's a Configuration Error on my Side π. Or, possibly, Caddy just doesn't support this, whereas Traefik does.
How does exactly the Service know how/when to Bind to each Socket Activation ?
With Traefik it seems to be in the Name of the Router, e.g. --entryPoints.example-http-80-ipv4.address=:80 must match the FileDescriptorName=example-http-80-ipv4 in example-http-80-ipv4.socket.
How does Caddy handle this? I couldn't see a clear Explanation in the Example. Maybe it only supports 1 single Socket π€ ?
EDIT 1: I see https://github.com/eriksjolund/podman-caddy-socket-activation?tab=readme-ov-file#support-for-socket-activation-in-caddy ...
I am however confused by this Comment:
Caddy does not make use of file descriptor names that can be retrieved with sd_listen_fds_with_names(). Instead file descriptor numbers are specified. Do not use multiple socket units. Use one socket unit so that the file descriptor numbers can be mapped to the listening sockets that are configured with ListenStream= and ListenDatagram=.
Since with Traefik I couldn't get all Ports & IP Address configured in a single File, Systemd just wouldn't let me π.