Podman Low-Port Publishing and sysctl
`-p 80:80` rootless fails with `pasta failed ... Listen failed for HOST TCP port */80: Permission denied`. One sysctl fixes it, and the failed container is still left behind for you to remove.
Networking Guide 27 of 47 Beginner
- OSUbuntu 26.04 LTS (resolute)
- Podman5.7.0
- Runtimecrun 1.21
- Networknetavark 1.16.1
- TimeAbout 12 min
- Reviewed22 August 2026
Written against the versions above. Podman follows the distribution here rather than a vendor repository, so the version you get is the one Ubuntu shipped. The commands are stable across 5.x.
| Server Name | IP Address | OS | Roles | CPU | RAM | HDD |
|---|---|---|---|---|---|---|
| PODMAN01 | 192.168.0.21 | Ubuntu 26.04 LTS | Primary Container Host | 2 Core | 4 GB | 50 GB |
Before you start
- Podman installed - see guide 1.
sudofor the sysctl. Nothing else here needs it.
-
The refusal, and what it names
The default threshold is the traditional Unix one:
net.ipv4.ip_unprivileged_port_start = 1024So
-p 80:80fails:Error: pasta failed with exit code 1: Listen failed for HOST TCP port */80: Permission denied Couldn't listen on requested TCP portsRead who is complaining: pasta, the userspace network process from guide 53. Publishing a port rootless means pasta opens a listening socket as your user, and your user may not bind below 1024. The container never started; nothing about the image or nginx is involved.
-p 8080:80works immediately, andpodman portconfirms the mapping. This is why every guide on this path publishes a high port.bash Example session sysctl net.ipv4.ip_unprivileged_port_startnet.ipv4.ip_unprivileged_port_start = 1024podman run -d --name low -p 80:80 docker.io/library/nginx:alpineError: pasta failed with exit code 1:Listen failed for HOST TCP port */80: Permission deniedCouldn't listen on requested TCP ports [exit 126]podman run -d --name high -p 8080:80 docker.io/library/nginx:alpinec7cfb4b643d51ebe0a6fecfe1ac7d1f20b068721c2bdbd926fac41edfe3512a7podman port high80/tcp -> 0.0.0.0:8080podman rm -f highhighExpected resultA threshold of 1024, a pasta permission error on port 80, and a working 8080.
Success conditionYou have the exact error and know which process produced it.
-
A failed run still leaves a container
Worth knowing before the next step, because it cost this guide a capture.
The
-p 80:80run failed - but it failed after creating the container's storage and before starting it. So a container namedlowexists, in created state, and the obvious retry gives you:Error: creating container storage: the container name "low" is already in useWhich looks like a completely different problem and sends people looking in the wrong place.
The general lesson:
podman runis not atomic. A failure part-way through can leave a container behind, sopodman ps -ais worth a look after any failed run.--replaceavoids the collision, and is what the next step uses.bash Example session podman ps -a --format 'table {{.Names}} {{.Status}}'NAMES STATUSExpected resultAn empty list, after the leftover container was removed.
Success conditionYou know to check for a leftover container after a failed run.
-
Lower the threshold, and decide whether you should
One sysctl, and
-p 80:80works -podman portshows0.0.0.0:80andcurlreturnshttp=200:sudo sysctl net.ipv4.ip_unprivileged_port_start=80Two things about this that matter more than the command.
It is host-wide. You have not granted Podman anything - you have told the kernel that *every* unprivileged process on this machine may bind ports from 80 up. Any user, any program. On a single-purpose server that is a reasonable trade; on a shared host it is a real reduction in a boundary that exists for a reason.
It does not persist.
sysctlsets the running value only, so a reboot puts it back and your service stops publishing. For anything permanent, a file in/etc/sysctl.d/.The alternatives, roughly in order of how much most people should prefer them:
- Publish a high port and put a reverse proxy in front. The proxy runs as root or has
CAP_NET_BIND_SERVICE, and your containers stay unprivileged. - A rootful container, which has the capability already - at the cost of everything in guide 3.
setcap CAP_NET_BIND_SERVICEon the pasta binary, which is narrower than the sysctl but a package upgrade silently removes it.- The sysctl, which is the simplest and the bluntest.
The threshold was returned to 1024 after this capture.
bash Example session sudo -n sysctl net.ipv4.ip_unprivileged_port_start=80net.ipv4.ip_unprivileged_port_start = 80podman run -d --replace --name low -p 80:80 docker.io/library/nginx:alpinea3d56c6e60581e33065eff8a21ff355bf89bb2ae9f9d3da8c45c2fb30873caaapodman port low80/tcp -> 0.0.0.0:80curl -s -o /dev/null -w 'http=%{http_code}\n' http://localhost:80http=200podman rm -f lowlowsudo -n sysctl net.ipv4.ip_unprivileged_port_start=1024net.ipv4.ip_unprivileged_port_start = 1024Expected resultThe threshold at 80, a container publishing port 80,
http=200, and the threshold restored.Success conditionYou published a privileged port rootless and put the setting back.
- Publish a high port and put a reverse proxy in front. The proxy runs as root or has
Troubleshooting
Listen failed for HOST TCP port */443: Permission denied.Why: Same rule, different port. Anything below the threshold behaves this way.
Fix:Lower the threshold below the port you need, or publish high and proxy.
The sysctl worked yesterday and the service will not start today.
Why: The host rebooted and
sysctldoes not persist.Fix:
echo 'net.ipv4.ip_unprivileged_port_start=80' | sudo tee /etc/sysctl.d/99-podman-ports.conf, thensudo sysctl --system.address already in useon a high port.Why: Something else has it - possibly a container you forgot.
Fix:
podman port -afor Podman's view andss -ltnpfor the rest of the machine.The port binds but nothing outside the host can reach it.
Why: A host firewall, or the port bound only to loopback.
Fix:
podman portshows0.0.0.0if it is on all interfaces. Then checkufw status.