{"id":18088990,"url":"https://github.com/eriksjolund/podman-networking-docs","last_synced_at":"2025-04-06T02:28:51.996Z","repository":{"id":210266732,"uuid":"656160641","full_name":"eriksjolund/podman-networking-docs","owner":"eriksjolund","description":"rootless Podman networking documentation with examples","archived":false,"fork":false,"pushed_at":"2025-01-01T16:16:48.000Z","size":71,"stargazers_count":69,"open_issues_count":3,"forks_count":0,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-02-12T08:39:03.907Z","etag":null,"topics":["documentation","examples","networking","pasta","podman","slirp4netns","socket-activation","systemd","systemd-run"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/eriksjolund.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-06-20T11:23:52.000Z","updated_at":"2025-02-03T19:31:07.000Z","dependencies_parsed_at":"2024-04-11T16:26:35.370Z","dependency_job_id":"6d3c1839-0b8d-44e6-baf0-5e4c8681c3ee","html_url":"https://github.com/eriksjolund/podman-networking-docs","commit_stats":null,"previous_names":["eriksjolund/podman-networking-docs"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eriksjolund%2Fpodman-networking-docs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eriksjolund%2Fpodman-networking-docs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eriksjolund%2Fpodman-networking-docs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eriksjolund%2Fpodman-networking-docs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/eriksjolund","download_url":"https://codeload.github.com/eriksjolund/podman-networking-docs/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247425537,"owners_count":20936971,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["documentation","examples","networking","pasta","podman","slirp4netns","socket-activation","systemd","systemd-run"],"created_at":"2024-10-31T17:42:32.828Z","updated_at":"2025-04-06T02:28:51.977Z","avatar_url":"https://github.com/eriksjolund.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# podman-networking-docs\n\nThis guide is about how to configure networking when using __rootless Podman__.\n\n# Inbound TCP/UDP connections\n\n## Overview\n\nListening TCP/UDP sockets\n\n| method | source address preserved | native performance | support for binding to specific network device | minimum port number |\n|-|-|-|-|-|\n| [socket activation (systemd user service)](#socket-activation-systemd-user-service) | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | [ip_unprivileged_port_start](https://github.com/eriksjolund/podman-networking-docs#configure-ip_unprivileged_port_start) |\n| [socket activation (systemd system service with User=)](#socket-activation-systemd-system-service-with-user) | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | 0 |\n| pasta             | :heavy_check_mark: | | :heavy_check_mark: | [ip_unprivileged_port_start](https://github.com/eriksjolund/podman-networking-docs#configure-ip_unprivileged_port_start) |\n| pasta + custom network | | | | [ip_unprivileged_port_start](https://github.com/eriksjolund/podman-networking-docs#configure-ip_unprivileged_port_start) |\n| slirp4netns + port_handler=slirp4netns | :heavy_check_mark: | | | [ip_unprivileged_port_start](https://github.com/eriksjolund/podman-networking-docs#configure-ip_unprivileged_port_start) |\n| slirp4netns + port_handler=rootlesskit | | | | [ip_unprivileged_port_start](https://github.com/eriksjolund/podman-networking-docs#configure-ip_unprivileged_port_start) |\n| host | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | [ip_unprivileged_port_start](https://github.com/eriksjolund/podman-networking-docs#configure-ip_unprivileged_port_start) |\n\n## Valid method combinations\n\nThe methods\n\n* pasta\n* pasta + custom network\n* slirp4netns + port_handler=rootlesskit\n* slirp4netns + port_handler=slirp4netns\n* host\n\nare mutually exclusive.\n\nSocket activation can be combined with the other methods.\n\nFor example, it is possible to combine __socket activation__ with __pasta + custom network__ to get __source address preserved__ and __native speed__ communication to an HTTP reverse proxy that\nis running on a custom network.\n\n## Source address preserved\n\nExample:\n\nIf the source address __is preserved__ in the incoming TCP connection,\nthen nginx is able to see the IP address of host2 (192.0.2.10)\nwhere the curl request is run.\n\n``` mermaid\nflowchart LR\n    curl--\u003enginx[\"nginx container\"]\n    subgraph host1\n    nginx\n    end\n    subgraph host2 [\"host2 ip=192.0.2.10\"]\n    curl\n    end\n```\n\nnginx logs the HTTP request as coming from _192.0.2.10_\n```\n192.0.2.10 - - [15/Jun/2023:07:41:18 +0000] \"GET / HTTP/1.1\" 200 615 \"-\" \"curl/8.1.1\" \"-\"\n```\n\nIf the source address __is not preserved__, then nginx sees another\nsource address in the TCP connection.\nFor example, if the nginx container is run with __slirp4netns + port_handler=rootlesskit__\n\n```\npodman run --network=slirp4netns:port_handler=rootlesskit \\\n           --publish 8080:80 \\\n           --rm \\\n           ghcr.io/nginxinc/nginx:latest\n```\n\nnginx logs the HTTP request as coming from _10.0.2.2_\n```\n10.0.2.2 - - [15/Jun/2023:07:41:18 +0000] \"GET / HTTP/1.1\" 200 615 \"-\" \"curl/8.1.1\" \"-\"\n```\n\n#### example: socket activation (systemd user service) - source address preserved\n\n\u003cdetails\u003e\n  \u003csummary\u003eClick me\u003c/summary\u003e\n\n-------------\n\nThis example uses two computers \n* _host1.example.com_ (for running the nginx web server)\n* _host2.example.com_ (for running curl)\n\n1. On _host1_ create user _test_\n   ```\n   sudo useradd test\n   ```\n2. Open an interactive shell session for the user _test_\n   ```\n   sudo machinectl shell test@\n   ```\n3. Create directories\n   ```\n   mkdir -p ~/.config/containers/systemd\n   mkdir -p ~/.config/systemd/user\n   ```\n4. Create the file _/home/test/.config/containers/systemd/nginx.container_ containing\n   ```\n   [Container]\n   Image=ghcr.io/nginxinc/nginx-unprivileged:latest\n   ContainerName=mynginx\n   Environment=\"NGINX=3;\"\n   \n   [Install]\n   WantedBy=default.target\n   ```\n5. Create the file _/home/test/.config/systemd/user/nginx.socket_ containing\n   ```\n   [Unit]\n   Description=nginx socket\n   \n   [Socket]\n   ListenStream=0.0.0.0:8080\n   \n   [Install]\n   WantedBy=default.target\n   ```\n6. Reload the systemd user manager\n   ```\n   systemctl --user daemon-reload\n   ```\n7. Pull the container image\n   ```\n   podman pull ghcr.io/nginxinc/nginx-unprivileged:latest\n   ```\n8. Start the socket\n   ```\n   systemctl --user start nginx.socket\n   ```\n9. Test the nginx web server by accessing it from _host2_\n   1. Log in to _host2_\n   2. Run curl\n       ```\n       curl host1.example.com:8080\n       ```\n   3. Log out from _host2_\n10. Check the logs in the container _mynginx_\n    ```\n    podman logs mynginx 2\u003e /dev/null | grep \"GET /\"\n    ```\n    The output should look something like\n    ```\n    192.0.2.10 - - [15/Jun/2023:07:41:18 +0000] \"GET / HTTP/1.1\" 200 615 \"-\" \"curl/8.1.1\" \"-\"\n    ```\n    nginx logged the source address of the TCP connection to be 192.0.2.10 which matches the IP address of _host2.example.com_. Conclusion: the source address was preserved.\n\n__A side-note:__ If the feature request https://trac.nginx.org/nginx/ticket/237 gets implemented, the `Environment=\"NGINX=3;\"` could be removed. This example makes use of the fact that \"_nginx includes an undocumented, internal socket-passing mechanism_\" quote from https://freedesktop.org/wiki/Software/systemd/DaemonSocketActivation/\n\n-------------\n\n\u003c/details\u003e\n\n#### example: pasta - source address preserved\n\n\u003cdetails\u003e\n  \u003csummary\u003eClick me\u003c/summary\u003e\n\n-------------\n\nThis example uses two computers \n* _host1.example.com_ (for running the nginx web server)\n* _host2.example.com_ (for running curl)\n\n1. On _host1_ create user _test_\n   ```\n   sudo useradd test\n   ```\n2. Open an interactive shell session for the user _test_\n   ```\n   sudo machinectl shell test@\n   ```\n3. Create directories\n   ```\n   mkdir -p ~/.config/containers/systemd\n   ```\n4. Create the file _/home/test/.config/containers/systemd/nginx.container_ containing\n   ```\n   [Container]\n   Image=ghcr.io/nginxinc/nginx-unprivileged:latest\n   ContainerName=mynginx\n   Network=pasta\n   PublishPort=0.0.0.0:8080:8080\n   \n   [Install]\n   WantedBy=default.target\n   ```\n5. Reload the systemd user manager\n   ```\n   systemctl --user daemon-reload\n   ```\n6. Pull the container image\n   ```\n   podman pull ghcr.io/nginxinc/nginx-unprivileged:latest\n   ```\n7. Start the service\n   ```\n   systemctl --user start nginx.service\n   ```\n8. Test the nginx web server by accessing it from _host2_\n   1. Log in to _host2_\n   2. Run curl\n       ```\n       curl host1.example.com:8080\n       ```\n   3. Log out from _host2_\n9. Check the logs in the container _mynginx_\n   ```\n   podman logs mynginx 2\u003e /dev/null | grep \"GET /\"\n   ```\n   The output should look something like\n   ```\n   192.0.2.10 - - [15/Jun/2023:07:55:03 +0000] \"GET / HTTP/1.1\" 200 615 \"-\" \"curl/8.1.1\" \"-\"\n   ```\n   nginx logged the source address of the TCP connection to be 192.0.2.10 which matches the IP address of _host2.example.com_. Conclusion: the source address __is preserved__.\n\n-------------\n\n\u003c/details\u003e\n\n#### example: pasta + custom network - source address not preserved\n\n\u003cdetails\u003e\n  \u003csummary\u003eClick me\u003c/summary\u003e\n\n-------------\n\nFollow the same steps as\n\n[example: pasta - source address preserved](#example-pasta---source-address-preserved)\n\nbut replace `Network=pasta` with `Network=mynet.network`. Create the network unit\nfile `mynet.network` that defines a custom network. (_mynet_ is an arbitrarily chosen name)\n\nIn other words, replace step 4 with\n\n4. Create the file _/home/test/.config/containers/systemd/nginx.container_ containing\n   ```\n   [Container]\n   Image=ghcr.io/nginxinc/nginx-unprivileged:latest\n   ContainerName=mynginx\n   Network=mynet.network\n   PublishPort=0.0.0.0:8080:8080\n   \n   [Install]\n   WantedBy=default.target\n   ```\n   Create the file _/home/test/.config/containers/systemd/mynet.network_ containing\n   ```\n   [Network]\n   ```\n\nAt step 9 you will see that the source address __is not preserved__. Instead of 192.0.2.10 (IP address for _host1.example.com_),\nnginx instead logs the IP address 10.89.0.2.\n\n   ```\n   podman logs mynginx 2\u003e /dev/null | grep \"GET /\"\n   ```\n   The output should look something like\n   ```\n   10.89.0.2 - - [24/Jun/2024:07:10:59 +0000] \"GET / HTTP/1.1\" 200 615 \"-\" \"curl/8.6.0\" \"-\"\n   ```\n\n-------------\n\n\u003c/details\u003e\n\n#### example: pasta + custom network + socket activation + libsdsock - source address preserved\n\n\u003cdetails\u003e\n  \u003csummary\u003eClick me\u003c/summary\u003e\n\nStatus: experimental. (The use of [__libsdsock__](https://github.com/ryancdotorg/libsdsock) in this example makes it experimental)\n\nSome container images do not support _socket activation_.\nFor example this Containerfile defines a container image that has a web server that does not support _socket activation_.\n\n   ```\n   FROM docker.io/library/fedora\n   RUN dnf -y install python3\n   CMD [\"python3\",\"-m\", \"http.server\", \"8080\", \"--bind\", \"0.0.0.0\"]\n   ```\n\nSuch a container is typically configured with the `PublishPort` instruction in the container unit (for example `PublishPort=8080:8080`).\nUnfortunately, the source address of a TCP connection that the web server sees is not the IP address of the client when using pasta and a custom network.\nIn other words, the _source address is not preserved_.\n\nThis shortcoming can be fixed by using the library [__libsdsock__](https://github.com/ryancdotorg/libsdsock).\nIf we create a socket unit and let the the web server have the library __libsdsock__ preloaded, the curl client source address is preserved.\n\nNote, this is a rather experimental approach.\n\n1. Create directory _dir_\n\n2. Create the file _dir/Containerfile_ with the contents\n   ```\n   FROM docker.io/library/fedora as myweb\n   RUN dnf -y install python3\n   CMD [\"python3\",\"-m\", \"http.server\", \"8080\",\"--bind\", \"0.0.0.0\"]\n   \n   FROM docker.io/library/fedora as libsdsock-builder\n   RUN dnf -y install gcc git make systemd-devel\n   RUN git clone https://github.com/ryancdotorg/libsdsock.git\n   RUN cd /libsdsock \u0026\u0026 make \u0026\u0026 make install\n\n   FROM myweb\n   RUN dnf -y install systemd-libs\n   COPY --from=libsdsock-builder /usr/local/lib/libsdsock.so /usr/local/lib/libsdsock.so\n   ```\n   Note the difference to the original Containerfile. The file _/usr/local/lib/libsdsock.so_ and the\n   RPM package _systemd-libs_ are installed.\n3. Build the container image\n   ```\n   podman build -t myweb dir/\n   ```\n4. Create directories\n   ```\n   mkdir -p ~/.config/containers/systemd\n   mkdir -p ~/.config/systemd/user\n   ```\n5. Create the file _~/.config/systemd/user/mynet.network_ with the contents\n   ```\n   [Network]\n   Internal=true\n   ```\n6. Create the file _~/.config/systemd/user/myweb.socket_ with the contents\n   ```\n   [Socket]\n   ListenStream=0.0.0.0:8080\n   \n   [Install]\n   WantedBy=sockets.target\n   ```\n7. Create the file _~/.config/containers/systemd/myweb.container_ with the contents\n   ```\n   [Unit]\n   Requires=myweb.socket\n   After=myweb.socket\n\n   [Container]\n   Image=localhost/myweb\n   Network=mynet.network\n   Environment=LD_PRELOAD=/usr/local/lib/libsdsock.so\n   Environment=LIBSDSOCK_MAP=tcp://0.0.0.0:8080=myweb.socket\n\n   [Install]\n   WantedBy=default.target\n   ```\n8. Reload the systemd user manager\n   ```\n   systemctl --user daemon-reload\n   ```\n9. Start the socket\n   ```\n   systemctl --user start myweb.socket\n   ```\n10. Fetch a web page with curl\n    ```\n    curl -s http://localhost:8080 | head -2\n    ```\n    The following output is printed\n    ```\n    \u003c!DOCTYPE HTML\u003e\n    \u003chtml lang=\"en\"\u003e\n    ```\n11. Run the command\n    ```\n    journalctl --user -xequ myweb.service | tail -1\n    ```\n    The following output is printed\n    ```\n    Aug 04 15:57:26 mycomputer systemd-myweb[12829]: 127.0.0.1 - - [04/Aug/2024 15:57:26] \"GET / HTTP/1.1\" 200 -\n    ```\n\n__result:__ The client source address is preserved.\n\n\u003c/details\u003e\n\n#### example: slirp4netns + port_handler=slirp4netns - source address preserved\n\n\u003cdetails\u003e\n  \u003csummary\u003eClick me\u003c/summary\u003e\n\n-------------\n\nFollow the same steps as\n\n[example: pasta - source address preserved](#example-pasta---source-address-preserved)\n\nbut replace `Network=pasta` with `Network=slirp4netns:port_handler=slirp4netns`.\n\nIn other words, replace step 4 with\n\n4. Create the file _/home/test/.config/containers/systemd/nginx.container_ containing\n   ```\n   [Container]\n   Image=ghcr.io/nginxinc/nginx-unprivileged:latest\n   ContainerName=mynginx\n   Network=slirp4netns:port_handler=slirp4netns\n   PublishPort=0.0.0.0:8080:8080\n   \n   [Install]\n   WantedBy=default.target\n   ```\n\n-------------\n\n\u003c/details\u003e\n\n#### example: slirp4netns + port_handler=rootlesskit - source address not preserved\n\n\u003cdetails\u003e\n  \u003csummary\u003eClick me\u003c/summary\u003e\n\n-------------\n\nFollow the same steps as\n\n[example: pasta - source address preserved](#example-pasta---source-address-preserved)\n\nbut replace `Network=pasta` with `Network=slirp4netns:port_handler=rootlesskit`.\n\nIn other words, replace step 4 with\n\n4. Create the file _/home/test/.config/containers/systemd/nginx.container_ containing\n   ```\n   [Container]\n   Image=ghcr.io/nginxinc/nginx-unprivileged:latest\n   ContainerName=mynginx\n   Network=slirp4netns:port_handler=rootlesskit\n   PublishPort=0.0.0.0:8080:8080\n   \n   [Install]\n   WantedBy=default.target\n   ```\n\nAt step 9 you will see that the source address __is not preserved__. Instead of 192.0.2.10 (IP address for _host1.example.com_),\nnginx instead logs the IP address 10.0.2.100.\n\n   ```\n   podman logs mynginx 2\u003e /dev/null | grep \"GET /\"\n   ```\n   The output should look something like\n   ```\n   10.0.2.100 - - [15/Jun/2023:07:55:03 +0000] \"GET / HTTP/1.1\" 200 615 \"-\" \"curl/8.1.1\" \"-\"\n   ```\n\n-------------\n\n\u003c/details\u003e\n\n#### example: host - source address preserved\n\n\u003cdetails\u003e\n  \u003csummary\u003eClick me\u003c/summary\u003e\n\n-------------\n\nFollow the same steps as\n\n[example: pasta - source address preserved](#example-pasta---source-address-preserved)\n\nbut remove the line `PublishPort=0.0.0.0:8080:8080` and replace `Network=pasta` with `Network=host`.\n\nIn other words, replace step 4 with\n\n4. Create the file _/home/test/.config/containers/systemd/nginx.container_ containing\n   ```\n   [Container]\n   Image=ghcr.io/nginxinc/nginx-unprivileged:latest\n   ContainerName=mynginx\n   Network=host\n   \n   [Install]\n   WantedBy=default.target\n   ```\n\n-------------\n\n\u003c/details\u003e\n\n## Performance\n\n| method | native performance |\n|-|-|\n| socket activation (systemd user service) | :heavy_check_mark: |\n| socket activation (systemd system service) | :heavy_check_mark: |\n| pasta | |\n| slirp4netns + port_handler=slirp4netns | |\n| slirp4netns + port_handler=rootlesskit | |\n| host | :heavy_check_mark: |\n\nBest performance has\n\n* socket activation (systemd user service)\n* socket activation (systemd system service)\n* host\n\nwhere there is no slowdown compared to running directly on the host.\n\nThe other methods ordered from fastest to slowest:\n\n1. pasta\n2. slirp4netns + port_handler=rootlesskit\n3. slirp4netns + port_handler=slirp4netns\n\n## Support for binding to specific network device\n\n| method | support for binding to specific network device |\n|-|-|\n| socket activation (systemd user service) | :heavy_check_mark: |\n| socket activation (systemd system service) | :heavy_check_mark: |\n| pasta | :heavy_check_mark: |\n| pasta + custom network | |\n| slirp4netns + port_handler=slirp4netns | |\n| slirp4netns + port_handler=rootlesskit | |\n| host | :heavy_check_mark: |\n\nexamples\n\n-------------\n\n\u003c/details\u003e\n\n#### example: socket activation (systemd user service) - bind to specific network device\n\n\u003cdetails\u003e\n  \u003csummary\u003eClick me\u003c/summary\u003e\n\n-------------\n\nSpecify the network device to bind to with the systemd directive [BindToDevice](https://www.freedesktop.org/software/systemd/man/systemd.socket.html#BindToDevice=) in the socket unit file.\n\nFor example, to bind to the ethernet interface _eth0_, add the line\n```\nBindToDevice=eth0\n```\nThe socket unit file could look like this \n\n```\n[Unit]\nDescription=example socket\n\n[Socket]\nListenStream=0.0.0.0:8080\nBindToDevice=eth0\n\n[Install]\nWantedBy=default.target\n```\n\n\n-------------\n\n\u003c/details\u003e\n\n#### example: pasta - bind to specific network device\n\n\u003cdetails\u003e\n  \u003csummary\u003eClick me\u003c/summary\u003e\n\n-------------\n\nTo publish the TCP port 8080 and bind the listening socket to the\nethernet interface _eth0_ use the configuration lines\n\n```\nNetwork=pasta:-t,0.0.0.0%%eth0/8080:8080\n```\n\nunder the `[Container]` section in the container file.\n\nFor example the file _/home/test/.config/containers/systemd/nginx.container_ containing\n\n   ```\n   [Container]\n   Image=ghcr.io/nginxinc/nginx-unprivileged:latest\n   ContainerName=mynginx\n   Network=pasta:-t,0.0.0.0%%eth0/8080:8080\n   \n   [Install]\n   WantedBy=default.target\n   ```\n\nIf you want to publish an UDP port instead of a TCP port, replace `-t` with `-u` above.\n\n__Side note 1:__ The quadlet configuration directive `PublishPort=` is not used.\nThe port is in this example published by specifying the pasta `-t` option.\n\n__Side note 2:__ Due to how quadlet/systemd parses the configuration line, a percentage character\nneeds to be escaped by prepending it with an extra percentage character.\n\nThe percentage character should not be escaped when the network option is provided\nas a command-line option for `podman run`, for example `--network=pasta:-t,0.0.0.0%eth0/8080:8080`\n\n-------------\n\n\u003c/details\u003e\n\n\n## Configure `ip_unprivileged_port_start`\n\nRead the current setting\n\n```\n$ cat /proc/sys/net/ipv4/ip_unprivileged_port_start\n1024\n```\n\nTo set a new value (for example 443), create\nthe file _/etc/sysctl.d/99-mysettings.conf_\nwith the contents:\n\n```\nnet.ipv4.ip_unprivileged_port_start=443\n```\n\nand reload the configuration\n\n```\nsudo sysctl --system\n```\n\nThe setting is system-wide so changing it impacts all users on the system.\n\nGiving this privilege to all users on the computer might not be what you want\nbecause often you already know which systemd service should be listening on a privileged port.\nIf the software supports _socket activation_, an alternative is to set up a\nsystemd system service with `User=`. For details, see the\nsection [_Socket activation (systemd system service with User=)_](#socket-activation-systemd-system-service-with-user)\n\n## Outbound TCP/UDP connections\n\n### Outbound TCP/UDP connections to the internet\n\nAn example of an outbound TCP/UDP connection to the internet\nis when a container downloads a file from a\nweb server on the internet.\n\n| method | native performance |\n|-|-|\n| pasta | |\n| slirp4netns | |\n| host | :heavy_check_mark: |\n\n## Outbound TCP/UDP connections to the host's localhost\n\nAn example of an outbound TCP/UDP connection to the host's localhost\nis when a container downloads a file from a web server on the host that\nlistens on 127.0.0.1:80.\n\n| method | outbound TCP/UDP connection to the host's localhost | comment |\n|-|-|-|\n| pasta |:heavy_check_mark: | enable with one of the pasta options `--map-gw`, `--map-host-loopback` or `--tcp-ns` (`-T`) |\n| slirp4netns |:heavy_check_mark: | enable with the slirp4netns option `allow_host_loopback=true` |\n| host | :heavy_check_mark: | |\n\nConnecting to the host's localhost is not enabled by default for _pasta_ and _slirp4netns_ due to security reasons.\nSee network mode [`host`](#host) as to why access to the host's localhost is considered insecure.\n\nScenario: allow curl in a container to connect to a web server on the host that listens on 127.0.0.1:8080\n\n#### example: connect to host's localhost using slirp4netns\n\nAdd the slirp4netns option `allow_host_loopback=true`\n\n```\npodman run --rm \\\n           --network=slirp4netns:allow_host_loopback=true \\\n           registry.fedoraproject.org/fedora curl 10.0.2.2:8080\n```\n\nThe IP address `10.0.2.2` is a special address used by slirp4netns.\n\n#### example: connect to host's localhost using the pasta option `--map-gw`\n\nAdd the pasta option `--map-gw` and connect to `10.0.2.2:8080`\n\n```\npodman run --rm \\\n           --network=pasta:--map-gw \\\n           registry.fedoraproject.org/fedora curl 10.0.2.2:8080\n```\n\nThe IP address `10.0.2.2` is a special address used by pasta.\n\n#### example: connect to host's localhost using the pasta option `--map-host-loopback`\n\nAdd the pasta option `--map-host-loopback=11.11.11.11` and connect to _11.11.11.11:8080_.\nThe IP address _11.11.11.11_ was chosen arbitrarily.\n\n```\npodman run -ti --rm --network=pasta:--map-host-loopback=11.11.11.11 docker.io/library/fedora curl -s -4 11.11.11.11:8080\n```\n\n#### example: connect to host's localhost using the pasta option `--tcp-ns` (`-T`)\n\nFor better performance and security, pasta offers an alternative to using `--map-gw`.\nThe option `-T` (`--tcp-ns`) configures TCP port forwarding from the container network namespace to the init network namespace.\n\n```\npodman run --rm \\\n           --network=pasta:-T,8081:8080 \\\n           registry.fedoraproject.org/fedora curl 127.0.0.1:8081\n```\n\n(Instead of the port number 8081, it would also have been possible to specify the port number 8080)\n\nFor more information about how to use pasta to connect to a service running on the host, see [GitHub comment](https://github.com/containers/podman/issues/22653#issuecomment-2108922749).\n\n## Outbound TCP/UDP connections to the host's main network interface (e.g eth0)\n\nAn example of an outbound TCP/UDP connection to the host's main network interface\nis when a container downloads a file from a web server that\nlistens on the host's main network interface.\n\n| method | outbound TCP/UDP connection to the host's main network interface | comment |\n|-|-|-|\n| pasta | :heavy_check_mark: | Connect to _host.containers.internal_ or _host.docker.internal_ or a hostname set with `--add-host=example.com:host-gateway`. Requires podman 5.3.0. For earlier Podman versions, try to set pasta option `--map-guest-addr` (see [Documentation relevant to older Podman versions](#documentation-relevant-to-older-podman-versions)) |\n| slirp4netns | :heavy_check_mark: | |\n| host | :heavy_check_mark: | |\n\nTo try this out, first start a web server that listens on the IP address of the host's main network interface.\n\n\u003cdetails\u003e\n  \u003csummary\u003eStart a web server that listens on host's main network interface: Click me\u003c/summary\u003e\n\nCheck the IP address of the host\n\n1. To show the IP address of the host's main network interface, run the command\n   ```\n   hostname -I\n   ```\n   The following output is printed\n   ```\n   192.168.10.108 192.168.122.1 192.168.39.1 fd25:c7f8:948a:0:912d:3900:d5c4:45ad\n   ```\n   __result:__  The IP address of the host's main network interface is 192.168.10.108. (The first listed IP address)\n\nStart the web server\n\n__Alternative 1__\n\nRequirement: Python3 installed on the host\n\n1. `sudo useradd user1`\n3. `sudo machinectl shell --uid=user1`\n4. `mkdir ~/emptydir`\n5. `cd ~/emptydir`\n6. Run the command\n   ```\n   python3 -m http.server 8080 --bind 192.168.10.108\n   ```\n   Note, the previously detected IP address of the host's main network interface was given as value to the __--bind__ option.\n\n__Alternative 2__\n\nRun a socket-activated nginx container with rootless podman.\n\nRequirement: Podman installed on the host\n\n1. `sudo useradd user1`\n2. `sudo machinectl shell --uid=user1`\n3. `mkdir -p ~/.config/systemd/user`\n4. `mkdir -p ~/.config/containers/systemd`\n5. Create the file _~/.config/systemd/user/nginx.socket_ containing\n   ```\n   [Unit]\n   Description=Example\n   \n   [Socket]\n   ListenStream=192.168.10.108:8080\n   \n   [Install]\n   WantedBy=sockets.target\n   ```\n   Note, `192.168.10.108` is the previously detected IP address of the host's main network interface.\n   It is used in the value for the directive `ListenStream`.\n6. Create the file _~/.config/containers/systemd/nginx.container_ containing\n   ```\n   [Unit]\n   Requires=nginx.socket\n   After=nginx.socket\n   \n   [Container]\n   Image=ghcr.io/nginxinc/nginx-unprivileged\n   Environment=NGINX=3;\n   Network=none\n   Volume=%h/nginx_conf_d:/etc/nginx/conf.d:Z\n   [Install]\n   WantedBy=default.target\n   ```\n7. Create a directory that will be bind-mounted to _/etc/nginx/conf.d_ in the container\n   ```\n   $ mkdir $HOME/nginx_conf_d\n   ```\n8. Create the file _$HOME/nginx_conf_d/default.conf_ with the contents\n   ```\n   server {\n       listen 192.168.10.108:8080;\n       server_name example.com;\n       location / {\n\t   root   /usr/share/nginx/html;\n\t   index  index.html index.htm;\n       }\n       error_page   500 502 503 504  /50x.html;\n       location = /50x.html {\n\t   root   /usr/share/nginx/html;\n       }\n   }\n   ```\n   The file contents were created with the command\n   ```\n   podman run --rm ghcr.io/nginxinc/nginx-unprivileged /bin/bash -c 'cat /etc/nginx/conf.d/default.conf | grep -v \\# | sed \"s/listen\\s\\+8080;/listen 192.168.10.108:8080;/g\" | sed \"s/  localhost/ example.com/g\" | sed /^[[:space:]]*$/d' \u003e default.conf\n   ```\n   Note, `192.168.10.108` is the previously detected IP address of the host's main network interface.\n   The IP address is used in the value for the nginx configuration directive `listen`.\n9. Reload the systemd user manager\n   ```\n   systemctl --user daemon-reload\n   ```\n10. Enable linger for the current user (_user1_)\n    ```\n    loginctl enable-linger\n    ```\n11. Pull the container image\n    ```\n    podman pull ghcr.io/nginxinc/nginx-unprivileged\n    ```\n12. Start the socket\n    ```\n    systemctl --user start nginx.socket\n    ```\n11. `exit`\n\n\u003c/details\u003e\n\n#### example: connect to host's main network interface using slirp4netns\n\nThis example shows that `--network slirp4netns` allows a container to connect to a port on the host's main network interface.\n\n\u003cdetails\u003e\n  \u003csummary\u003eClick me\u003c/summary\u003e\n\nRun curl to access the web server\n\n1. `sudo useradd user2`\n2. `sudo machinectl shell --uid=user2`\n3. `podman pull docker.io/library/fedora`\n4. Run the command\n   ```\n   podman run --rm --network slirp4netns docker.io/library/fedora curl -s -4 192.168.10.108:8080 | head -4\n   ```\n   The following output is printed\n   ```\n   \u003c!DOCTYPE html\u003e\n   \u003chtml\u003e\n   \u003chead\u003e\n   \u003ctitle\u003eWelcome to nginx!\u003c/title\u003e\n   ```\n   Note, `192.168.10.108` is the previously detected IP address of the host's main network interface.\n5. `exit`\n6. `sudo machinectl shell --uid=user1`\n7. Check the nginx logs\n   ```\n   journalctl --user -q -xeu nginx.service | tail -1\n   ```\n   The following output is printed\n   ```\n   Aug 19 18:22:00 fcos systemd-nginx[16328]: 192.168.10.108 - - [19/Aug/2024:18:22:00 +0000] \"GET / HTTP/1.1\" 200 615 \"-\" \"curl/8.6.0\" \"-\"\n   ```\n  _192.168.10.108_ is the IP address of the host's main network interface.\n\n\u003c/details\u003e\n\n#### example: connect to host's main network interface using pasta\n\nThis example shows that pasta allows a container to connect to a port on the host's main network interface\nby connecting to _host.containers.internal_, _host.docker.internal_ or to a custom hostname that is set with `--add-host=example.com:host-gateway`.\nThe example requires Podman 5.3.0 or later.\n\n\u003cdetails\u003e\n  \u003csummary\u003eClick me\u003c/summary\u003e\n\nTo connect to  _example.com_, add `--add-host=example.com:host-gateway`\n\n```\n$ podman run --rm --add-host=example.com:host-gateway fedora curl -4 -s example.com:8080 | head -4\n\u003c!DOCTYPE html\u003e\n\u003chtml\u003e\n\u003chead\u003e\n\u003ctitle\u003eWelcome to nginx!\u003c/title\u003e\n```\n\nThe web page was downloaded from an nginx server that listens on the host's main network interface.\n\nUsing a custom network works too.\n\n```\n$ podman network create mynet\n$ podman run --rm --network mynet --add-host=example.com:host-gateway fedora curl -4 -s example.com:8080 | head -4\n\u003c!DOCTYPE html\u003e\n\u003chtml\u003e\n\u003chead\u003e\n\u003ctitle\u003eWelcome to nginx!\u003c/title\u003e\n```\n\nInstead of setting a hostname with `--add-host=example.com:host-gateway` you could also connect to\n_host.containers.internal_ or _host.docker.internal_. Podman adds those hostnames by default to\n_/etc/hosts_ in the container.\n\n```\n$ podman run --rm fedora cat /etc/hosts | grep host.containers.internal\n169.254.1.2\thost.containers.internal host.docker.internal\n```\n\n```\n$ podman run --rm --add-host=example.com:host-gateway fedora cat /etc/hosts | grep -E 'example.com|host.containers.internal'\n169.254.1.2\texample.com\n169.254.1.2\thost.containers.internal host.docker.internal\n```\n\n\u003c/details\u003e\n\n## Connecting to Unix socket on the host\n\n| method | description |\n|-|-|\n| systemd directive `OpenFile=` | The executed command in the container inherits a file descriptor to an already opened file. |\n| bind-mount, (--volume ./dir:/dir:Z ) | Standard way |\n\nThe systemd directive [`OpenFile=`](https://www.freedesktop.org/software/systemd/man/systemd.service.html#OpenFile=) was introduced in __systemd 253__ (released February 2023).\n\nSee also\nhttps://github.com/eriksjolund/podman-OpenFile\n\n# Description of the different methods\n\n## Socket activation (systemd user service)\n\nThis method can only be used for container images that has software that supports socket activation.\n\nSocket activation of a systemd user service is set up by creating two files\n\n* _~/.config/systemd/user/example.socket_\n\nand either a Quadlet file\n\n* _~/.config/containers/systemd/example.container_\n\nor a service unit\n\n* _~/.config/systemd/user/example.service_\n\nSee [Socket activation](https://github.com/containers/podman/blob/main/docs/tutorials/socket_activation.md#example-socket-activated-echo-server-container-in-a-systemd-service)\n\n### Add socket activation support by preloading libsdsock with LD_PRELOAD\n\nStatus: experimental\n\nIs it possible to use _socket activation_ when the executable in the container does not support _socket activation_?\n\nYes, sometimes.\nIf the executable in the container is dynamically linked, it might be possible to preload the library [__libsdsock__](https://github.com/ryancdotorg/libsdsock)\nto add support for _socket activation_.\n\nThe container unit needs to set the environment variables `LD_PRELOAD` and `LIBSDSOCK_MAP`\n\n```\nEnvironment=LD_PRELOAD=/usr/local/lib/libsdsock.so\nEnvironment=LIBSDSOCK_MAP=tcp://0.0.0.0:8080=myweb.socket\n```\nThe container needs to have the systemd libraries (RPM package: systemd-libs) and the file /usr/local/lib/libsdsock.so installed.\n\nSee [example: pasta + custom network + socket activation + libsdsock - source address preserved](#example-pasta--custom-network--socket-activation--libsdsock---source-address-preserved)\n\n## Socket activation (systemd system service with `User=`)\n\nSystemd system service (`User=`) and socket activation makes it possible for rootless Podman to use privileged ports.\n\nFor details of how to use socket-activated nginx, see for instance\nExample 3, Example 4, Example 5, Example 6 in the repo https://github.com/eriksjolund/podman-nginx-socket-activation\n\n:warning: How well this solution works is currently unknown. What are the pros and cons? Will it work for other software than nginx? More testing is needed.\n\nThere is a [Podman feature request](https://github.com/containers/podman/discussions/20573)\nfor adding Podman support for `User=` in systemd system services.\nThe feature request was moved into a GitHub discussion.\n\n## Pasta\n\nPasta is enabled by default if no `--network` option is provided to `podman run`.\nPasta is generally the better choice because it is often faster and has more features than slirp4netns.\n\nOn RPM-based systems the executable pasta is in the _passt_ RPM package.\n\nShow the RPM package for the executable `/usr/bin/pasta`\n```\n$ rpm -qf --queryformat \"%{NAME}\\n\" /usr/bin/pasta\npasst\n```\nThe RPM package _passt-selinux_ contains the SELinux configuration for pasta.\n\nTo install pasta on Fedora run\n\n```\n$ sudo dnf install -y passt passt-selinux\n```\n\nSee the [`--network`](https://docs.podman.io/en/latest/markdown/podman-run.1.html#network-mode-net) option.\nSee also the pasta web page https://passt.top/\n\n\n### Show the default rootlessNetworkCmd\n\nPasta is the default rootlessNetworkCmd since Podman 5.0.0 (released March 2024).\n\nTo show the rootlessNetworkCmd that is configured to be used by default, run\n\n```\npodman info -f '{{.Host.RootlessNetworkCmd}}'\n```\n\nIf __jq__ is installed on the computer, then the same result is produced with\n\n```\npodman info -f json | jq -r .host.rootlessNetworkCmd\n```\n\nIf __podman info__ does not support the field `RootlessNetworkCmd`, then\nit's possible to find out the information by running\n\n```\npodman run -d --rm -p 12345 docker.io/library/alpine sleep 300\n```\nand observing if the helper process is `pasta` or `slirp4netns`.\n\nFor details:\n\n\u003cdetails\u003e\n  \u003csummary\u003eClick me\u003c/summary\u003e\n\n1. Set the shell variable `user` to a username that is not in use.\n   ```\n   user=mytestuser\n   ```\n1. Create the new user\n   ```\n   sudo useradd $user\n   ```\n1. Open a shell for the new user\n   ```\n   sudo machinectl shell --uid $user\n   ```\n1. Verify that no pasta processes are running as the new user.\n   ```\n   pgrep -u $USER pasta -l\n   ```\n   The command should not list any processes.\n1. Verify that no slirp4netns processes are running as the new user.\n   ```\n   pgrep -u $USER slirp4netns -l\n   ```\n   The command should not list any processes.\n1. Run container\n   ```\n   podman run -d --rm -p 12345 docker.io/library/alpine sleep 300\n   ```\n   (12345 is just an arbitrary container port number)\n1. Check if there are any pasta processes running as the new user.\n   ```\n   pgrep -u $USER pasta -l\n   ```\n   If the command lists any processes, then pasta is detected as being the default.\n1. Check if there are any slirp4netns processes running as the new user.\n   ```\n   pgrep -u $USER slirp4netns -l\n   ```\n   If the command lists any processes, then slirp4netns is detected as being the default.\n1. Exit the shell\n   ```\n   exit\n   ```\n1. Optional step: Delete the newly created user\n\n\u003c/details\u003e\n\n### Publish container ports with pasta\n\n#### example:  use `podman run` option `-p`\n\nThe __podman run__ option [`-p`](https://docs.podman.io/en/latest/markdown/podman-run.1.html#publish-p-ip-hostport-containerport-protocol) (`--publish`) publishes\na container's port, or a range of ports, to the host.\n\nThis example shows that if __podman run__ is given `-p 8080:80`, then podman starts _pasta_ with the argument  `-t 8080-8080:80-80` (which is equivalent to `-t 8080:80`)\n\n\u003cdetails\u003e\n  \u003csummary\u003eClick me\u003c/summary\u003e\n\n1. Run an nginx container and publish container port 80 to host port 8080\n   ```\n   podman run -p 8080:80 \\\n              -d \\\n              --rm \\\n              --name test \\\n              docker.io/library/nginx\n   ```\n2. Fetch a web page with curl\n   ```\n   curl -s http://localhost:8080 | head -4\n   ```\n   The command prints the following output\n   ```\n   \u003c!DOCTYPE html\u003e\n   \u003chtml\u003e\n   \u003chead\u003e\n   \u003ctitle\u003eWelcome to nginx!\u003c/title\u003e\n   ```\n3. Check command-line arguments of the pasta process\n   ```\n   pgrep -l -a pasta\n   ```\n   The command prints the following output\n   ```\n   851253 /usr/bin/pasta --config-net -t 8080-8080:80-80 --dns-forward 169.254.0.1 -u none -T none -U none --no-map-gw --quiet --netns /run/user/1004/netns/netns-830a424a-0592-361f-556b-7bef910405cf\n   ```\n   __result__: pasta was started with the option `-t 8080-8080:80-80` which is equivalent with `-t 8080:80`\n4. Remove container\n   ```\n   podman container rm -t0 -f test\n   ```\n\n\u003c/details\u003e\n\n#### example: use pasta option `-t` to publish a port\n\nAlthough ports are usually published by providing the __podman run__ option  [`-p`](https://docs.podman.io/en/latest/markdown/podman-run.1.html#publish-p-ip-hostport-containerport-protocol) (`--publish`) , this example shows that passing `--network pasta:-t,8080:80` is roughly equivalent to passing `-p 8080:80`\n\n\u003cdetails\u003e\n  \u003csummary\u003eClick me\u003c/summary\u003e\n\n1. Run an nginx container and publish container port 80 to host port 8080\n   ```\n   podman run --network pasta:-t,8080:80 \\\n              --rm \\\n              -d \\\n              --name test \\\n              docker.io/library/nginx\n   ```\n2. Fetch a web page with curl\n   ```\n   curl -s http://localhost:8080 | head -4\n   ```\n   The command prints the following output\n   ```\n   \u003c!DOCTYPE html\u003e\n   \u003chtml\u003e\n   \u003chead\u003e\n   \u003ctitle\u003eWelcome to nginx!\u003c/title\u003e\n   ```\n3. Check command-line arguments of the pasta process\n   ```\n   pgrep -l -a pasta\n   ```\n   The command prints the following output\n   ```\n   851253 /usr/bin/pasta --config-net -t 8088-8088:80-80 --dns-forward 169.254.0.1 -u none -T none -U none --no-map-gw --quiet --netns /run/user/1004/netns/netns-830a424a-0592-361f-556b-7bef910405cf\n   ```\n   __result__: pasta was started with the option `-t 8088-8088:80-80` which is equivalent with `-t 8088:80`\n4. Remove container\n   ```\n   podman container rm -t0 -f test\n   ```\n\n\u003c/details\u003e\n\n#### example: use pasta option `-t auto` to let pasta detect listening sockets\n\nLet pasta check once a second for new listening sockets (TCP or UDP) in the container and automatically publish them.\nUse `--network=pasta:-t,auto`\n\n\u003cdetails\u003e\n  \u003csummary\u003eClick me\u003c/summary\u003e\n\n1. Create directory _dir_\n\n1. Create the file _dir/Containerfile_ with the contents\n   ```\n   FROM docker.io/library/fedora\n   RUN dnf -y install iproute nmap-ncat\n   ```\n1. Build the container image\n   ```\n   podman build -t ncat dir/\n   ```\n1. Run `nc -l 1234` in the container (but first wait 60 seconds)\n   ```\n   podman run --network=pasta:-t,auto \\\n              --rm \\\n              -d \\\n              --name test \\\n              localhost/ncat bash -c \"sleep 60 \u0026\u0026 nc -l 1234 \u0026\u0026 sleep inf\"\n   ```\n   The container starts listening on port 1234 after a delay of 60 seconds. The delay\n   is added to demonstrate that pasta will detect that a listening socket is created while\n   the container is running.\n1. Check if the listening TCP port 1234 has been published on the host\n   ```\n   $ ss -tlnp \"sport = 1234\"\n   State                   Recv-Q                  Send-Q                                   Local Address:Port                                    Peer Address:Port                  Process\n   ```\n   __result:__ No\n1. Wait 60 seonds and check again if the listening TCP port 1234 has been published on the host\n   ```\n   $ ss -tlnp \"sport = 1234\"\n   State                   Recv-Q                  Send-Q                                   Local Address:Port                                    Peer Address:Port                  Process\n   LISTEN                  0                       128                                            0.0.0.0:1234                                         0.0.0.0:*                      users:((\"pasta\",pid=2644,fd=146))\n   ```\n   __result:__ Yes. After 60 seconds `nc` in the container started listening on TCP port 1234. Pasta detected this and published TCP port 1234 on the host.\n1. Remove container\n   ```\n   podman container rm -t0 -f test\n   ```\n\n\u003c/details\u003e\n\n__Side note__: Pasta does not publish TCP ports below [ip_unprivileged_port_start](https://github.com/eriksjolund/podman-networking-docs#configure-ip_unprivileged_port_start).\n\n### Pasta documentation links\n\nGitHub comments:\n\n* [GitHub issue](https://github.com/containers/podman/issues/23883) mentions that the performance of pasta can be improved by adding the option `-o mtu=65520`  to the __podman network create__ command.\n\n* [GitHub comment](https://github.com/containers/podman/discussions/22943#discussioncomment-9795883) with a diagram of how pasta sets up custom networks.\n  The diagram shows an example similar to this\n  ```\n  podman network create mynet1\n  podman network create mynet2\n  podman run --network mynet1 --name container1 ...\n  podman run --network mynet1 --network mynet2 --name container2 ...\n  podman run --network mynet2 --name container4 ...\n  ```\n* [GitHub comment](https://github.com/containers/podman/issues/19213#issuecomment-1979948655) Comparing the design of pasta and slirp4netns regarding the use of NAT\n\nTalks:\n\n* March 2023 [_passt \u0026 pasta: Modern unprivileged networking for containers and VMs_](https://www.youtube.com/watch?v=QMUEtEt1i3I) from conference _Everything Open_ Melbourne, Australia.\n* June 2023 [_Root is less: container networks get in shape with pasta - DevConf.CZ_](https://devconfcz2023.sched.com/event/1MYld/root-is-less-container-networks-get-in-shape-with-pasta) video: [youtube](https://www.youtube.com/watch?v=tlxDmUPc4WY), slides: [pdf](https://static.sched.com/hosted_files/devconfcz2023/b5/pasta_devconf.pdf)\n* June 2024 [_Podman networking deep dive - DevConf.CZ_](https://pretalx.com/devconf-cz-2024/talk/BVM77L/) video: [youtube](https://youtu.be/MCY6APZ4x3A?si=Pp64Vcpa8l3qmfm-\u0026t=1180), slides: [pdf](https://pretalx.com/media/devconf-cz-2024/submissions/BVM77L/resources/Devconf.cz_podman_networking_rQ3aMf1.pdf)\n\n## Slirp4netns\n\nSlirp4netns is similar to Pasta but is slower and has less functionality.\nSlirp4netns was the default rootlessNetworkCmd before Podman 5.0.0 (released March 2024).\n\nThe two port forwarding modes allowed with slirp4netns are described in \nhttps://news.ycombinator.com/item?id=33255771\n\nSee the [`--network`](https://docs.podman.io/en/latest/markdown/podman-run.1.html#network-mode-net) option.\n\n## Host\n\n:warning: Using `--network=host` is considered insecure.\n\nQuote from [podman run man page](https://docs.podman.io/en/latest/markdown/podman-run.1.html#network-mode-net):\n_\"The host mode gives the container full access to local system services such as D-bus and is therefore considered insecure\"._\n\nSee also the article [_[CVE-2020–15257] Don’t use --net=host . Don’t use spec.hostNetwork_](https://medium.com/nttlabs/dont-use-host-network-namespace-f548aeeef575) that explains why running containers in the host network namespace is insecure.\n\n# Network backends\n\nCheck which network backend is in use\n\n```\n$ podman info --format {{.Host.NetworkBackend}}\nnetavark\n```\n\n## CNI\n\nThe network backend CNI ([Container Network Interface](https://www.cni.dev/)) was removed in Podman 5.0.0.\nThe reasons for replacing CNI with Netavark are described in the article\n[_Podman 4.0's new network stack: What you need to know_](https://www.redhat.com/sysadmin/podman-new-network-stack).\n\n## Netavark\n\n_Netavark_ is the default network backend.\n\n**Example** Create a network and run an nginx container\n\nCreate the network _mynet_\n\n```\n$ podman network create mynet\n```\n\nStart the container __docker.io/library/nginx__ and let it be connected to the network _mynet_\n\n```\n$ podman run -d -q --network mynet docker.io/library/nginx\n19f812cfbb43c022529b84bb9914cda2b16e55ef09c0bc8e937afddfc803f812\n```\n\nCheck the IP address\n\n```\n$ podman container inspect -l --format \"{{(index .NetworkSettings.Networks \\\"mynet\\\").IPAddress}}\"\n10.89.0.2\n```\n\nTry to fetch a web page from nginx\n\n```\n$ curl --max-time 3 10.89.0.2\ncurl: (28) Connection timed out after 3000 milliseconds\n```\n__result:__ curl was not able to connect to the web server\n\nJoin the rootless network namespace used for netavark networking before running the curl command\n\n```\n$ podman unshare --rootless-netns curl --max-time 3 10.89.0.2 | head -4\n\u003c!DOCTYPE html\u003e\n\u003chtml\u003e\n\u003chead\u003e\n\u003ctitle\u003eWelcome to nginx!\u003c/title\u003e\n```\n__result:__ curl fetched the web page.\n\n# Capture network traffic\n\nThe pasta option __--pcap__ enables capturing of network traffic.\n\n__Example__\n\nCapture a curl request with pasta to the file _myfile.pcap_.\nUse `tshark` to analyse the file _myfile.pcap_.\n\n1. Fetch web page from http://podman.io with `curl`\n   ```\n   podman run \\\n      --rm \\\n      --network=pasta:--pcap,myfile.pcap \\\n      docker.io/library/fedora curl http://podman.io\n   ```\n   pasta is configured to capture network traffic to the file _myfile.pcap_\n\n\nBuild tshark container image\n\n\n1. Create directory\n   ```\n   mkdir ctr\n   ```\n1. Create the file _ctr/Containerfile_ with the contents\n   ```\n   FROM docker.io/library/fedora\n   RUN dnf install -y tshark \u0026\u0026 dnf clean all\n   ```\n1. Build container image _tshark_\n   ```\n   podman build -t tshark ctr/\n   ```\n\nShow HTTP host and HTTP method in HTTP requests\n\n1. Use __tshark__ to analyse the file _myfile.pcap_.\n   ```\n   podman run \\\n      --rm\n      -v ./myfile.pcap:/mnt/myfile.pcap:Z,ro \\\n      --user 65534:65534 \\\n      --userns keep-id:uid=65534,gid=65534 \\\n      localhost/tshark \\\n        tshark \\\n          -r /mnt/myfile.pcap \\\n          -T fields \\\n          -e http.host \\\n          -e http.request.method \\\n          -Y http | sort -u\n   ```\n   The command prints the following output\n   ```\n        \n   podman.io    GET\n   ```\n\nShow the destination address of IP packets.\n\n1. Use __tshark__ to analyse the file _myfile.pcap_.\n   ```\n   podman run \\\n      --rm\n      -v ./myfile.pcap:/mnt/myfile.pcap:Z,ro \\\n      --user 65534:65534 \\\n      --userns keep-id:uid=65534,gid=65534 \\\n      localhost/tshark \\\n        tshark \\\n          -r /mnt/myfile.pcap \\\n          -T fields \\\n          -e ip.dst | sort -u\n   ```\n   The command prints the following output\n   ```\n   \n   10.0.2.15\n   169.254.0.1\n   185.199.110.153\n   ```\n2. Look up DNS A record of _podman.io_\n   ```\n   host -t a podman.io\n   ```\n   The command prints the following output\n   ```\n   podman.io has address 185.199.110.153\n   podman.io has address 185.199.111.153\n   podman.io has address 185.199.108.153\n   podman.io has address 185.199.109.153\n   ```\n   The IP address 185.199.110.153 is also\n   seen in the __tshark__ output in step 1.\n\n# HTTP reverse proxy\n\nUse an HTTP reverse proxy that supports socket activation to get better support for preserved source IP address\nin incoming connections.\n\n| software | socket activation support | systemd notify support | comment |\n| --       | --                        | --                     | --      |\n| caddy    | :heavy_check_mark:        | :heavy_check_mark:     | Reloading the caddy configuration does not work (see https://github.com/caddyserver/caddy/issues/6631) |\n| nginx    | :heavy_check_mark:        |                        | Although _socket activation_ works, it is not officially supported by nginx. See feature request https://trac.nginx.org/nginx/ticket/237. |\n| traefik  | :heavy_check_mark:        | :heavy_check_mark:     | Traefik has issues during startup otherwise it works fine after a few seconds. When Traefik starts up Traefik might return HTTP response 404. Traefik sends systemd notify `READY=1` before traefik is ready. See https://github.com/traefik/traefik/issues/7347 |\n\nSee examples:\n\n* https://github.com/eriksjolund/podman-caddy-socket-activation\n* https://github.com/eriksjolund/podman-nginx-socket-activation\n* https://github.com/eriksjolund/podman-traefik-socket-activation\n\n# Troubleshooting\n\n### systemd user service generated from quadlet fails after reboot. Error message `External interface not usable`\n\n__Symptom__\n\nPasta is used. A systemd user service _example.service_ is generated from the podman container unit file _example.container_. Such a file is also called a quadlet file. After a reboot\nthe _example.service_ fails to start. The journal log contains an error message\n\n```\nError: pasta failed with exit code 1:\nExternal interface not usable\n```\n\n__Solution__\n\nThe container needs to start after the systemd system target _network-online.target_ has become active.\n\nsystemd does not support defining dependencies between _systemd system targets_ and _systemd user services_.\n\nThere is a GitHub feature request for adding the functionality:\n\n* https://github.com/systemd/systemd/issues/3312\n\nAs a workaround create a _systemd user service_ that runs `sh -c 'until systemctl is-active network-online.target; do sleep 0.5; done'`\n\nAlternative 1:\n\nUse Podman 5.3.0 or later which includes the file _/usr/lib/systemd/user/podman-user-wait-network-online.service_.\n\n```\n$ grep ExecStart= /usr/lib/systemd/user/podman-user-wait-network-online.service\nExecStart=sh -c 'until systemctl is-active network-online.target; do sleep 0.5; done'\n```\n\nDependencies for that service is added by default by the quadlet generator (`/usr/lib/systemd/user-generators/podman-user-generator`)\nwhen it generates systemd user services from user container units.\n\nAlternative 2:\n\nFor older Podman versions follow these steps:\n\n1. Create directory\n   ```\n   mkdir -p ~/.config/systemd/user/\n   ```\n1. Create the file _~/.config/systemd/user/podman-user-wait-network-online.service_\n   ```\n   curl -o ~/.config/systemd/user/podman-user-wait-network-online.service \\\n     -Ls https://raw.githubusercontent.com/containers/podman/refs/heads/main/contrib/systemd/user/podman-user-wait-network-online.service\n   ```\n2. Add the following lines to the existing file _~/.config/containers/systemd/example.container_ under the `[Unit]` section\n   ```\n   Wants=podman-user-wait-network-online.service\n   After=podman-user-wait-network-online.service\n   ```\n3. Reload the systemd user manager\n   ```\n   systemctl --user daemon-reload\n   ```\n4. Enable _podman-user-wait-network-online.service_\n   ```\n   systemctl --user enable podman-user-wait-network-online.service\n   ```\n\nThe systemd user service _podman-user-wait-network-online.service_ will be in the _activating_ state until the systemd system service _network-online.target_ is active.\n\nTo show the current state of the systemd user service _podman-user-wait-network-online.service_, run the command\n\n```\nsystemctl --user show -P ActiveState podman-user-wait-network-online.service\n```\n\nTo show the current state of the systemd system target _network-online.target_, run the command\n\n```\nsystemctl show -P ActiveState network-online.target\n```\n\nThe output should usually be one of\n\n* `active`\n* `activating`\n\n### Laptop intermittent network connectivity issues. Error message `External interface not usable`\n\n__Symptom__\n\npodman / pasta is currently not prepared for the situation when running containers while traveling with a laptop.\nA wireless network might not always be available while traveling. The network might come and go which\ncauses problems like the error message `External interface not usable`\n\n```\n$ podman run --rm alpine echo hello world\nError: pasta failed with exit code 1:\nExternal interface not usable\n```\nSee also [GitHub discussion thread](https://github.com/containers/podman/discussions/22737)\n\n__Solution 1__\n\nIf network access is not needed, add `--network none`\n\n```\n$ podman run --rm --network none alpine echo hello world\nhello world\n```\n\n__Solution 2__\n\nIf network access is needed, add `--network slirp4netns`\n\n__Side note__: Using `--network host` should also work but it is not recommended due to security reasons.\n\n# Documentation relevant to older Podman versions\n\nDocumentation relevant to Podman 5.2.2 and earlier versions\n\n\u003cdetails\u003e\n  \u003csummary\u003eClick me\u003c/summary\u003e\n\n### About the pasta option __--map-guest-addr__\n\nPodman 5.3.0 or later sets the pasta option __--map-guest-addr__ by default.\n\nIf you are runnning an earlier Podman version, you could try to enable it yourself.\n\nRequirement: passt-0^20240821.g1d6142f or newer. That version was released 21 August 2024.\n\nIn the example Podman 5.2.1 is used. Earlier Podman versions might work too.\n\nThe example shows that `--network=pasta:--map-guest-addr=11.11.11.11` allows a container to connect\nto a port on the host's main network interface by connecting to _11.11.11.11_.\nThe IP address _11.11.11.11_ was chosen arbitrarily.\n\n```\npodman run --rm --network=pasta:--map-guest-addr=11.11.11.11 docker.io/library/fedora curl -s -4 11.11.11.11:8080 | head -4\n```\nThe following output is printed\n```\n\u003c!DOCTYPE html\u003e\n\u003chtml\u003e\n\u003chead\u003e\n\u003ctitle\u003eWelcome to nginx!\u003c/title\u003e\n```\n\nThe web page was downloaded from an nginx server that is listening on TCP port 8080 on the host's main network interface.\nThe IP address _11.11.11.11_ was chosen arbitrarily in the example.\n\nIf you want to use a specific hostname such as _example.com_, run the command\n```\npodman run --rm --network=pasta:--map-guest-addr=11.11.11.11 --add-host example.com:11.11.11.11 docker.io/library/fedora curl -s -4 example.com:8080 | head -4\n```\nThe following output is printed\n```\n\u003c!DOCTYPE html\u003e\n\u003chtml\u003e\n\u003chead\u003e\n\u003ctitle\u003eWelcome to nginx!\u003c/title\u003e\n```\n\n#### example: connect to host's main network interface using pasta and custom network\n\nThis example shows that setting\n```\npasta_options = [\"--map-guest-addr\",\"11.11.11.11\"]\n```\nin the file _containers.conf_ allows containers\nin a custom network to connect to the host's main network interface by\nconnecting to _11.11.11.11_. The IP address _11.11.11.11_ was chosen arbitrarily.\n\nRequirement: passt-0^20240821.g1d6142f or newer. That version was released 21 August 2024.\nIn the example Podman 5.2.1 is used. Earlier Podman versions might work too.\n\n1. Create directory\n   ```\n   mkdir -p ~/.config/containers\n   ```\n2. If the file _~/.config/containers/containers.conf_ does not exist, create the file with the command\n   ```\n   cp /usr/share/containers/containers.conf ~/.config/containers/\n   ```\n3. Check the current `pasta_options` setting\n   ```\n   grep pasta_options ~/.config/containers/containers.conf\n   ```\n   The following output is printed\n   ```\n   #pasta_options = []\n   ```\n4. Edit the file _~/.config/containers/containers.conf_ and\n   replace the line\n   ```\n   #pasta_options = []\n   ```\n   with\n   ```\n   pasta_options = [\"--map-guest-addr\",\"11.11.11.11\"]\n   ```\n   The IP address _11.11.11.11_ was chosen arbitrarily. Remember the IP address because it can\n   be used to for connecting to ports listening on the host's main network interface.\n5. Create a custom network\n   ```\n   podman network create mynet\n   ```\n6. Run `curl` to download a web page from a web server listening on the host's main network interface\n   ```\n   podman run --rm --network=mynet docker.io/library/fedora curl -s -4 11.11.11.11:8080 | head -4\n   ```\n   The following output is printed\n   ```\n   \u003c!DOCTYPE html\u003e\n   \u003chtml\u003e\n   \u003chead\u003e\n   \u003ctitle\u003eWelcome to nginx!\u003c/title\u003e\n   ```\n\n\u003c/details\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feriksjolund%2Fpodman-networking-docs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feriksjolund%2Fpodman-networking-docs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feriksjolund%2Fpodman-networking-docs/lists"}