Podman Compose with rootlessport not working as local user

I tried to use Podman Compose with rootlessport 69 UDP for a TFTP server container as my local user with the id 1000, but it’s not working as I can’t access the port with the client tftp. When I use the user root it’s working as expected.

Thats my compose.yaml file:

---
services:
  tftpd-hpa:
    container_name:netboot_tftpd_hpa
    image: netboot_tftpd_hpa
    ports:
      - 69:69/udp
    volumes:
      - type: bind
        source: "${PWD}/files"
        target: "/var/tftpboot"
        read_only: false
    build:
      context: .
      dockerfile: "${PWD}/compose/netboot-tftpd-hpa"
      args:
        NETBOOT_TFTP_HPA_ALPINE_VERSION: ${NETBOOT_TFTP_HPA_ALPINE_VERSION}

compose/netboot-tftpd-hpa file:

ARG NETBOOT_TFTP_HPA_ALPINE_VERSION
FROM docker.io/library/alpine:${NETBOOT_TFTP_HPA_ALPINE_VERSION}

RUN apk add --update --no-cache tftp-hpa

# Run the TFTP server
ENTRYPOINT ["in.tftpd"]
CMD ["--foreground", "--create", "--verbosity", "3", "--secure", "/var/tftpboot"]

.env file:

NETBOOT_TFTP_HPA_ALPINE_VERSION=3.21.3

I also added the following setting permanently (and rebooted):

# sysctl -p
net.ipv4.ip_unprivileged_port_start = 2

Since I added that setting I also don’t get a warning for port 69 anymore.

When I start my container with podman-compose up -d --build I can see that the port 69 UDP is listed:

# ss -tulpn | grep 69          
udp   UNCONN 0      0                  *:69               *:*    users:(("rootlessport",pid=31841,fd=10))

When I now start tftp 127.0.0.1 and try get hello.txt it’s timing out. Now podman compose down and sudo -ito be root and podman compose up -d --build again will show this port:

# ss -tulpn | grep 69
udp   UNCONN 0      0            0.0.0.0:69         0.0.0.0:*    users:(("conmon",pid=32547,fd=5))

Instead of * with user rootlessport it’s now 0.0.0.0 and conmon. The tftp client can now successfully get the hello.txt file.

I also tried to add the port 69/udp to the firewall:

# firewall-cmd --list-all
public (default, active)
  target: default
  ingress-priority: 0
  egress-priority: 0
  icmp-block-inversion: no
  interfaces: enp5s0
  sources: 
  services: dhcpv6-client ssh
  ports: 69/udp 80/udp 80/tcp 443/tcp 443/udp
  protocols: 
  forward: yes
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules:

…and also stopped the firewall service. But nothing works.

Do you have any idea why it’s not working under Tumbleweed as local user, but only as user root?

The very first obvious step is to check whether you program sees incoming requests.

Half educated guess - when running as root podman forgoes (network) namespace and your program is directly using host networking, while as non-root it forwards traffic between host and container and your program does not like how it is done.

Check logs in your container.

Part of the problem is that tftpd was not logging anything. So today did another test with the official NGINX docker image (without additional configuration in the compose.yaml file) on port 80 and believe it or not, but it’s working flawlessly :face_with_spiral_eyes::grinning:

That being said: It’s all about the tftpd. I tried to run the service with a newly created user and group tftp:tftp, but the service seems to ignore that. I will check for alternatives for the tftpd-hpaservice as I’m tired to get it working. I will come back if I have a solution some $someone can benefit from it.

At least it’s not a Podman issue with rootlessport :+1:

Okay, next step: I used this tftpd-hpa pre-build Docker image on Podman. I followed the simple documentation, but I got these logging messages:

Mar 21 12:24:14 66cc7fa3e298 daemon.notice in.tftpd[10]: RRQ from 10.89.0.27 filename hello.txt
Mar 21 12:24:14 66cc7fa3e298 daemon.warn in.tftpd[10]: tftpd: read(ack): Connection refused

It was still not working, but at least I saw some error messages.

I found out that I had to add network_mode: host to the compose.yaml configuration, but I don’t know why. That mode is considered as insecure and therefore I will have figure out why I had to change that mode at all :face_with_diagonal_mouth:

And this address belongs to … ?

I disabled the network_mode: host again. This time it’s the IP address 10.89.0.28 as can be seen here:

Mar 21 13:49:38 4231b116ce31 daemon.notice in.tftpd[9]: RRQ from 10.89.0.28 filename hello.txt
Mar 21 13:49:38 4231b116ce31 daemon.warn in.tftpd[9]: tftpd: read(ack): Connection refused

Inspecting:

podman network inspect my-netboot_default
[
     {
          "name": "my-netboot_default",
          "id": "088a5518b2407d1ff463f712982a6912da14bd5df936ae6d2e0307398ccc0929",
          "driver": "bridge",
          "network_interface": "podman1",
          "created": "2025-03-21T10:14:10.451212586+01:00",
          "subnets": [
               {
                    "subnet": "10.89.0.0/24",
                    "gateway": "10.89.0.1"
               }
          ],
          "ipv6_enabled": false,
          "internal": false,
          "dns_enabled": true,
          "labels": {
               "com.docker.compose.project": "my-netboot",
               "io.podman.compose.project": "my-netboot"
          },
          "ipam_options": {
               "driver": "host-local"
          },
          "containers": {
               "4231b116ce31d518d7ca6176b9a2c98618e1449047c777cbf61ec922e8f86bce": {
                    "name": "basan_netboot_tftpd_hpa",
                    "interfaces": {
                         "eth0": {
                              "subnets": [
                                   {
                                        "ipnet": "10.89.0.28/24",
                                        "gateway": "10.89.0.1"
                                   }
                              ],
                              "mac_address": "0a:5b:92:41:16:c1"
                         }
                    }
               }
          }
     }
]

…so that’s the container itself:

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0@if4: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP qlen 1000
    link/ether 0a:5b:92:41:16:c1 brd ff:ff:ff:ff:ff:ff
    inet 10.89.0.28/24 brd 10.89.0.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::85b:92ff:fe41:16c1/64 scope link 
       valid_lft forever preferred_lft forever

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.