Rootless Docker with ports < 1024

Hi there,
I need to make my rootless Docker run a container and expose it on port 80 at ( However I get the following error:

Error response from daemon: driver failed programming external connectivity on endpoint [container name] ([container hash]): Error starting userland proxy: error while calling PortManager.AddPort(): cannot expose privileged port 80, you can add 'net.ipv4.ip_unprivileged_port_start=80' to /etc/sysctl.conf (currently 1024), or set CAP_NET_BIND_SERVICE on rootlesskit binary, or choose a larger port number (>= 1024): listen tcp4 bind: permission denied

So I have tried to set this via security.wrappers like this:

    rootlesskit = { owner = "root";
      group = "root";
      capabilities = "cap_net_bind_service=+ep";
      source = "${pkgs.rootlesskit.out}/bin/rootlesskit";

which did not succeed even if I restarted the docker service both with --user and without. So, how can I achieve this? I cannot just do

 sudo setcap cap_net_bind_service=+ep /nix/store/[hash]-rootlesskit-1.1.0/bin/rootlesskit

because it is read-only. Perhaps this should be added as a config option or are there any solutions/workarounds for that without changing net.ipv4.ip_unprivileged_port_start?

doesn’t docker use nat rules to remap lower port to higher ones internally.

This seems a bit weird to me?

but maybe you’ve got a good reason to give your processes more privileges than they need?

They’re trying to have the host port be port 80 so that the host serves http from the container directly. For this, docker does need permission to bind that port (irrespective of what docker’s internal mapping is).

I’ve not used rootlesskit before, is it in turn started as a daemon by systemd? Could you use the services’ Capabilities= setting to apply CAP_NET_BIND_SERVICE instead?

Another workaround would be to use nginx as a reverse proxy (and give the nginx process CAP_NET_BIND_SERVICE, the nixos module does so by default) that just forwards all requests to a higher port where you can bind this rootless docker service. A bit overly cumbersome for your current use case, but more flexible in the long run.

1 Like

Can you just use boot.kernel.sysctl to set net.ipv4.ip_unprivileged_port_start? That seems like the nix way.

1 Like

Okay, so I will try setting capabilites in service that’s a great idea. Using nginx is also a good idea. Thank you so much! I will update when I try editing Docker service’s capabilities.

Update: Setting capability on service didn’t work. I think it is because that I need to give that capability to rootlesskit not docker. However, I can use nginx for now. It seems to be the most logical option for now. I might create an issue about this on GitHub.

1 Like

Depends on your use case. That will enable random processes to open low ports, which is a security risk. A very small one, to be fair, I think if malicious processes try to overtake your http port by starting before your webserver you have bigger problems, but nonetheless, changing that is explicitly removing security features and not always desirable.

1 Like