├── LICENSE ├── README.md └── examples ├── example1 ├── README.md ├── default.conf ├── example1.container └── example1.socket ├── example2 ├── README.md ├── example2.container └── example2.socket ├── example3 ├── README.md ├── example3.service └── example3.socket ├── example4 ├── README.md ├── apache.container ├── caddy.container ├── example4-net.network ├── example4.service.in ├── example4.socket ├── install.bash └── nginx-reverse-proxy-conf │ ├── apache-example-com.conf │ ├── caddy-example-com.conf │ └── default.conf ├── example5 ├── Caddyfile ├── README.md ├── caddy.container ├── example5.service.in ├── example5.socket ├── install.bash └── nginx-reverse-proxy-conf │ ├── caddy-example-com.conf │ └── default.conf └── example6 ├── README.md ├── example6-backend.service.in ├── example6-backend.socket.in ├── example6-proxy.service.in ├── example6-proxy.socket ├── install.bash ├── nginx-backend-conf ├── default.conf └── nginx-example-com.conf.in └── nginx-reverse-proxy-conf ├── default.conf └── nginx-example-com.conf /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Erik Sjölund 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # podman-nginx-socket-activation 2 | 3 | This demo shows how to run a socket-activated nginx container with Podman. 4 | See also the [Podman socket activation tutorial](https://github.com/containers/podman/blob/main/docs/tutorials/socket_activation.md). 5 | 6 | Overview of the examples 7 | 8 | | Example | Type of service | Port | Using quadlet | rootful/rootless podman | Comment | 9 | | -- | -- | -- | -- | -- | -- | 10 | | [Example 1](examples/example1) | systemd user service | 8080 | yes | rootless podman | Only unprivileged port numbers can be used | 11 | | [Example 2](examples/example2) | systemd system service | 80 | yes | rootful podman | | 12 | | [Example 3](examples/example3) | systemd system service (with `User=test3`) | 80 | no | rootless podman | Status: experimental | 13 | | [Example 4](examples/example4) | 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. | 14 | | [Example 5](examples/example5) | 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. | 15 | | [Example 6](examples/example6) | 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. | 16 | 17 | > **Note** 18 | > 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/ 19 | 20 | ## Advantages of using rootless Podman with socket activation 21 | 22 | ### Native network performance over the socket-activated socket 23 | 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. 24 | 25 | See the [Podman socket activation tutorial](https://github.com/containers/podman/blob/main/docs/tutorials/socket_activation.md#native-network-performance-over-the-socket-activated-socket). 26 | 27 | ### Possibility to restrict the network in the container 28 | 29 | The option `podman run` option `--network=none` enhances security. 30 | 31 | ``` diff 32 | --- nginx.service 2022-08-27 10:46:14.586561964 +0200 33 | +++ nginx.service.new 2022-08-27 10:50:35.698301637 +0200 34 | @@ -15,6 +15,7 @@ 35 | TimeoutStopSec=70 36 | ExecStartPre=/bin/rm -f %t/%n.ctr-id 37 | ExecStart=/usr/bin/podman run \ 38 | + --network=none \ 39 | --cidfile=%t/%n.ctr-id \ 40 | --cgroups=no-conmon \ 41 | --rm \ 42 | ``` 43 | 44 | See the [Podman socket activation tutorial](https://github.com/containers/podman/blob/main/docs/tutorials/socket_activation.md#disabling-the-network-with---networknone). 45 | 46 | See the blog post [_How to limit container privilege with socket activation_](https://www.redhat.com/sysadmin/socket-activation-podman) 47 | 48 | ### Possibility to restrict the network in the container, Podman and OCI runtime 49 | 50 | The systemd configuration `RestrictAddressFamilies=AF_UNIX AF_NETLINK` enhances security. 51 | To try it out, modify the file _~/.config/systemd/user/nginx.service_ according to 52 | 53 | ``` diff 54 | --- nginx.service 2022-08-27 10:46:14.586561964 +0200 55 | +++ nginx.service.new 2022-08-27 10:58:06.625475911 +0200 56 | @@ -7,14 +7,20 @@ 57 | Documentation=man:podman-generate-systemd(1) 58 | Wants=network-online.target 59 | After=network-online.target 60 | +Requires=podman-usernamespace.service 61 | +After=podman-usernamespace.service 62 | RequiresMountsFor=%t/containers 63 | 64 | [Service] 65 | +RestrictAddressFamilies=AF_UNIX AF_NETLINK 66 | +NoNewPrivileges=yes 67 | Environment=PODMAN_SYSTEMD_UNIT=%n 68 | Restart=on-failure 69 | TimeoutStopSec=70 70 | ExecStartPre=/bin/rm -f %t/%n.ctr-id 71 | ExecStart=/usr/bin/podman run \ 72 | + --network=none \ 73 | + --pull=never \ 74 | --cidfile=%t/%n.ctr-id \ 75 | --cgroups=no-conmon \ 76 | --rm \ 77 | ``` 78 | and create the file _~/.config/systemd/user/podman-usernamespace.service_ with this contents 79 | 80 | ``` 81 | [Unit] 82 | Description=podman-usernamespace.service 83 | 84 | [Service] 85 | Type=oneshot 86 | Restart=on-failure 87 | TimeoutStopSec=70 88 | ExecStart=/usr/bin/podman unshare /bin/true 89 | RemainAfterExit=yes 90 | ``` 91 | 92 | See the blog post [_How to restrict network access in Podman with systemd_](https://www.redhat.com/sysadmin/podman-systemd-limit-access) 93 | 94 | ### The source IP address is preserved 95 | 96 | The rootlesskit port forwarding backend for slirp4netns does not preserve source IP. 97 | This is not a problem when using socket-activated sockets. See Podman GitHub [discussion](https://github.com/containers/podman/discussions/10472). 98 | 99 | ### Podman installation size can be reduced 100 | 101 | The Podman network tools are not needed when using __--network=host__ or __--network=none__ 102 | (see GitHub [issue comment](https://github.com/containers/podman/discussions/16493#discussioncomment-4140832)). 103 | In other words, the total amount of executables and libraries that are needed by Podman is reduced 104 | when you run the nginx container with _socket activation_ and __--network=none__. 105 | 106 | ### References 107 | 108 | __Reference 1:__ 109 | 110 | The github project [PhracturedBlue/podman-socket-activated-services](https://github.com/PhracturedBlue/podman-socket-activated-services) contains an [example](https://github.com/PhracturedBlue/podman-socket-activated-services/tree/main/reverse-proxy) of a 111 | 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 112 | been systemd that created the Unix sockets. The __podman run__ option `--network none` is used. 113 | 114 | __Reference 2:__ 115 | 116 | The article "_How to create multidomain web applications with Podman and Nginx_" https://www.redhat.com/sysadmin/podman-nginx-multidomain-applications 117 | describes running nginx as a reverse proxy with rootless podman. 118 | In the article rootless podman is given the privilege to listen on port 80 with the command 119 | ``` 120 | sudo sysctl net.ipv4.ip_unprivileged_port_start=80 121 | ``` 122 | Socket activation is not used in the article. 123 | -------------------------------------------------------------------------------- /examples/example1/README.md: -------------------------------------------------------------------------------- 1 | return to [main page](../..) 2 | 3 | ## Example 1 4 | 5 | ``` mermaid 6 | graph TB 7 | 8 | a1[curl localhost:8080] -.->a2[nginx container in systemd user service] 9 | 10 | ``` 11 | 12 | Set up a systemd user service _example1.service_ for the user _test_ where rootless podman is running the container image __docker.io/library/nginx__. 13 | Configure _socket activation_ for TCP port 8080. 14 | 15 | 1. Log in to user _test_ 16 | 2. Create directories 17 | ``` 18 | $ mkdir -p $HOME/.config/systemd/user 19 | $ mkdir -p $HOME/.config/containers/systemd 20 | ``` 21 | 3. Create a directory that will be bind-mounted to _/etc/nginx/conf.d_ in the container 22 | ``` 23 | $ mkdir $HOME/nginx_conf_d 24 | ``` 25 | 4. Create the file _$HOME/nginx_conf_d/default.conf_ with the contents 26 | ``` 27 | server { 28 | listen 8080; 29 | server_name localhost; 30 | location / { 31 | root /usr/share/nginx/html; 32 | index index.html index.htm; 33 | } 34 | error_page 500 502 503 504 /50x.html; 35 | location = /50x.html { 36 | root /usr/share/nginx/html; 37 | } 38 | } 39 | ``` 40 | The file contents were created with the command 41 | ``` 42 | podman run --rm docker.io/library/nginx /bin/bash -c 'cat /etc/nginx/conf.d/default.conf | grep -v \# | sed "s/listen\s\+80;/listen 8080;/g" | sed /^[[:space:]]*$/d' > default.conf 43 | ``` 44 | 5. Create the file _$HOME/.config/containers/systemd/example1.container_ with the contents 45 | ``` 46 | [Unit] 47 | Requires=example1.socket 48 | After=example1.socket 49 | 50 | [Container] 51 | Image=docker.io/library/nginx 52 | Environment=NGINX=3; 53 | Volume=%h/nginx_conf_d:/etc/nginx/conf.d:Z 54 | [Install] 55 | WantedBy=default.target 56 | ``` 57 | 6. Optional step for improved security: Edit the file _$HOME/.config/containers/systemd/example1.container_ 58 | and add this line below the line `[Container]` 59 | ``` 60 | Network=none 61 | ``` 62 | For details, see section [_Possibility to restrict the network in the container_](#possibility-to-restrict-the-network-in-the-container) 63 | 7. Create the file _$HOME/.config/systemd/user/example1.socket_ that defines the sockets that the container should use 64 | ``` 65 | [Unit] 66 | Description=Example 1 67 | 68 | [Socket] 69 | ListenStream=0.0.0.0:8080 70 | 71 | [Install] 72 | WantedBy=sockets.target 73 | ``` 74 | 8. Reload the systemd configuration 75 | ``` 76 | $ systemctl --user daemon-reload 77 | ``` 78 | 9. Start the socket 79 | ``` 80 | $ systemctl --user start example1.socket 81 | ``` 82 | 10. Test the web server 83 | ``` 84 | $ curl -s localhost:8080 | head -4 85 | 86 | 87 | 88 | Welcome to nginx! 89 | ``` 90 | 91 | ### Discussion 92 | 93 | The default configuration for _ip_unprivileged_port_start_ was used 94 | 95 | ``` 96 | $ cat /proc/sys/net/ipv4/ip_unprivileged_port_start 97 | 1024 98 | ``` 99 | TCP port 8080 is thus an unprivileged port. 100 | 101 | To use the method described in Example 1 for TCP port 80 instead, you need to 102 | modify the Linux kernel setting _ip_unprivileged_port_start_ to the number 103 | 80 or less. 104 | 105 | Create the file _/etc/sysctl.d/99-unprivileged-port.conf_ with the contents 106 | ``` 107 | net.ipv4.ip_unprivileged_port_start=80 108 | ``` 109 | Reload sysctl configuration 110 | ``` 111 | sudo sysctl --system 112 | ``` 113 | Note that any user on the system could then bind to port 80 if it is unused. 114 | -------------------------------------------------------------------------------- /examples/example1/default.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 8080; 3 | server_name localhost; 4 | location / { 5 | root /usr/share/nginx/html; 6 | index index.html index.htm; 7 | } 8 | error_page 500 502 503 504 /50x.html; 9 | location = /50x.html { 10 | root /usr/share/nginx/html; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /examples/example1/example1.container: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Requires=example1.socket 3 | After=example1.socket 4 | 5 | [Container] 6 | Image=docker.io/library/nginx 7 | Environment=NGINX=3; 8 | Volume=%h/nginx_conf_d:/etc/nginx/conf.d:Z 9 | [Install] 10 | WantedBy=default.target 11 | -------------------------------------------------------------------------------- /examples/example1/example1.socket: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Example 1 3 | 4 | [Socket] 5 | ListenStream=0.0.0.0:8080 6 | 7 | [Install] 8 | WantedBy=sockets.target 9 | -------------------------------------------------------------------------------- /examples/example2/README.md: -------------------------------------------------------------------------------- 1 | return to [main page](../..) 2 | 3 | ## Example 2 4 | 5 | ``` mermaid 6 | graph TB 7 | 8 | a1[curl localhost:80] -.->a2[nginx container in systemd system service] 9 | 10 | ``` 11 | 12 | Set up a systemd system service _example2.service_ where rootful podman is running the container image __docker.io/library/nginx__. 13 | Configure _socket activation_ for TCP port 80. 14 | 15 | The instructions are similar to Example 1. 16 | 17 | 1. Create the file _/etc/containers/systemd/example2.container_ with the contents 18 | ``` 19 | [Unit] 20 | Requires=example2.socket 21 | After=example2.socket 22 | 23 | [Container] 24 | Image=docker.io/library/nginx 25 | Environment=NGINX=3; 26 | [Install] 27 | WantedBy=default.target 28 | ``` 29 | 2. Optional step for improved security: Edit the file _/etc/containers/systemd/example2.container_ 30 | and add this line below the line `[Container]` 31 | ``` 32 | Network=none 33 | ``` 34 | For details, see section [_Possibility to restrict the network in the container_](#possibility-to-restrict-the-network-in-the-container) 35 | 3. Create the file _/etc/systemd/system/example2.socket_ that defines the sockets that the container should use 36 | ``` 37 | [Unit] 38 | Description=Example 2 39 | 40 | [Socket] 41 | ListenStream=0.0.0.0:80 42 | 43 | [Install] 44 | WantedBy=sockets.target 45 | ``` 46 | 4. Reload the systemd configuration 47 | ``` 48 | $ sudo systemctl daemon-reload 49 | ``` 50 | 5. Start the socket 51 | ``` 52 | $ sudo systemctl start example2.socket 53 | ``` 54 | 6. Test the web server 55 | ``` 56 | $ curl -s localhost:80 | head -4 57 | 58 | 59 | 60 | Welcome to nginx! 61 | ``` 62 | -------------------------------------------------------------------------------- /examples/example2/example2.container: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Requires=example2.socket 3 | After=example2.socket 4 | 5 | [Container] 6 | Image=docker.io/library/nginx 7 | Environment=NGINX=3; 8 | [Install] 9 | WantedBy=default.target 10 | -------------------------------------------------------------------------------- /examples/example2/example2.socket: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Example 2 3 | 4 | [Socket] 5 | ListenStream=0.0.0.0:80 6 | 7 | [Install] 8 | WantedBy=sockets.target 9 | -------------------------------------------------------------------------------- /examples/example3/README.md: -------------------------------------------------------------------------------- 1 | return to [main page](../..) 2 | 3 | ## Example 3 4 | 5 | status: experimental 6 | 7 | ``` mermaid 8 | graph TB 9 | 10 | a1[curl localhost:80] -.->a2[nginx container in systemd system service with directive User=] 11 | ``` 12 | 13 | Set up a systemd system service _example3.service_ that is configured to run as the user _test3_ (systemd configuration `User=test3`) 14 | where rootless podman is running the container image __docker.io/library/nginx__. 15 | Configure _socket activation_ for TCP port 80. 16 | 17 | The default configuration for _ip_unprivileged_port_start_ can be used 18 | 19 | ``` 20 | $ cat /proc/sys/net/ipv4/ip_unprivileged_port_start 21 | 1024 22 | ``` 23 | 24 | Unprivileged users can only listen on TCP port 1024 and above. 25 | 26 | The reason the unprivileged user _test3_ is able to run a socket-activated nginx container on port 80 is that 27 | the syscalls `socket()` and `bind()` were run by the systemd system manager (`systemd`) which is running as root. 28 | The socket file descriptor is then inherited by the rootless podman process. 29 | 30 | Side note: There is a [Podman feature request](https://github.com/containers/podman/discussions/20573) 31 | for adding Podman support for `User=` in systemd system services. 32 | The feature request was moved into a GitHub discussion. 33 | 34 | ## Requirements 35 | 36 | These instructions were tested on Fedora 39 with Podman 4.7.2. 37 | 38 | ## Install instructions 39 | 40 | 1. Create the user _test3_ 41 | ``` 42 | $ sudo useradd test3 43 | ``` 44 | 2. Check the UID of the user _test3_ 45 | ``` 46 | $ id -u test3 47 | 1000 48 | ``` 49 | 3. Create the file _/etc/systemd/system/example3.service_ with the contents 50 | ``` 51 | [Unit] 52 | Wants=network-online.target 53 | After=network-online.target 54 | Requires=user@1000.service 55 | After=user@1000.service 56 | RequiresMountsFor=/run/user/1000/containers 57 | 58 | [Service] 59 | User=test3 60 | Environment=PODMAN_SYSTEMD_UNIT=%n 61 | KillMode=mixed 62 | ExecStop=/usr/bin/podman rm -f -i --cidfile=/run/user/1000/%N.cid 63 | ExecStopPost=-/usr/bin/podman rm -f -i --cidfile=/run/user/1000/%N.cid 64 | Delegate=yes 65 | Type=notify 66 | NotifyAccess=all 67 | SyslogIdentifier=%N 68 | ExecStart=/usr/bin/podman run \ 69 | --cidfile=/run/user/1000/%N.cid \ 70 | --cgroups=split \ 71 | --rm \ 72 | --env "NGINX=3;" \ 73 | -d \ 74 | --replace \ 75 | --name systemd-%N \ 76 | --sdnotify=conmon \ 77 | docker.io/library/nginx 78 | ``` 79 | 4. Edit the file _/etc/systemd/system/example3.service_ and replace `1000` with the UID found in step 2. 80 | 5. Optional step for improved security: Edit the file _/etc/systemd/system/example3.service_ 81 | and add the option `--network none` to the `podman run` command. 82 | For details, see section [_Possibility to restrict the network in the container_](#possibility-to-restrict-the-network-in-the-container) 83 | 6. Create the file _/etc/systemd/system/example3.socket_ with the contents 84 | ``` 85 | [Unit] 86 | Description=Example 3 socket 87 | 88 | [Socket] 89 | ListenStream=0.0.0.0:80 90 | 91 | [Install] 92 | WantedBy=sockets.target 93 | ``` 94 | 7. Reload the systemd configuration 95 | ``` 96 | $ sudo systemctl daemon-reload 97 | ``` 98 | 8. Start the socket 99 | ``` 100 | $ sudo systemctl start example3.socket 101 | ``` 102 | 103 | ## Test the nginx web server 104 | 105 | 1. Test the web server 106 | ``` 107 | $ curl -s localhost:80 | head -4 108 | 109 | 110 | 111 | Welcome to nginx! 112 | ``` 113 | -------------------------------------------------------------------------------- /examples/example3/example3.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Wants=network-online.target 3 | After=network-online.target 4 | Requires=user@1000.service 5 | After=user@1000.service 6 | RequiresMountsFor=/run/user/1000/containers 7 | 8 | [Service] 9 | User=test 10 | Environment=PODMAN_SYSTEMD_UNIT=%n 11 | KillMode=mixed 12 | ExecStop=/usr/bin/podman rm -f -i --cidfile=/run/user/1000/%N.cid 13 | ExecStopPost=-/usr/bin/podman rm -f -i --cidfile=/run/user/1000/%N.cid 14 | Delegate=yes 15 | Type=notify 16 | NotifyAccess=all 17 | SyslogIdentifier=%N 18 | ExecStart=/usr/bin/podman run \ 19 | --cidfile=/run/user/1000/%N.cid \ 20 | --cgroups=split \ 21 | --rm \ 22 | --env "NGINX=3;" \ 23 | -d \ 24 | --replace \ 25 | --name systemd-%N \ 26 | --sdnotify=conmon \ 27 | docker.io/library/nginx 28 | -------------------------------------------------------------------------------- /examples/example3/example3.socket: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Example 3 socket 3 | 4 | [Socket] 5 | ListenStream=0.0.0.0:80 6 | 7 | [Install] 8 | WantedBy=sockets.target 9 | -------------------------------------------------------------------------------- /examples/example4/README.md: -------------------------------------------------------------------------------- 1 | return to [main page](../..) 2 | 3 | # Example 4 4 | 5 | status: experimental 6 | 7 | ``` mermaid 8 | graph TB 9 | 10 | a1[curl] -.->a2[nginx container reverse proxy] 11 | a2 -->|"for http://apache.example.com"| a3["apache httpd container"] 12 | a2 -->|"for http://caddy.example.com"| a4["caddy container"] 13 | ``` 14 | 15 | Containers: 16 | 17 | | Container image | Type of service | Role | Network | Socket activation | 18 | | -- | -- | -- | -- | -- | 19 | | docker.io/library/nginx | systemd system service with `User=test4` | HTTP reverse proxy | [internal bridge network](example4-net.network) | :heavy_check_mark: | 20 | | docker.io/library/httpd | systemd user service | backend web server | [internal bridge network](example4-net.network) | | 21 | | docker.io/library/caddy | systemd user service | backend web server | [internal bridge network](example4-net.network) | | 22 | 23 | This example is similar to [Example 3](../example3) but here the nginx container is configured 24 | as an HTTP reverse proxy for two backend web server containers (apache httpd and caddy). 25 | All containers are run by rootless podman, which belongs to the user _test4_. 26 | The containers communicate over an internal bridge network that does not have internet access. 27 | 28 | ## Requirements 29 | 30 | These instructions were tested on Fedora 39 with Podman 4.7.2. 31 | 32 | ## Install instructions 33 | 34 | These install instructions will create the new user _test4_ and install these files: 35 | 36 | ``` 37 | /etc/systemd/system/example4.socket 38 | /etc/systemd/system/example4.service 39 | /home/test4/.config/containers/systemd/caddy.container 40 | /home/test4/.config/containers/systemd/apache.container 41 | /home/test4/.config/containers/systemd/example4-net.network 42 | /home/test4/nginx-reverse-proxy-conf/apache-example-com.conf 43 | /home/test4/nginx-reverse-proxy-conf/caddy-example-com.conf 44 | /home/test4/nginx-reverse-proxy-conf/default.conf 45 | ``` 46 | 47 | and start _caddy.service_, _apache.service_ and _example4.socket_. 48 | 49 | 1. Clone this GitHub repo 50 | ``` 51 | $ git clone URL 52 | ``` 53 | 2. Change directory 54 | ``` 55 | $ cd podman-nginx-socket-activation 56 | ``` 57 | 3. Choose a username that will be created and used for the test 58 | ``` 59 | $ user=test4 60 | ``` 61 | 4. Run install script 62 | ``` 63 | $ sudo bash ./examples/example4/install.bash ./ $user 64 | ``` 65 | 5. Check the status of the backend containers 66 | ``` 67 | $ sudo systemctl --user -M ${user}@ is-active apache.service 68 | active 69 | $ sudo systemctl --user -M ${user}@ is-active caddy.service 70 | active 71 | ``` 72 | 6. Check the status of the HTTP reverse proxy socket 73 | ``` 74 | $ sudo systemctl is-active example4.socket 75 | active 76 | ``` 77 | 78 | ## Test the nginx reverse proxy 79 | 80 | 1. Test the nginx HTTP reverse proxy 81 | ``` 82 | $ curl -s --resolve apache.example.com:80:127.0.0.1 apache.example.com:80 83 |

