Skip to content

Latest commit

 

History

History

README.md

return to main page

Example 4

Example 4 is similar to Example 2 but Example 4 also provides HTTP/3 support.

graph TB

    a1[curl] -.->a2[caddy container reverse proxy]
    a2 -->|"for https://static.example.com"| a3["handled internally by caddy file_server"]
    a2 -->|"for https://whoami.example.com"| a4["whoami container"]
Loading

Set up a systemd user service example4.service for the user test where rootless podman is running the container image docker.io/library/caddy. The caddy container is acting as an HTTP reverse proxy that forwards requests for https://whoami.example.com to a whoami container. Caddy is also configured to be a static file server for requests to https://static.example.com. Configure socket activation for the ports 80/TCP, 443/TCP and 443/UDP. Let Caddy use these ports for the HTTP reverse proxy. A TLS certificate is automatically retrieved with the ACME prototol. Configure socket activation for the unix socket ~/caddy.sock. Let Caddy use this socket for the admin API endpoint.

To allow containers on the custom network mynet to access the caddy proxy, configure caddy to also listen on port 80 on the custom network mynet and add NetworkAlias= for each hosted domain. For details about using NetworkAlias= with an HTTP reverse proxy, see Alternative 1: create extra socket and use NetworkAlias=

  1. Verify that unprivileged users are allowed to open port numbers 80 and above. Run the command
    cat /proc/sys/net/ipv4/ip_unprivileged_port_start
    
    Make sure the number printed is not higher than 80. To configure a new port number (for example 80), create the file /etc/sysctl.d/99-mysettings.conf with the contents:
    net.ipv4.ip_unprivileged_port_start=80
    
    and reload the configuration
    sudo sysctl --system
    
    Note, allowing unprivileged users to listen on ports below 1024 can be a security concern. For example, if another user on your system would start a web server on the same ports, that web server could impersionate as your web server. This security concern can be avoided by running Caddy in a systemd system service instead, thus using rootful Podman instead of rootless Podman. See Example 5 (TODO: create example 5) for how to run a Caddy reverse proxy with rootful Podman in a systemd system service.
  2. Check the IPv4 address of the main network interface. Run the command
    hostname -I
    
    The following output is printed
    192.0.2.5 fd25:c7f8:948a:0:912d:3900:d5c4:45ad
    
    result: The IPv4 address of the main network interface is 192.0.2.5 (the address furthest to the left)
  3. Verify that the domain names nginx.example.com and whoami.example.com resolve to the IP address of the host's main IPv4 interface. Run commands to resolve the hostnames.
    host nginx.example.com
    
    and
    host whoami.example.com
    
    Verify that the results match the left-most IPv4 address detected in the previous step.
  4. Create a test user
    sudo useradd --create-home test
    
  5. Open a shell for user test
    sudo machinectl shell --uid=test
    
  6. Optional step: enable lingering to avoid services from being stopped when the user test logs out.
    loginctl enable-linger test
    
  7. Create directories
    mkdir -p ~/.config/systemd/user
    mkdir -p ~/.config/containers/systemd
    mkdir ~/caddy_etc
    mkdir ~/caddy_static
    
  8. Pull caddy container image
    podman pull docker.io/library/caddy
    
  9. Pull whoami container image
    podman pull docker.io/traefik/whoami
    
  10. Clone git repo
    git clone https://github.com/eriksjolund/podman-caddy-socket-activation.git
    
  11. Install the container unit files
    cp podman-caddy-socket-activation/examples/example4/*.container \
       ~/.config/containers/systemd/
    
  12. Install the network unit file
    cp podman-caddy-socket-activation/examples/example4/mynet.network \
       ~/.config/containers/systemd/
    
  13. Install the socket unit file
    cp podman-caddy-socket-activation/examples/example4/caddy.socket \
       ~/.config/systemd/user/
    
  14. Install volume units
    cp podman-caddy-socket-activation/examples/example4/*.volume \
       ~/.config/containers/systemd/
    
  15. Install the Caddyfile
    cp podman-caddy-socket-activation/examples/example4/Caddyfile \
       ~/caddy_etc/Caddyfile
    
    (The path ~/caddy_etc/Caddyfile was arbitrarily chosen)
  16. Edit ~/Caddyfile so that example.com is replaced with the hostname of your computer.
  17. Create a static files
    echo "my static file" > ~/caddy_static/file.txt
    
  18. Reload the systemd user manager
    systemctl --user daemon-reload
    
  19. Start the whoami container
    systemctl --user start whoami.service
    
  20. Start the caddy socket
    systemctl --user start caddy.socket
    
  21. Download the URL https://whoami.example.com and see that the request is proxied to the container whoami. Resolve whoami.example.com to 127.0.0.1 so that curl connects to localhost.
    curl -s --resolve whoami.example.com:443:127.0.0.1 \
      https://whoami.example.com | grep X-Forwarded-For
    
    The following output is printed
    X-Forwarded-For: 127.0.0.1
    
    result: The IPv4 address 127.0.0.1 matches the IP address of X-Forwarded-For
  22. Download the URL https://whoami.example.com from the caddy container and see that the request is proxied to the container whoami. Resolve whoami.example.com to the IPv4 address of the main network interface. Run the command
    curl -s https://whoami.example.com | grep X-Forwarded-For
    
    The following output is printed
    X-Forwarded-For: 192.0.2.5
    
    result: IPv4 address of X-Forwarded-For matches address of the main network interface
  23. From another computer download the URL https://whoami.example.com from the caddy container and see that the request is proxied to the container whoami.
    curl -s https://whoami.example.com | grep X-Forwarded-For
    
    The following output is printed
    X-Forwarded-For: 192.0.2.18
    
    Check the IP address of the other computer (which in this example runs macOS). In the macOS terminal run the command
    ipconfig getifaddr en0
    
    The following output is printed
    192.0.2.18
    
    result: The IPv4 address of X-Forwarded-For matches the IP address of the other computer.
  24. Download the URL https://static.example.com/file.txt Run the command
    curl https://static.example.com/file.txt
    
    The following output is printed
    my static file
    
  25. Access the admin API endpoint.
    curl -s -H "Host: " --unix-socket $XDG_RUNTIME_DIR/caddy.sock http://localhost/config/ | jq . | head -5
    
    The following output is printed
    {
      "admin": {
        "listen": "fd/6"
      },
      "apps": {
    
  26. Start a curl container on the custom network and download http://whoami.example.com.
    podman run --rm \
               --name curl \
               --network mynet \
                docker.io/library/fedora curl -s http://whoami.example.com \
        | grep X-Forwarded-For
    
    The following output is printed
    X-Forwarded-For: 10.89.0.43
    
    result: Due to the line
    NetworkAlias=whoami.example.com
    
    in the file caddy.container, the connection will be made to the caddy container. Caddy proxies the request to the whoami container. In the request cadd adds X-Forwarded-For with the IPv4 address of the curl container. While the curl container is running, this IP address can be shown with the command
    podman container inspect curl
    
  27. Show caddy access logs from the last minute
    bash podman-caddy-socket-activation/show-caddy-logs-last-minute.bash
    
    The following output is printed
    {
      "remote_ip": "10.89.0.43",
      "remote_port": "44274",
      "client_ip": "10.89.0.43",
      "proto": "HTTP/1.1",
      "method": "GET",
      "host": "whoami.example.com",
      "uri": "/",
      "headers": {
        "Accept": [
      "*/*"
        ],
        "User-Agent": [
      "curl/8.11.1"
        ]
      }
    }
    
  28. Start a curl container on the custom network and download http://whoami.example.com but this time don't connect to the caddy container, instead use the --connect-to option to connect to the whoami container.
    podman run --rm \
               --name curl \
               --network mynet \
                docker.io/library/fedora curl \
               --connect-to whoami.example.com:80:whoami:80 \
     	  -s http://whoami.example.com \
        | grep X-Forwarded-For
    
    result: The curl command succeeds but the X-Forwarded-For was not found in output.

Using Internal=true

In the example caddy fetches a TLS certificate with the ACME protocol.

An alternative to this is to provide the TLS certificate yourself by specifying a path to a cert file and a path to a key file. For details, see https://caddyserver.com/docs/caddyfile/directives/tls

Creating outgoing connections is needed when using the ACME protocol. If you provide the TLS certificate yourself, then the caddy container does not use the ACME protocol. You could then append the line

Internal=true

to mynet.network.

This improves security. For details, see the blog post How to limit container privilege with socket activation

However, Internal=true will also prevent the other containers on the network mynet from connecting to the internet.