Skip to content

Commit 2534643

Browse files
committed
Add example5 (--network=none)
Add example5 that is similar to example4 but the containers use `--network=none` and communicate over a Unix socket. Move references to main README.md Signed-off-by: Erik Sjölund <[email protected]>
1 parent 1ba54a2 commit 2534643

11 files changed

+276
-158
lines changed

README.md

+20-1
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ Overview of the examples
77

88
| Example | Type of service | Port | Using quadlet | rootful/rootless podman | Comment |
99
| -- | -- | -- | -- | -- | -- |
10-
| [Example 1](examples/example1) | systemd user service | 8080 | yes | rootless podman | |
10+
| [Example 1](examples/example1) | systemd user service | 8080 | yes | rootless podman | Only unprivileged port numbers can be used |
1111
| [Example 2](examples/example2) | systemd system service | 80 | yes | rootful podman | |
1212
| [Example 3](examples/example3) | systemd system service (with `User=test`) | 80 | no | rootless podman | Status: experimental |
1313
| [Example 4](examples/example4) | systemd system service (with `User=test`) | 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=test`) | 80 | no | rootless podman | Similar to Example 4 but the containers use `--network=none` and communicate over a Unix socket. Status: experimental. |
1415

1516
> **Note**
1617
> 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/
@@ -100,3 +101,21 @@ The Podman network tools are not needed when using __--network=host__ or __--ne
100101
(see GitHub [issue comment](https://github.com/containers/podman/discussions/16493#discussioncomment-4140832)).
101102
In other words, the total amount of executables and libraries that are needed by Podman is reduced
102103
when you run the nginx container with _socket activation_ and __--network=none__.
104+
105+
### References
106+
107+
__Reference 1:__
108+
109+
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
110+
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
111+
been systemd that created the Unix sockets. The __podman run__ option `--network none` is used.
112+
113+
__Reference 2:__
114+
115+
The article "_How to create multidomain web applications with Podman and Nginx_" https://www.redhat.com/sysadmin/podman-nginx-multidomain-applications
116+
describes running nginx as a reverse proxy with rootless podman.
117+
In the article rootless podman is given the privilege to listen on port 80 with the command
118+
```
119+
sudo sysctl net.ipv4.ip_unprivileged_port_start=80
120+
```
121+
Socket activation is not used in the article.

examples/example4/README.md

+45-157
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
return to [main page](../..)
22

3-
## Example 4
3+
# Example 4
44

55
status: experimental
66

@@ -14,171 +14,68 @@ graph TB
1414

1515
Containers:
1616

17-
| Container image | Type of service | Role |
18-
| -- | -- | -- |
19-
| docker.io/library/nginx | systemd system service with `User=test` | HTTP reverse proxy |
20-
| docker.io/library/httpd | systemd user service | backend web server |
21-
| docker.io/library/caddy | systemd user service | backend web server |
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 | [internal bridge network](example4-net.network) | backend web server | |
21+
| docker.io/library/caddy | systemd user service | backend web server | [internal bridge network](example4-net.network) | |
2222

2323
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) that
25-
are running in systemd user services. All containers are run by rootless podman,
26-
which belongs to the user _test_.
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 _test_.
2726
The containers communicate over an internal bridge network that does not have internet access.
2827

29-
#### set up _example4.service_
28+
## Requirements
3029

31-
1. Create the user _test_ if it does not yet exist.
32-
```
33-
$ sudo useradd test
34-
```
35-
2. Check the UID of the user _test_
36-
```
37-
$ id -u test
38-
1000
39-
```
40-
3. Create the directory _/home/test/nginx_conf_d_
41-
4. Create the file _/home/test/nginx_conf_d/default.conf_ with the contents
42-
```
43-
server {
44-
listen 80;
45-
server_name localhost;
46-
location / {
47-
root /usr/share/nginx/html;
48-
index index.html index.htm;
49-
}
50-
error_page 500 502 503 504 /50x.html;
51-
location = /50x.html {
52-
root /usr/share/nginx/html;
53-
}
54-
}
55-
```
56-
The file contents were created with the command
57-
```
58-
podman run --rm docker.io/library/nginx /bin/bash -c 'cat /etc/nginx/conf.d/default.conf | grep -v \# | sed /^[[:space:]]*$/d' > default.conf
59-
```
60-
4. Create the file _/home/test/nginx_conf_d/apache-example-com.conf_ with the contents
61-
```
62-
server {
63-
listen 80;
64-
server_name apache.example.com;
65-
location / {
66-
proxy_pass http://apache-container:80;
67-
}
68-
}
69-
```
70-
5. Create the file _/home/test/nginx_conf_d/caddy-example-com.conf_ with the contents
71-
```
72-
server {
73-
listen 80;
74-
server_name caddy.example.com;
75-
location / {
76-
proxy_pass http://caddy-container:80;
77-
}
78-
}
79-
```
80-
6. Create the file _/etc/systemd/system/example4.service_ with the contents
81-
```
82-
[Unit]
83-
Wants=network-online.target
84-
After=network-online.target
85-
86-
87-
RequiresMountsFor=/run/user/1000/containers
88-
89-
[Service]
90-
User=test
91-
Environment=PODMAN_SYSTEMD_UNIT=%n
92-
KillMode=mixed
93-
ExecStop=/usr/bin/podman rm -f -i --cidfile=/run/user/1000/%N.cid
94-
ExecStopPost=-/usr/bin/podman rm -f -i --cidfile=/run/user/1000/%N.cid
95-
Delegate=yes
96-
Type=notify
97-
NotifyAccess=all
98-
SyslogIdentifier=%N
99-
ExecStart=/usr/bin/podman run \
100-
--cidfile=/run/user/1000/%N.cid \
101-
--cgroups=split \
102-
--rm \
103-
--env "NGINX=3;" \
104-
-d \
105-
--network systemd-example4-net \
106-
--replace \
107-
--name systemd-%N \
108-
--sdnotify=conmon \
109-
--volume /home/test/nginx_conf_d:/etc/nginx/conf.d:Z \
110-
docker.io/library/nginx
111-
```
112-
(To adjust the file for your system, replace `1000` with the UID found in step 2)
113-
7. Create the file _/etc/systemd/system/example4.socket_ with the contents
114-
```
115-
[Unit]
116-
Description=Example 4 socket
30+
These instructions were tested on Fedora 39 with Podman 4.7.2.
11731

