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:

    1. 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.
    1. My setup works but is quite convoluted and probably has many unnecessary lines, so please give me any improvements you see
    1. 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.

  • Excaliburr@lemmy.dbzer0.comOP
    link
    fedilink
    English
    arrow-up
    1
    ·
    11 hours ago

    Yes, rootless podman.

    Just to see if I understood correctly: So your container is running as 999, and UserNS=keep-id:uid=999,gid=999 maps 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=999 ONLY 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

      • Excaliburr@lemmy.dbzer0.comOP
        link
        fedilink
        English
        arrow-up
        1
        ·
        2 hours ago

        I’ve been running Docker for various things on Windows before and I’m not a stranger to computers and tech in general, so that’s why I went this deep from the get go. The whole stack works and I’m like 90% sure that it works the way I want it to work, I just want to make it better (and “bullet proof”). I don’t have much experience with networking or Linux, though, so yeah, this was quite the challenge haha. Thanks again for the help, I’ll have a look at your quadlets.

      • [Unit]  
        Description=Container running Portainer container management platform  
        Wants=podman-user-wait-network-online.service  
        After=podman-user-wait-network-online.service  
        After=local-fs.target  
        Requires=podman.socket  
        
        • [Container]  
          AutoUpdate=registry  
          ContainerName=con-portainer  
          HostName=con-portainer  
          Image=docker.io/portainer/portainer-ce:lts  
          Notify=conmon  
          PublishPort=8000:8000  
          PublishPort=9443:9443  
          Pull=missing  
          Volume=vol-portainer:/data  
          Volume=%t/podman/podman.sock:%t/podman/podman.sock  
          
          • [Install]  
            \# Start by default on boot without explicit enabling  
            \# To avoid automatic start Install section has to be  
            \# disabled  
            WantedBy=default.target multi-user.target
            
            [Service]  
            \# Restart service in case of failures  
            Restart=on-failure  
            TimeoutStartSec=20  
            TimeoutStopSec=20  
            Type=notify