eriksjolund / podman-nginx-socket-activation

Demo of how to run socket-activated nginx with Podman
MIT License
27 stars 5 forks source link
container demo nginx podman socket-activation systemd-service

podman-nginx-socket-activation

This demo shows how to run a socket-activated nginx container with Podman. See also the Podman socket activation tutorial.

Overview of the examples

Example Type of service Port Using quadlet rootful/rootless podman Comment
Example 1 systemd user service 8080 yes rootless podman Only unprivileged port numbers can be used
Example 2 systemd system service 80 yes rootful podman
Example 3 systemd system service (with User=test3) 80 no rootless podman Status: experimental
Example 4 systemd system service (with User=test4) 80 no rootless podman Similar to Example 3 but configured to run as an HTTP reverse proxy. Status: experimental.
Example 5 systemd system service (with User=test5) 80 no rootless podman Similar to Example 4 but the containers use --network=none and communicate over a Unix socket. Status: experimental.
Example 6 systemd system service (with User=test6) 80 no rootless podman Similar to Example 5 but the backend web server is started with socket activation in a systemd system service with User=test6. Status: experimental.

Note nginx has no official support for systemd socket activation (feature request: https://trac.nginx.org/nginx/ticket/237). These examples makes use of the fact that "nginx includes an undocumented, internal socket-passing mechanism" quote from https://freedesktop.org/wiki/Software/systemd/DaemonSocketActivation/

Advantages of using rootless Podman with socket activation

Native network performance over the socket-activated socket

Communication over the socket-activated socket does not pass through pasta or slirp4netns so it has the same performance characteristics as the normal network on the host.

See the Podman socket activation tutorial.

Possibility to restrict the network in the container

The option podman run option --network=none enhances security.

--- nginx.service   2022-08-27 10:46:14.586561964 +0200
+++ nginx.service.new   2022-08-27 10:50:35.698301637 +0200
@@ -15,6 +15,7 @@
 TimeoutStopSec=70
 ExecStartPre=/bin/rm -f %t/%n.ctr-id
 ExecStart=/usr/bin/podman run \
+   --network=none \
    --cidfile=%t/%n.ctr-id \
    --cgroups=no-conmon \
    --rm \

See the Podman socket activation tutorial.

See the blog post How to limit container privilege with socket activation

Possibility to restrict the network in the container, Podman and OCI runtime

The systemd configuration RestrictAddressFamilies=AF_UNIX AF_NETLINK enhances security. To try it out, modify the file ~/.config/systemd/user/nginx.service according to

--- nginx.service   2022-08-27 10:46:14.586561964 +0200
+++ nginx.service.new   2022-08-27 10:58:06.625475911 +0200
@@ -7,14 +7,20 @@
 Documentation=man:podman-generate-systemd(1)
 Wants=network-online.target
 After=network-online.target
+Requires=podman-usernamespace.service
+After=podman-usernamespace.service
 RequiresMountsFor=%t/containers

 [Service]
+RestrictAddressFamilies=AF_UNIX AF_NETLINK
+NoNewPrivileges=yes
 Environment=PODMAN_SYSTEMD_UNIT=%n
 Restart=on-failure
 TimeoutStopSec=70
 ExecStartPre=/bin/rm -f %t/%n.ctr-id
 ExecStart=/usr/bin/podman run \
+   --network=none \
+   --pull=never \
    --cidfile=%t/%n.ctr-id \
    --cgroups=no-conmon \
    --rm \

and create the file ~/.config/systemd/user/podman-usernamespace.service with this contents

[Unit]
Description=podman-usernamespace.service

[Service]
Type=oneshot
Restart=on-failure
TimeoutStopSec=70
ExecStart=/usr/bin/podman unshare /bin/true
RemainAfterExit=yes

See the blog post How to restrict network access in Podman with systemd

The source IP address is preserved

The rootlesskit port forwarding backend for slirp4netns does not preserve source IP. This is not a problem when using socket-activated sockets. See Podman GitHub discussion.

Podman installation size can be reduced

The Podman network tools are not needed when using --network=host or --network=none (see GitHub issue comment). In other words, the total amount of executables and libraries that are needed by Podman is reduced when you run the nginx container with socket activation and --network=none.

References

Reference 1:

The github project PhracturedBlue/podman-socket-activated-services contains an example of a customized socket-activated nginx container that watches a directory for Unix sockets that backend applications have created. In case of socket-activated backend application it would have been systemd that created the Unix sockets. The podman run option --network none is used.

Reference 2:

The article "How to create multidomain web applications with Podman and Nginx" https://www.redhat.com/sysadmin/podman-nginx-multidomain-applications describes running nginx as a reverse proxy with rootless podman. In the article rootless podman is given the privilege to listen on port 80 with the command

sudo sysctl net.ipv4.ip_unprivileged_port_start=80

Socket activation is not used in the article.