118-
[Socket]
119-
ListenStream=0.0.0.0:80
32+
## Install instructions
12033

121-
[Install]
122-
WantedBy=sockets.target
123-
```
124-
8. Reload the systemd configuration
125-
```
126-
$ sudo systemctl daemon-reload
127-
```
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+
```
12846

129-
#### set up _apache.service_ and _caddy.service_
47+
and start _caddy.service_, _apache.service_ and _example4.socket_.
13048

131-
1. Open a terminal as the user _test_
132-
```
133-
$ sudo machinectl shell --uid test
49+
1. Clone this GitHub repo
13450
```
135-
(It might be more convenient to create directories and files when logged in as the user)
136-
2. Create directory
51+
$ git clone URL
13752
```
138-
$ mkdir -p /home/test/.config/containers/systemd
53+
2. Change directory
13954
```
140-
3. Create the file _/home/test/.config/containers/systemd/apache.container_ with the contents
55+
$ cd podman-nginx-socket-activation
14156
```
142-
[Container]
143-
Image=docker.io/library/apache
144-
Network=example4-net.network
145-
ContainerName=apache-container
146-
[Install]
147-
WantedBy=default.target
57+
3. Choose a username that will be created and used for the test
14858
```
149-
4. Create the file _/home/test/.config/containers/systemd/caddy.container_ with the contents
59+
$ user=test4
15060
```
151-
[Container]
152-
Image=docker.io/library/caddy
153-
Network=example4-net.network
154-
ContainerName=caddy-container
155-
[Install]
156-
WantedBy=default.target
61+
4. Run install script
15762
```
158-
5. Create the file _/home/test/.config/containers/systemd/example4-net.network_ with the contents
63+
$ sudo bash ./examples/example4/install.bash ./ $user
15964
```
160-
[Network]
161-
Internal=true
65+
5. Check the status of the backend containers
16266
```
163-
Optional: To give the containers access to the internet, remove the line `Internal=true`
164-
6. Reload the systemd configuration
67+
$ sudo systemctl --user -M ${user}@ is-active apache.service
68+
active
69+
$ sudo systemctl --user -M ${user}@ is-active caddy.service
70+
active
16571
```
166-
$ systemctl --user daemon-reload
72+
6. Check the status of the HTTP reverse proxy socket
16773
```
168-
7. Start _apache.service_ and _caddy.service_
74+
$ sudo systemctl is-active example4.socket
75+
active
16976
```
170-
$ systemctl --user start apache.service
171-
$ systemctl --user start caddy.service
172-
```
173-
174-
__Side-note__: If the user _test_ is an account with no log in shell, skip step 1 and replace step 6 and 7 with
175-
```
176-
$ sudo systemctl --user -M test@ daemon-reload
177-
$ sudo systemctl --user -M test@ start apache.service
178-
$ sudo systemctl --user -M test@ start caddy.service
179-
```
180-
181-
#### test the HTTP reverse proxy
77+
78+
## Test the nginx reverse proxy
18279

18380
1. Test the nginx HTTP reverse proxy
18481
```
@@ -195,22 +92,13 @@ $ sudo systemctl --user -M test@ start caddy.service
19592
```
19693
Result: Success. The nginx reverse proxy fetched the output from the caddy container.
19794

198-
#### discussion about service dependencies
95+
## Discussion about service dependencies
19996

20097
systemd does not support having dependencies between _systemd system services_ and _systemd user services_.
201-
Because of that we need to make sure that _example4-nginx.socket_ is started after
98+
Because of that we need to make sure that _example4.service_ is started after
20299

203100
* podman has created the network _systemd-example4-net_
204-
* podman has started _apache-container_ and _caddy-container_
101+
* podman has started _apache-container_ (_apache.service_) and _caddy-container_ (_caddy.service_)
205102

206103
A possible future modification to Example 4 could be to also run the backend web servers inside _systemd system services_ with `User=`.
207104
Then it would be possible to configure dependencies between the services by adding `After=`, `Depends=`, `Requires=` directives.
208-
209-
#### references
210-
211-
See also the article "_How to create multidomain web applications with Podman and Nginx_" https://www.redhat.com/sysadmin/podman-nginx-multidomain-applications
212-
It describes a similar setup but neither systemd system service with `User=` nor socket activation is used.
213-
To be able to bind to port 80, the following command is used:
214-
```
215-
sudo sysctl net.ipv4.ip_unprivileged_port_start=80
216-
```
File renamed without changes.

examples/example5/Caddyfile

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
http:// {
2+
bind unix//var/socketdir/socket
3+
root * /usr/share/caddy
4+
file_server
5+
}

examples/example5/README.md

+97
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
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 _test_.
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+
<!DOCTYPE html>
83+
<html>
84+
<head>
85+
<title>Caddy works!</title>
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.

examples/example5/caddy.container

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
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

0 commit comments

Comments
 (0)