What is the correct way to allow binding of port 80 and 443?

Hello , I am working on a web application which uses caddy. By default Caddy want to bind to port 80 and 443, but that is not allowed on NixOS. I could get around this by using the following command

sudo sysctl -w net.ipv4.ip_unprivileged_port_start=0

However after restarting, this value is reset to 1024 again. I guess this could lead to other security problems as well. So my question is, how can I make my own user or all users able to bind to port 80 and 443?

How do you start caddy?

AFAIK services.caddy.* can deal fine with priviliged ports.


I start it with devenv, so it is run by my user (I suppose)

If you run it as your user, you shouldn’t be running it on ports below 1024.

Even though I do not know anything about devenv, but that it requires --impure and therefore is not an option for me, I think it should be possible to make it use some form of privilige (de-)escalation or capability settings and dropping.

wow I just did this for me a few hours ago for the first time (Synchronicity???). So, better take advice from more “PRO” “devoppers” :slight_smile:

but what i did was make the server use ports above 1024, and then i added firewall rules like:

iptables -t nat -I PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports xxxx
iptables -t nat -I PREROUTING -p tcp --dport 443 -j REDIRECT --to-ports yyyy

where of course, ports xxxx and yyyy are the server’s http and https ports

Why shouldn’t I run it on ports below 1024?

But anyway, maybe I should just try to get caddy to run on port 3000 and 3001 or something.

Why is it not an option for you if it uses --impure?

Because --impure is a can of worms, which I do not want to open just to be able to fire up a database.

I have choosen flake as my main way to pin inputs rather than niv or anything else, for the fact that the pure evaluation gives some extra benefits. Using --impure then would just be absurd then…

Good question! Traditionally, those ports are reserved for root. The idea is that, in theory, when the system boots a non-privileged user may be able to start a service a bit more quickly than root, thereby reserving the port for their application before root has a chance to.

This would result in them being able to launch an ssh server or a web server, and take over the respective services. You can imagine how much of a security nightmare this could be if a malicious user does so. Hence, ports < 1024 are reserved for important services like httpd or sshd.

A lot of system security today relies on encapsulating services under different namespaces, which can do exactly the same thing as an unprivileged user, and are only prevented from doing so by this same security feature.

If you want to start caddy on low ports, I’d suggest giving it the capability (CAP_NET_BIND_SERVICE, probably what the NixOS module does too) to do so instead. This also protects caddy from being taken over by a different unprivileged user, which is probably better than running it on high ports.

That said, on a dev machine this sysctl may be totally valid. I’m not your mom, here’s the scissors, don’t tell me I didn’t warn you if you end up running with them: https://search.nixos.org/options?channel=23.05&show=boot.kernel.sysctl&from=0&size=50&sort=relevance&type=packages&query=sysctl

1 Like