It works!

84 | ``` 85 | Result: Success. The nginx reverse proxy fetched the output from the apache httpd container. 86 | ``` 87 | $ curl -s --resolve caddy.example.com:80:127.0.0.1 caddy.example.com:80 | head -4 88 | 89 | 90 | 91 | Caddy works! 92 | ``` 93 | Result: Success. The nginx reverse proxy fetched the output from the caddy container. 94 | 95 | ## Discussion about service dependencies 96 | 97 | systemd does not support having dependencies between _systemd system services_ and _systemd user services_. 98 | Because of that we need to make sure that _example4.service_ is started after 99 | 100 | * podman has created the network _systemd-example4-net_ 101 | * podman has started _apache-container_ (_apache.service_) and _caddy-container_ (_caddy.service_) 102 | 103 | A possible future modification to Example 4 could be to also run the backend web servers inside _systemd system services_ with `User=`. 104 | Then it would be possible to configure dependencies between the services by adding `After=`, `Depends=`, `Requires=` directives. 105 | -------------------------------------------------------------------------------- /examples/example4/apache.container: -------------------------------------------------------------------------------- 1 | [Container] 2 | Image=docker.io/library/httpd 3 | Network=example4-net.network 4 | ContainerName=apache-container 5 | [Install] 6 | WantedBy=default.target 7 | -------------------------------------------------------------------------------- /examples/example4/caddy.container: -------------------------------------------------------------------------------- 1 | [Container] 2 | Image=docker.io/library/caddy 3 | Network=example4-net.network 4 | ContainerName=caddy-container 5 | [Install] 6 | WantedBy=default.target 7 | -------------------------------------------------------------------------------- /examples/example4/example4-net.network: -------------------------------------------------------------------------------- 1 | [Network] 2 | # To give the containers access to the internet, remove the line `Internal=true` 3 | Internal=true 4 | -------------------------------------------------------------------------------- /examples/example4/example4.service.in: -------------------------------------------------------------------------------- 1 | # This file should be preprocessed with the envsubst command 2 | # to convert such text strings: ${envsubst_variablename} 3 | 4 | [Unit] 5 | Wants=network-online.target 6 | After=network-online.target 7 | Requires=user@${envsubst_uid}.service 8 | After=user@${envsubst_uid}.service 9 | RequiresMountsFor=/run/user/${envsubst_uid}/containers 10 | 11 | [Service] 12 | User=${envsubst_user} 13 | Environment=PODMAN_SYSTEMD_UNIT=%n 14 | KillMode=mixed 15 | ExecStop=/usr/bin/podman rm -f -i --cidfile=/run/user/${envsubst_uid}/%N.cid 16 | ExecStopPost=-/usr/bin/podman rm -f -i --cidfile=/run/user/${envsubst_uid}/%N.cid 17 | Delegate=yes 18 | Type=notify 19 | NotifyAccess=all 20 | SyslogIdentifier=%N 21 | ExecStart=/usr/bin/podman run \ 22 | --cidfile=/run/user/${envsubst_uid}/%N.cid \ 23 | --cgroups=split \ 24 | --rm \ 25 | --env "NGINX=3;" \ 26 | -d \ 27 | --network systemd-example4-net \ 28 | --replace \ 29 | --name systemd-%N \ 30 | --sdnotify=conmon \ 31 | --volume /home/${envsubst_user}/nginx-reverse-proxy-conf:/etc/nginx/conf.d:Z \ 32 | docker.io/library/nginx 33 | -------------------------------------------------------------------------------- /examples/example4/example4.socket: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Example 4 socket 3 | 4 | [Socket] 5 | ListenStream=0.0.0.0:80 6 | 7 | [Install] 8 | WantedBy=sockets.target 9 | -------------------------------------------------------------------------------- /examples/example4/install.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | 6 | repodir=$1 7 | user=$2 8 | 9 | # Alternatively a system account with no shell access could be created: 10 | # sudo useradd --system --shell /usr/sbin/nologin --create-home --add-subids-for-system -d "/home/$user" -- "$user" 11 | sudo useradd -- "$user" 12 | 13 | uid=$(id -u -- "$user") 14 | sourcedir="$repodir/examples/example4" 15 | 16 | sudo install --mode 0755 -Z -d -o "$user" -g "$user" "/home/$user/nginx-reverse-proxy-conf" 17 | sudo install --mode 0644 -Z -D -o "$user" -g "$user" --target-directory "/home/$user/nginx-reverse-proxy-conf" "$sourcedir/nginx-reverse-proxy-conf/apache-example-com.conf" 18 | sudo install --mode 0644 -Z -D -o "$user" -g "$user" --target-directory "/home/$user/nginx-reverse-proxy-conf" "$sourcedir/nginx-reverse-proxy-conf/caddy-example-com.conf" 19 | sudo install --mode 0644 -Z -D -o "$user" -g "$user" --target-directory "/home/$user/nginx-reverse-proxy-conf" "$sourcedir/nginx-reverse-proxy-conf/default.conf" 20 | 21 | sudo install --mode 0755 -Z -d -o "$user" -g "$user" "/home/$user/.config/containers/systemd" 22 | sudo install --mode 0644 -Z -D -o "$user" -g "$user" --target-directory "/home/$user/.config/containers/systemd" "$sourcedir/apache.container" 23 | sudo install --mode 0644 -Z -D -o "$user" -g "$user" --target-directory "/home/$user/.config/containers/systemd" "$sourcedir/caddy.container" 24 | sudo install --mode 0644 -Z -D -o "$user" -g "$user" --target-directory "/home/$user/.config/containers/systemd" "$sourcedir/example4-net.network" 25 | sudo install --mode 0644 -Z -D -o root -g root --target-directory /etc/systemd/system/ "$sourcedir/example4.socket" 26 | 27 | # envsubst is used for text replacement in example4.service 28 | cat $repodir/examples/example4/example4.service.in | sudo bash -c "cat - | envsubst_user=$user envsubst_uid=$uid envsubst > /etc/systemd/system/example4.service" 29 | 30 | sudo loginctl enable-linger "$user" 31 | 32 | sudo systemctl daemon-reload 33 | sudo systemctl --user -M "$user@" daemon-reload 34 | sudo systemctl --user -M "$user@" start apache.service 35 | sudo systemctl --user -M "$user@" start caddy.service 36 | sudo systemctl start example4.socket 37 | -------------------------------------------------------------------------------- /examples/example4/nginx-reverse-proxy-conf/apache-example-com.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | server_name apache.example.com; 4 | location / { 5 | proxy_pass http://apache-container:80; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /examples/example4/nginx-reverse-proxy-conf/caddy-example-com.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | server_name caddy.example.com; 4 | location / { 5 | proxy_pass http://caddy-container:80; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /examples/example4/nginx-reverse-proxy-conf/default.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | server_name localhost; 4 | location / { 5 | root /usr/share/nginx/html; 6 | index index.html index.htm; 7 | } 8 | error_page 500 502 503 504 /50x.html; 9 | location = /50x.html { 10 | root /usr/share/nginx/html; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /examples/example5/Caddyfile: -------------------------------------------------------------------------------- 1 | http:// { 2 | bind unix//var/socketdir/socket 3 | root * /usr/share/caddy 4 | file_server 5 | } 6 | -------------------------------------------------------------------------------- /examples/example5/README.md: -------------------------------------------------------------------------------- 1 | 2 | return to [main page](../..) 3 | 4 | # Example 5 5 | 6 | status: experimental 7 | 8 | ``` mermaid 9 | graph TB 10 | 11 | a1[curl] -.->a2[nginx container reverse proxy] 12 | a2 -->|"for http://caddy.example.com"| a4["caddy container"] 13 | ``` 14 | 15 | Containers: 16 | 17 | | Container image | Type of service | Role | Network | Socket activation | 18 | | -- | -- | -- | -- | -- | 19 | | docker.io/library/nginx | systemd system service with `User=test5` | HTTP reverse proxy | `--network=none` | :heavy_check_mark: | 20 | | docker.io/library/caddy | systemd user service | backend web server | `--network=none` | | 21 | 22 | This example is similar to [Example 4](../example4) but here the containers are configured 23 | to use `--network=none`. The containers communicate over a Unix socket instead of using 24 | an internal bridge network. The containers do not have permissions to connect to the internet. 25 | This is improves security. In case an intruder would compromise any of these containers, 26 | the intruder would not be able to use the compromised container to attack other computers 27 | on the internet if we ignore the possibility of local kernel exploits. 28 | 29 | All containers are run by rootless podman, which belongs to the user _test5_. 30 | 31 | ## Requirements 32 | 33 | These instructions were tested on Fedora 39 with Podman 4.7.2. 34 | 35 | ## Install instructions 36 | 37 | These install instructions will create the new user _test5_ and install these files: 38 | 39 | ``` 40 | /etc/systemd/system/example5.socket 41 | /etc/systemd/system/example5.service 42 | /home/test5/.config/containers/systemd/caddy.container 43 | /home/test5/nginx-reverse-proxy-conf/caddy-example-com.conf 44 | /home/test5/nginx-reverse-proxy-conf/default.conf 45 | /home/test5/Caddyfile 46 | ``` 47 | 48 | and start _caddy.service_ and _example5.socket_. 49 | 50 | 1. Clone this GitHub repo 51 | ``` 52 | $ git clone URL 53 | ``` 54 | 2. Change directory 55 | ``` 56 | $ cd podman-nginx-socket-activation 57 | ``` 58 | 3. Choose a username that will be created and used for the test 59 | ``` 60 | $ user=test5 61 | ``` 62 | 4. Run install script 63 | ``` 64 | $ sudo bash ./examples/example5/install.bash ./ $user 65 | ``` 66 | 5. Check the status of the backend container 67 | ``` 68 | $ sudo systemctl --user -M ${user}@ is-active caddy.service 69 | active 70 | ``` 71 | 6. Check the status of the HTTP reverse proxy socket 72 | ``` 73 | $ sudo systemctl is-active example5.socket 74 | active 75 | ``` 76 | 77 | ## Test the nginx reverse proxy 78 | 79 | 1. Test the nginx HTTP reverse proxy 80 | ``` 81 | $ curl -s --resolve caddy.example.com:80:127.0.0.1 caddy.example.com:80 | head -4 82 | 83 | 84 | 85 | Caddy works! 86 | ``` 87 | Result: Success. The nginx reverse proxy fetched the output from the caddy container. 88 | 89 | ## Discussion about service dependencies 90 | 91 | systemd does not support having dependencies between _systemd system services_ and _systemd user services_. 92 | Because of that we need to make sure that _example5.service_ is started after 93 | 94 | * podman has started the _caddy-container_ 95 | 96 | A possible future modification to Example 5 could be to also run the backend web servers inside _systemd system services_ with `User=`. 97 | Then it would be possible to configure dependencies between the services by adding `After=`, `Depends=`, `Requires=` directives. 98 | -------------------------------------------------------------------------------- /examples/example5/caddy.container: -------------------------------------------------------------------------------- 1 | [Container] 2 | Image=docker.io/library/caddy 3 | ContainerName=caddy-container 4 | Volume=%h/Caddyfile:/etc/caddy/Caddyfile:Z 5 | Volume=%h/socketdir:/var/socketdir:z 6 | Network=none 7 | 8 | [Install] 9 | WantedBy=default.target 10 | -------------------------------------------------------------------------------- /examples/example5/example5.service.in: -------------------------------------------------------------------------------- 1 | # This file should be preprocessed with the envsubst command 2 | # to convert such text strings: ${envsubst_variablename} 3 | 4 | [Unit] 5 | Wants=network-online.target 6 | After=network-online.target 7 | Requires=user@${envsubst_uid}.service 8 | After=user@${envsubst_uid}.service 9 | RequiresMountsFor=/run/user/${envsubst_uid}/containers 10 | 11 | [Service] 12 | User=${envsubst_user} 13 | Environment=PODMAN_SYSTEMD_UNIT=%n 14 | KillMode=mixed 15 | ExecStop=/usr/bin/podman rm -f -i --cidfile=/run/user/${envsubst_uid}/%N.cid 16 | ExecStopPost=-/usr/bin/podman rm -f -i --cidfile=/run/user/${envsubst_uid}/%N.cid 17 | Delegate=yes 18 | Type=notify 19 | NotifyAccess=all 20 | SyslogIdentifier=%N 21 | ExecStart=/usr/bin/podman run \ 22 | --cidfile=/run/user/${envsubst_uid}/%N.cid \ 23 | --cgroups=split \ 24 | --rm \ 25 | --env "NGINX=3;" \ 26 | -d \ 27 | --network=none \ 28 | --volume /home/${envsubst_user}/socketdir:/var/socketdir:z \ 29 | --replace \ 30 | --userns keep-id:uid=101,gid=101 \ 31 | --user 0:0 \ 32 | --name systemd-%N \ 33 | --sdnotify=conmon \ 34 | --volume /home/${envsubst_user}/nginx-reverse-proxy-conf:/etc/nginx/conf.d:Z \ 35 | docker.io/library/nginx 36 | -------------------------------------------------------------------------------- /examples/example5/example5.socket: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Example 4 socket 3 | 4 | [Socket] 5 | ListenStream=0.0.0.0:80 6 | 7 | [Install] 8 | WantedBy=sockets.target 9 | -------------------------------------------------------------------------------- /examples/example5/install.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | 6 | repodir=$1 7 | user=$2 8 | 9 | # Alternatively a system account with no shell access could be created: 10 | # sudo useradd --system --shell /usr/sbin/nologin --create-home --add-subids-for-system -d "/home/$user" -- "$user" 11 | sudo useradd -- "$user" 12 | 13 | uid=$(id -u -- "$user") 14 | sourcedir="$repodir/examples/example5" 15 | 16 | sudo install --mode 0755 -Z -d -o "$user" -g "$user" "/home/$user/nginx-reverse-proxy-conf" 17 | sudo install --mode 0644 -Z -D -o "$user" -g "$user" --target-directory "/home/$user/nginx-reverse-proxy-conf" "$sourcedir/nginx-reverse-proxy-conf/caddy-example-com.conf" 18 | sudo install --mode 0644 -Z -D -o "$user" -g "$user" --target-directory "/home/$user/nginx-reverse-proxy-conf" "$sourcedir/nginx-reverse-proxy-conf/default.conf" 19 | 20 | sudo install --mode 0755 -Z -d -o "$user" -g "$user" "/home/$user/socketdir" 21 | sudo install --mode 0644 -Z -D -o "$user" -g "$user" --target-directory "/home/$user" "$sourcedir/Caddyfile" 22 | 23 | sudo install --mode 0755 -Z -d -o "$user" -g "$user" "/home/$user/.config/containers/systemd" 24 | sudo install --mode 0644 -Z -D -o "$user" -g "$user" --target-directory "/home/$user/.config/containers/systemd" "$sourcedir/caddy.container" 25 | sudo install --mode 0644 -Z -D -o root -g root --target-directory /etc/systemd/system/ "$sourcedir/example5.socket" 26 | 27 | # envsubst is used for text replacement in example5.service 28 | cat $repodir/examples/example5/example5.service.in | sudo bash -c "cat - | envsubst_user=$user envsubst_uid=$uid envsubst > /etc/systemd/system/example5.service" 29 | 30 | sudo loginctl enable-linger $user 31 | 32 | sudo systemctl daemon-reload 33 | sudo systemctl --user -M "$user@" daemon-reload 34 | sudo systemctl --user -M "$user@" start caddy.service 35 | sudo systemctl start example5.socket 36 | -------------------------------------------------------------------------------- /examples/example5/nginx-reverse-proxy-conf/caddy-example-com.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | server_name caddy.example.com; 4 | location / { 5 | proxy_pass http://caddy/; 6 | } 7 | } 8 | upstream caddy { 9 | server unix:/var/socketdir/socket; 10 | } 11 | -------------------------------------------------------------------------------- /examples/example5/nginx-reverse-proxy-conf/default.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | server_name localhost; 4 | location / { 5 | root /usr/share/nginx/html; 6 | index index.html index.htm; 7 | } 8 | error_page 500 502 503 504 /50x.html; 9 | location = /50x.html { 10 | root /usr/share/nginx/html; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /examples/example6/README.md: -------------------------------------------------------------------------------- 1 | return to [main page](../..) 2 | 3 | # Example 6 4 | 5 | status: experimental 6 | 7 | ``` mermaid 8 | graph TB 9 | 10 | a1[curl] -.->a2[nginx container reverse proxy] 11 | a2 -->|"for http://nginx.example.com"| a4["nginx backend container"] 12 | ``` 13 | 14 | Containers: 15 | 16 | | Container image | Type of service | Role | Network | Socket activation | SELinux | 17 | | -- | -- | -- | -- | -- | -- | 18 | | docker.io/library/nginx | systemd system service with `User=test6` | HTTP reverse proxy | `--network=none` | :heavy_check_mark: | disabled | 19 | | docker.io/library/nginx | systemd system service with `User=test6` | backend web server | `--network=none` | :heavy_check_mark: | enabled | 20 | 21 | > [!WARNING] 22 | > The container running the proxy is currently configured with`--security-opt label=disable` which means that SELinux is disabled for that container. 23 | 24 | This example is similar to [Example 5](../example5) but here the backend web server is 25 | started with _socket activation_ from a _systemd system service_ with `User=test6`. 26 | No systemd user services are used. 27 | All containers are run by rootless podman, which belongs to the user _test6_. 28 | 29 | ## Requirements 30 | 31 | These instructions were tested on Fedora 39 with Podman 4.7.2. 32 | 33 | ## Install instructions 34 | 35 | These install instructions will create the new user _test6_ and install these files: 36 | 37 | ``` 38 | /etc/systemd/system/example6-proxy.socket 39 | /etc/systemd/system/example6-proxy.service 40 | /etc/systemd/system/example6-backend.socket 41 | /etc/systemd/system/example6-backend.service 42 | /home/test6/nginx-reverse-proxy-conf/nginx-example-com.conf 43 | /home/test6/nginx-reverse-proxy-conf/default.conf 44 | /run/user/1006/backend-socket 45 | ``` 46 | (Here assuming `1006` is the UID of _test6_). 47 | The install instructions will also start _example6-proxy.socket_ and _example6-backend.socket_. 48 | 49 | 1. Clone this GitHub repo 50 | ``` 51 | $ git clone URL 52 | ``` 53 | 2. Change directory 54 | ``` 55 | $ cd podman-nginx-socket-activation 56 | ``` 57 | 3. Choose a username that will be created and used for the test 58 | ``` 59 | $ user=test6 60 | ``` 61 | 4. Run install script 62 | ``` 63 | $ sudo bash ./examples/example6/install.bash ./ $user 64 | ``` 65 | 5. Check the status of the backend socket 66 | ``` 67 | $ sudo systemctl is-active example6-backend.socket 68 | active 69 | ``` 70 | 6. Check the status of the HTTP reverse proxy socket 71 | ``` 72 | $ sudo systemctl is-active example6-proxy.socket 73 | active 74 | ``` 75 | 76 | ## Test the nginx reverse proxy 77 | 78 | 1. Test the nginx HTTP reverse proxy 79 | ``` 80 | $ curl -s --resolve nginx.example.com:80:127.0.0.1 nginx.example.com:80 | head -4 81 | 82 | 83 | 84 | Welcome to nginx! 85 | ``` 86 | Result: Success. The nginx reverse proxy fetched the output from the nginx backend. 87 | 88 | ## Discussion about SELinux 89 | 90 | To get it to work, `--security-opt label=disable` was given to the _podman run_ command in _example6-proxy.service_. 91 | -------------------------------------------------------------------------------- /examples/example6/example6-backend.service.in: -------------------------------------------------------------------------------- 1 | # This file should be preprocessed with the envsubst command 2 | # to convert such text strings: ${envsubst_variablename} 3 | 4 | [Unit] 5 | Wants=network-online.target 6 | After=network-online.target 7 | Requires=user@${envsubst_uid}.service 8 | After=user@${envsubst_uid}.service 9 | RequiresMountsFor=/run/user/${envsubst_uid}/containers 10 | 11 | [Service] 12 | User=${envsubst_user} 13 | Environment=PODMAN_SYSTEMD_UNIT=%n 14 | KillMode=mixed 15 | ExecStop=/usr/bin/podman rm -f -i --cidfile=/run/user/${envsubst_uid}/%N.cid 16 | ExecStopPost=-/usr/bin/podman rm -f -i --cidfile=/run/user/${envsubst_uid}/%N.cid 17 | Delegate=yes 18 | Type=notify 19 | NotifyAccess=all 20 | SyslogIdentifier=%N 21 | ExecStart=/usr/bin/podman run \ 22 | --cidfile=/run/user/${envsubst_uid}/%N.cid \ 23 | --cgroups=split \ 24 | --rm \ 25 | --env "NGINX=3;" \ 26 | -d \ 27 | --network=none \ 28 | --replace \ 29 | --userns keep-id:uid=101,gid=101 \ 30 | --user 0:0 \ 31 | --name systemd-%N \ 32 | --sdnotify=conmon \ 33 | --volume /home/${envsubst_user}/nginx-backend-conf:/etc/nginx/conf.d:Z \ 34 | docker.io/library/nginx 35 | -------------------------------------------------------------------------------- /examples/example6/example6-backend.socket.in: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Example 6 backend socket 3 | 4 | [Socket] 5 | ListenStream=/run/user/${envsubst_uid}/backend-socket 6 | SocketUser=${envsubst_user} 7 | SocketGroup=${envsubst_user} 8 | SocketMode=0600 9 | [Install] 10 | WantedBy=sockets.target 11 | -------------------------------------------------------------------------------- /examples/example6/example6-proxy.service.in: -------------------------------------------------------------------------------- 1 | # This file should be preprocessed with the envsubst command 2 | # to convert such text strings: ${envsubst_variablename} 3 | 4 | [Unit] 5 | Wants=network-online.target 6 | After=network-online.target 7 | Requires=user@${envsubst_uid}.service 8 | After=user@${envsubst_uid}.service 9 | 10 | Requires=example6-backend.socket 11 | After=example6-backend.socket 12 | 13 | RequiresMountsFor=/run/user/${envsubst_uid}/containers 14 | 15 | [Service] 16 | User=${envsubst_user} 17 | Environment=PODMAN_SYSTEMD_UNIT=%n 18 | KillMode=mixed 19 | ExecStop=/usr/bin/podman rm -f -i --cidfile=/run/user/${envsubst_uid}/%N.cid 20 | ExecStopPost=-/usr/bin/podman rm -f -i --cidfile=/run/user/${envsubst_uid}/%N.cid 21 | Delegate=yes 22 | Type=notify 23 | NotifyAccess=all 24 | SyslogIdentifier=%N 25 | ExecStart=/usr/bin/podman run \ 26 | --cidfile=/run/user/${envsubst_uid}/%N.cid \ 27 | --cgroups=split \ 28 | --rm \ 29 | --env "NGINX=3;" \ 30 | -d \ 31 | --network=none \ 32 | --replace \ 33 | --userns keep-id:uid=101,gid=101 \ 34 | --user 0:0 \ 35 | --name systemd-%N \ 36 | --sdnotify=conmon \ 37 | --security-opt label=disable \ 38 | --volume /home/${envsubst_user}/nginx-reverse-proxy-conf:/etc/nginx/conf.d:Z \ 39 | --volume /run/user/${envsubst_uid}/backend-socket:/var/socket:Z \ 40 | docker.io/library/nginx 41 | 42 | -------------------------------------------------------------------------------- /examples/example6/example6-proxy.socket: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Example 6 proxy socket 3 | 4 | [Socket] 5 | ListenStream=0.0.0.0:80 6 | 7 | [Install] 8 | WantedBy=sockets.target 9 | -------------------------------------------------------------------------------- /examples/example6/install.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | 6 | repodir=$1 7 | user=$2 8 | 9 | # Alternatively a system account with no shell access could be created: 10 | # sudo useradd --system --shell /usr/sbin/nologin --create-home --add-subids-for-system -d "/home/$user" -- "$user" 11 | sudo useradd -- "$user" 12 | 13 | sudo mkdir -p /srv/backend-socketdir 14 | 15 | #sudo chown -- "$user:$user" /srv/dir 16 | 17 | uid=$(id -u -- "$user") 18 | 19 | sourcedir="$repodir/examples/example6" 20 | 21 | sudo install --mode 0755 -Z -d -o "$user" -g "$user" "/home/$user/nginx-reverse-proxy-conf" 22 | sudo install --mode 0644 -Z -D -o "$user" -g "$user" --target-directory "/home/$user/nginx-reverse-proxy-conf" "$sourcedir/nginx-reverse-proxy-conf/nginx-example-com.conf" 23 | sudo install --mode 0644 -Z -D -o "$user" -g "$user" --target-directory "/home/$user/nginx-reverse-proxy-conf" "$sourcedir/nginx-reverse-proxy-conf/default.conf" 24 | 25 | sudo install --mode 0755 -Z -d -o "$user" -g "$user" "/home/$user/nginx-backend-conf" 26 | sudo install --mode 0644 -Z -D -o "$user" -g "$user" --target-directory "/home/$user/nginx-backend-conf" "$sourcedir/nginx-backend-conf/default.conf" 27 | 28 | sudo install --mode 0755 -Z -d -o "$user" -g "$user" "/home/$user/.config/containers/systemd" 29 | sudo install --mode 0644 -Z -D -o "$user" -g "$user" --target-directory "/home/$user/.config/containers/systemd" "$sourcedir/nginx.container" 30 | sudo install --mode 0644 -Z -D -o root -g root --target-directory /etc/systemd/system/ "$sourcedir/example6-proxy.socket" 31 | 32 | # envsubst is used for text replacement 33 | cat $repodir/examples/example6/example6-proxy.service.in | sudo bash -c "cat - | envsubst_user=$user envsubst_uid=$uid envsubst > /etc/systemd/system/example6-proxy.service" 34 | cat $repodir/examples/example6/example6-backend.service.in | sudo bash -c "cat - | envsubst_user=$user envsubst_uid=$uid envsubst > /etc/systemd/system/example6-backend.service" 35 | cat $repodir/examples/example6/example6-backend.socket.in | sudo bash -c "cat - | envsubst_user=$user envsubst_uid=$uid envsubst > /etc/systemd/system/example6-backend.socket" 36 | cat $repodir/examples/example6/nginx-backend-conf/nginx-example-com.conf.in | sudo bash -c "cat - | envsubst_user=$user envsubst_uid=$uid envsubst > /home/$user/nginx-backend-conf/nginx-example-com.conf" 37 | 38 | sudo chown "$user:$user" "/home/$user/nginx-backend-conf/nginx-example-com.conf" 39 | 40 | sudo loginctl enable-linger "$user" 41 | 42 | sudo systemctl daemon-reload 43 | 44 | sudo systemctl start example6-backend.socket 45 | sudo systemctl start example6-proxy.socket 46 | -------------------------------------------------------------------------------- /examples/example6/nginx-backend-conf/default.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | server_name localhost; 4 | location / { 5 | root /usr/share/nginx/html; 6 | index index.html index.htm; 7 | } 8 | error_page 500 502 503 504 /50x.html; 9 | location = /50x.html { 10 | root /usr/share/nginx/html; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /examples/example6/nginx-backend-conf/nginx-example-com.conf.in: -------------------------------------------------------------------------------- 1 | server { 2 | listen unix:/run/user/${envsubst_uid}/backend-socket; 3 | server_name nginx.example.com; 4 | location / { 5 | root /usr/share/nginx/html; 6 | index index.html index.htm; 7 | } 8 | error_page 500 502 503 504 /50x.html; 9 | location = /50x.html { 10 | root /usr/share/nginx/html; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /examples/example6/nginx-reverse-proxy-conf/default.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | server_name localhost; 4 | location / { 5 | root /usr/share/nginx/html; 6 | index index.html index.htm; 7 | } 8 | error_page 500 502 503 504 /50x.html; 9 | location = /50x.html { 10 | root /usr/share/nginx/html; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /examples/example6/nginx-reverse-proxy-conf/nginx-example-com.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | server_name nginx.example.com; 4 | location / { 5 | proxy_pass http://nginx/; 6 | } 7 | } 8 | upstream nginx { 9 | server unix:/var/socket; 10 | } 11 | --------------------------------------------------------------------------------