I need some help if anyone could take the time and has the knowledge:
I’m basically new to podman and namespaces, relatively new to linux and a noob at networking. So figuring this out and getting it to work took many more hours than I would like to admit, but I still have a few problems. I have all my current Quadlets below in the spoiler (seperated by “—”, assume user123 = UID 1000). I am on Bazzite, rootless Podman, which probably makes this even harder.
Spoiler with the Quadlets
[Unit]
Description=Arr-stack pod
[Pod]
PodName=arr-stack
# Network
# Network=vpn-only
# User mapping / I don't fully understand this yet, but the pod does not work without this (maps user id to specified ID inside the containers? So the containers have UID:GID 1000:1000?)
UserNS=keep-id:uid=1000,gid=1000
#
# Homepage Port Mapping
PublishPort=3000:3000
# Jellyfin Port Mapping
PublishPort=8096:8096/tcp
# qBittorrent Port Mapping
PublishPort=8080:8080
#PublishPort=6881:6881
#PublishPort=6881:6881/udp
# Prowlarr Port Mapping
PublishPort=9696:9696
# Flaresolverr Port Mapping
PublishPort=8191:8191
# Radarr Port Mapping
PublishPort=7878:7878
# Sonarr Port Mapping
PublishPort=8989:8989
# Jellyseerr Port Mapping
#PublishPort=8055:5055
#[Install]
# WantedBy=default.target
---
[Unit]
Description=Gluetun Container
# Dependencies
# pod
Wants=arr-stack-pod.service
After=arr-stack-pod.service
Requires=arr-stack-pod.service
PartOf=arr-stack-pod.service
# .pod is probably not quite what I want, but it works and I might as well keep it, in case they change the syntax
Wants=arr-stack.pod
After=arr-stack.pod
Requires=arr-stack.pod
PartOf=arr-stack.pod
[Container]
ContainerName=gluetun
Pod=arr-stack.pod
Image=docker.io/qmcgaw/gluetun:v3
AutoUpdate=registry
# Network
# Network=vpn-only
# UID/GID permissions / root + privileged for networking?
PodmanArgs=--privileged
User=0
Group=0
# Equivalent to cap_add: - NET_ADMIN # one wrong?
AddCapability=NET_ADMIN
AddCapability=CAP_NET_ADMIN
# Required for Gluetun to delete the bridge's default route, but does not work
AddCapability=NET_RAW
AddCapability=CAP_NET_RAW
# Equivalent to "devices: - /dev/net/tun:/dev/net/tun"
AddDevice=/dev/net/tun:/dev/net/tun
# EnvironmentFile=global.env
Timezone=UTC
Environment=TZ=Etc/UTC
# EnvironmentFile=gluetun.env
# Environment=FIREWALL_OUTBOUND_SUBNETS=10.90.0.0/24 / test from a specific podman network
Environment=FIREWALL_INPUT_PORTS=8080
#
Environment=VPN_SERVICE_PROVIDER= <123>
Environment=VPN_TYPE=wireguard
Environment=WIREGUARD_PRIVATE_KEY= <key>
Environment=SERVER_COUNTRIES= <country>
# for now:
Environment=VPN_PORT_FORWARDING=off
#Secret=openvpn_user,type=env,target=OPENVPN_USER
#Secret=openvpn_password,type=env,target=OPENVPN_PASSWORD
#Volume
Volume=/var/home/user123/.config/arr-configs/gluetun:/gluetun:Z
# SecurityLabel=disable
[Service]
Restart=always
#[Install]
#WantedBy=default.target
---
[Unit]
Description=qBittorrent Container
# Dependencies
# pod
Wants=arr-stack-pod.service
After=arr-stack-pod.service
Requires=arr-stack-pod.service
PartOf=arr-stack-pod.service
# .pod is probably not quite what I want, but it works and I might as well keep it, in case they change the syntax
Wants=arr-stack.pod
After=arr-stack.pod
Requires=arr-stack.pod
PartOf=arr-stack.pod
# gluetun
Wants=gluetun.service
After=gluetun.service
Requires=gluetun.service
BindsTo=gluetun.service
# .container is probably not quite what I want, but it works and I might as well keep it, in case they change the syntax
Wants=gluetun.container
After=gluetun.container
Requires=gluetun.container
BindsTo=gluetun.container
[Container]
ContainerName=qbittorrent
Pod=arr-stack.pod
Image=lscr.io/linuxserver/qbittorrent:latest
AutoUpdate=registry
# Network
Network=container:gluetun
# UID/GID permissions / linuxserver images require UID:GID 0:0 at the start; they won't start without it
User=0
Group=0
Environment=PUID=1000
Environment=PGID=1000
# EnvironmentFile=global.env
Timezone=UTC
Environment=TZ=Etc/UTC
# EnvironmentFile=qbittorrent.env
Environment=WEBUI_PORT=8080
# Environtment=TORRENTING_PORT=6881
# Volume :Z (> :z) probably works as well and is saver for configs?
Volume=/var/home/user123/.config/arr-configs/qbittorrent:/config:z
Volume=/var/home/user123/Videos/Downloads:/downloads:z
# Volume=/var/home/user123/Videos/Downloads/completed:/downloads:z,U
# Volume=/var/home/user123/Videos/Downloads/incomplete:/incomplete:z,U
# Volume=/var/home/user123/Videos/Downloads/torrents:/torrents:z,U
[Service]
Restart=always
#[Install]
#WantedBy=default.target
---
[Unit]
Description=Prowlarr Container
# Dependencies
# pod
Wants=arr-stack-pod.service
After=arr-stack-pod.service
Requires=arr-stack-pod.service
PartOf=arr-stack-pod.service
# .pod is probably not quite what I want, but it works and I might as well keep it, in case they change the syntax
Wants=arr-stack.pod
After=arr-stack.pod
Requires=arr-stack.pod
PartOf=arr-stack.pod
# gluetun
Wants=gluetun.service
After=gluetun.service
Requires=gluetun.service
BindsTo=gluetun.service
# .container is probably not quite what I want, but it works and I might as well keep it, in case they change the syntax
Wants=gluetun.container
After=gluetun.container
Requires=gluetun.container
BindsTo=gluetun.container
[Container]
ContainerName=prowlarr
Pod=arr-stack.pod
Image=lscr.io/linuxserver/prowlarr:latest
AutoUpdate=registry
# Network
Network=container:gluetun
# UID/GID permissions / linuxserver images require UID:GID 0:0 at the start; they won't start without it
User=0
Group=0
Environment=PUID=1000
Environment=PGID=1000
# EnvironmentFile=global.env
Timezone=UTC
Environment=TZ=Etc/UTC
# EnvironmentFile=prowlarr.env
Environment=WEBUI_PORT=9696
# Volume
Volume=/var/home/user123/.config/arr-configs/prowlarr:/config:z,U
[Service]
Restart=always
#[Install]
#WantedBy=default.target
---
[Unit]
Description=Sonarr Container
# Dependencies
# pod
Wants=arr-stack-pod.service
After=arr-stack-pod.service
Requires=arr-stack-pod.service
PartOf=arr-stack-pod.service
# .pod is probably not quite what I want, but it works and I might as well keep it, in case they change the syntax
Wants=arr-stack.pod
After=arr-stack.pod
Requires=arr-stack.pod
PartOf=arr-stack.pod
# gluetun
Wants=gluetun.service
After=gluetun.service
Requires=gluetun.service
BindsTo=gluetun.service
# .container is probably not quite what I want, but it works and I might as well keep it, in case they change the syntax
Wants=gluetun.container
After=gluetun.container
Requires=gluetun.container
BindsTo=gluetun.container
[Container]
ContainerName=sonarr
Pod=arr-stack.pod
Image=lscr.io/linuxserver/sonarr:latest
AutoUpdate=registry
# Network
Network=container:gluetun
# UID/GID permissions / linuxserver images require UID:GID 0:0 at the start; they won't start without it
User=0
Group=0
Environment=PUID=1000
Environment=PGID=1000
# EnvironmentFile=global.env
Timezone=UTC
Environment=TZ=Etc/UTC
# EnvironmentFile=sonarr.env
Environment=WEBUI_PORT=8989
# Volume / Disable SecurityLabels due to SMB share, need to look this up
SecurityLabelDisable=true
Volume=/var/home/user123/.config/arr-configs/sonarr:/config:z
Volume=/var/home/user123/Videos/Shows:/tv:z
Volume=/var/home/user123/Videos/Downloads:/downloads:z
[Service]
Restart=always
#[Install]
#WantedBy=default.target
---
[Unit]
Description=Radarr Container
# Dependencies
# pod
Wants=arr-stack-pod.service
After=arr-stack-pod.service
Requires=arr-stack-pod.service
PartOf=arr-stack-pod.service
# .pod is probably not quite what I want, but it works and I might as well keep it, in case they change the syntax
Wants=arr-stack.pod
After=arr-stack.pod
Requires=arr-stack.pod
PartOf=arr-stack.pod
# gluetun
Wants=gluetun.service
After=gluetun.service
Requires=gluetun.service
BindsTo=gluetun.service
# .container is probably not quite what I want, but it works and I might as well keep it, in case they change the syntax
Wants=gluetun.container
After=gluetun.container
Requires=gluetun.container
BindsTo=gluetun.container
[Container]
ContainerName=radarr
Pod=arr-stack.pod
Image=lscr.io/linuxserver/radarr:latest
AutoUpdate=registry
# Network
Network=container:gluetun
# UID/GID permissions / linuxserver images require UID:GID 0:0 at the start; they won't start without it
User=0
Group=0
Environment=PUID=1000
Environment=PGID=1000
# EnvironmentFile=global.env
Timezone=UTC
Environment=TZ=Etc/UTC
# EnvironmentFile=radarr.env
Environment=WEBUI_PORT=7878
# Volume / Disable SecurityLabels due to SMB share
SecurityLabelDisable=true
Volume=/var/home/user123/.config/arr-configs/radarr:/config:z
Volume=/var/home/user123/Videos/Movies:/movies:z
Volume=/var/home/user123/Videos/Downloads:/downloads:z
[Service]
Restart=always
#[Install]
#WantedBy=default.target
---
[Unit]
Description=Flaresolverr Container
# Dependencies
# pod
Wants=arr-stack-pod.service
After=arr-stack-pod.service
Requires=arr-stack-pod.service
PartOf=arr-stack-pod.service
# .pod is probably not quite what I want, but it works and I might as well keep it, in case they change the syntax
Wants=arr-stack.pod
After=arr-stack.pod
Requires=arr-stack.pod
PartOf=arr-stack.pod
# gluetun
Wants=gluetun.service
After=gluetun.service
Requires=gluetun.service
BindsTo=gluetun.service
# .container is probably not quite what I want, but it works and I might as well keep it, in case they change the syntax
Wants=gluetun.container
After=gluetun.container
Requires=gluetun.container
BindsTo=gluetun.container
[Container]
ContainerName=flaresolverr
Pod=arr-stack.pod
Image=ghcr.io/flaresolverr/flaresolverr:latest
AutoUpdate=registry
# Network
Network=container:gluetun
# UID/GID permissions
User=0
Group=0
Environment=PUID=1000
Environment=PGID=1000
# EnvironmentFile=global.env
Timezone=UTC
Environment=TZ=Etc/UTC
# EnvironmentFile=flaresolverr.env
Environment=WEBUI_PORT=8191
Environment=LOG_LEVEL=info
Environment=LOG_HTML=false
Environment=CAPTCHA_SOLVER=none
# Volume=flaresolverr:/app/
[Service]
Restart=always
#[Install]
#WantedBy=default.target
---
[Unit]
Description=Podman - Jellyfin
# Dependencies
# pod
Wants=arr-stack-pod.service
After=arr-stack-pod.service
Requires=arr-stack-pod.service
PartOf=arr-stack-pod.service
# .pod is probably not quite what I want, but it works and I might as well keep it, in case they change the syntax
Wants=arr-stack.pod
After=arr-stack.pod
Requires=arr-stack.pod
PartOf=arr-stack.pod
# gluetun
Wants=gluetun.service
After=gluetun.service
Requires=gluetun.service
BindsTo=gluetun.service
# .container is probably not quite what I want, but it works and I might as well keep it, in case they change the syntax
Wants=gluetun.container
After=gluetun.container
Requires=gluetun.container
BindsTo=gluetun.container
[Container]
ContainerName=jellyfin
Pod=arr-stack.pod
Image=ghcr.io/jellyfin/jellyfin
AutoUpdate=registry
# Network
Network=container:gluetun
# UID/GID permissions / 1000:1000 might work?
User=0
Group=0
Environment=PUID=1000
Environment=PGID=1000
# EnvironmentFile=global.env
Timezone=UTC
Environment=TZ=Etc/UTC
# EnvironmentFile=jellyfin.env
Environment=WEBUI_PORT=8096:8096/tcp
#PublishPort=8096:8096/tcp
#PublishPort=8920:8920
#PublishPort=7359:7359/udp
#PublishPort=1900:1900/udp
# Volume
Volume=/var/home/user123/.config/arr-configs/jellyfin:/config:z
Volume=/var/home/user123/Videos/jellyfin-cache:/cache:z
Volume=/var/home/user123/Videos/Movies:/data/movies:z
Volume=/var/home/user123/Videos/Shows:/data/shows:z
[Service]
# Inform systemd of additional exit status
# SuccessExitStatus=0 143a
Restart=always
TimeoutStartSec=900
#[Install]
# Start by default on boot
#WantedBy=default.target
---
[Unit]
Description=Homepage Dashboard
# Dependencies
# pod
Wants=arr-stack-pod.service
After=arr-stack-pod.service
Requires=arr-stack-pod.service
PartOf=arr-stack-pod.service
# .pod is probably not quite what I want, but it works and I might as well keep it, in case they change the syntax
Wants=arr-stack.pod
After=arr-stack.pod
Requires=arr-stack.pod
PartOf=arr-stack.pod
# gluetun
Wants=gluetun.service
After=gluetun.service
Requires=gluetun.service
BindsTo=gluetun.service
# .container is probably not quite what I want, but it works and I might as well keep it, in case they change the syntax
Wants=gluetun.container
After=gluetun.container
Requires=gluetun.container
BindsTo=gluetun.container
# idk about this?:
After=network-online.target
Wants=network-online.target
# Socket
Wants=podman.socket
After=podman.socket
Requires=podman.socket
[Container]
ContainerName=homepage
Pod=arr-stack.pod
Image=ghcr.io/gethomepage/homepage:latest
AutoUpdate=registry
# Network
Network=container:gluetun
# UID/GID permissions
User=1000
Group=1000
Environment=PUID=1000
Environment=PGID=1000
# EnvironmentFile=global.env
Timezone=UTC
Environment=TZ=Etc/UTC
# EnvirontmentFile=homepage.env
#Environment=LOG_LEVEL=debug
Environment=HOMEPAGE_ALLOWED_HOSTS=gethomepage.dev
#PublishPort=3000:3000
# Podman socket (recommended on Bazzite)
Volume=%t/podman/podman.sock:/var/run/docker.sock:ro
#Volume=/var/run/docker.sock:/run/user/1000/podman/podman.sock:ro
#Volume=/%t/podman/podman.sock:/run/user/1000/podman/podman.sock:ro
# Volume / Config directory
SecurityLabelDisable=true
Volume=%h/apps/homepage:/app/config:Z
Volume=%h/apps/homepage/icons:/app/public/icons:Z
[Service]
Restart=on-failure
TimeoutStartSec=300
#[Install]
#WantedBy=default.target
Questions:
-
- If I use “podman exec <container> ip route” (on e.g. qbittorrent) the default route goes through my actual network interface (actual ip adress) which I very much do not want (or through my killswitch dummy network from my VPN if on, which is better but still not ideal). Is there a way to completely remove my actual network from a container’s eyes? “podman exec <container> ip addr” shows 1 lo (local), 2 my actual network, 4 tun0 from gluetun. The traffic does go through gluetun correctly, but I don’t trust it 100%. Having the containers separated and NOT inside a pod gives the same result, since the containers share the network namespaces from the gluetun container when I do “Network=container:gluetun” (same as just having them in a pod as far as I understand). I tried to also create a podman network without a default gateway, but then gluetun cannot connect to the VPN in the first place.
-
- My setup works but is quite convoluted and probably has many unnecessary lines, so please give me any improvements you see
-
- Is User=1000, Group=1000, even sensible? For example in the homepage container those lines result in the container showing User “1000:1000” (from podman inspect). Would User=0, Group=0 (or no lines since I use UserNS=keep-id in the pod?), which shows as User=root (podman inspect) mean that it has actual root access or just that it is root INSIDE the container?
Thank you in advance for the answers, in case I don’t reply to your comment specifically.


Yes, rootless podman.
Just to see if I understood correctly: So your container is running as 999, and
UserNS=keep-id:uid=999,gid=999maps 999 (the user used inside the container) to the host (in my case 1000). So any files the container creates have their permission set to 1000 and can be read/modified by both the host user (1000) and the container.UserNS=keep-id:uid=999,gid=999ONLY maps the UIDs and does not set the UID of the container.I think I understand now, thanks for the example, that helped.
@Excaliburr Yes, you are right.
Do you have already a single container running with rootless podman?
Your given Arr-Stack seems to me relative complex when you are a beginner with podman.
Probably you could get some experience, when you start with just a single container.
In following posts are my personal quadlet settings for running Portainer, which could be helpful for getting insights of your running containers.
https://docs.portainer.io/start/install-ce/server/podman/linux