├── 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 |
--------------------------------------------------------------------------------