Skip to content

Trying to do the same as with Traefik - Caddy doesn't reply to HTTP RequestsΒ #76

@luckylinux

Description

@luckylinux

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 πŸ‘Ž.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions