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

**URL:** https://discourse.nixos.org/t/what-is-the-correct-way-to-allow-binding-of-port-80-and-443/32037
**Category:** Help
**Created:** [August 22, 2023, 9:04am UTC](https://discourse.nixos.org/t/what-is-the-correct-way-to-allow-binding-of-port-80-and-443/32037 "2023-08-22T09:04:47Z")
**Posts on this page:** 15
**Page:** 1

<div class="post-metadata">

### Author: ![alexnortung](https://discourse.nixos.org/user_avatar/discourse.nixos.org/alexnortung/32/4207_2.png) [@alexnortung](https://discourse.nixos.org/u/alexnortung)
#### Post date: [August 22, 2023, 9:04am UTC](https://discourse.nixos.org/t/what-is-the-correct-way-to-allow-binding-of-port-80-and-443/32037/1 "2023-08-22T09:04:47Z")

</div>

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

```auto
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?

---

<div class="post-metadata">

### Author: ![NobbZ](https://discourse.nixos.org/user_avatar/discourse.nixos.org/nobbz/32/7022_2.png) [@NobbZ](https://discourse.nixos.org/u/NobbZ)
#### Post date: [August 22, 2023, 9:19am UTC](https://discourse.nixos.org/t/what-is-the-correct-way-to-allow-binding-of-port-80-and-443/32037/2 "2023-08-22T09:19:52Z")

</div>

How do you start caddy?

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

[https://search.nixos.org/options?channel=23.05&from=0&size=50&sort=relevance&type=packages&query=services.caddy](https://search.nixos.org/options?channel=23.05&from=0&size=50&sort=relevance&type=packages&query=services.caddy)

---

<div class="post-metadata">

### Author: ![alexnortung](https://discourse.nixos.org/user_avatar/discourse.nixos.org/alexnortung/32/4207_2.png) [@alexnortung](https://discourse.nixos.org/u/alexnortung)
#### Post date: [August 22, 2023, 9:36am UTC](https://discourse.nixos.org/t/what-is-the-correct-way-to-allow-binding-of-port-80-and-443/32037/3 "2023-08-22T09:36:45Z")

</div>

I start it with [devenv](https://devenv.sh/reference/options/#servicescaddyconfig), so it is run by my user (I suppose)

---

<div class="post-metadata">

### Author: ![NobbZ](https://discourse.nixos.org/user_avatar/discourse.nixos.org/nobbz/32/7022_2.png) [@NobbZ](https://discourse.nixos.org/u/NobbZ)
#### Post date: [August 22, 2023, 10:03am UTC](https://discourse.nixos.org/t/what-is-the-correct-way-to-allow-binding-of-port-80-and-443/32037/4 "2023-08-22T10:03:30Z")

</div>

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.

---

<div class="post-metadata">

### Author: ![aJWXSLWNVHRrz](https://discourse.nixos.org/letter_avatar_proxy/v4/letter/a/ea5d25/32.png) [@aJWXSLWNVHRrz](https://discourse.nixos.org/u/aJWXSLWNVHRrz)
#### Post date: [August 22, 2023, 10:42am UTC](https://discourse.nixos.org/t/what-is-the-correct-way-to-allow-binding-of-port-80-and-443/32037/5 "2023-08-22T10:42:56Z")

</div>

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

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`  
and  
`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

---

<div class="post-metadata">

### Author: ![alexnortung](https://discourse.nixos.org/user_avatar/discourse.nixos.org/alexnortung/32/4207_2.png) [@alexnortung](https://discourse.nixos.org/u/alexnortung)
#### Post date: [August 22, 2023, 11:11am UTC](https://discourse.nixos.org/t/what-is-the-correct-way-to-allow-binding-of-port-80-and-443/32037/6 "2023-08-22T11:11:40Z")

</div>

> [@NobbZ](#):
>
> If you run it as your user, you shouldn’t be running it on ports below 1024.

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.

> [@NobbZ](#):
>
> but that it requires `--impure` and therefore is not an option for me

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

---

<div class="post-metadata">

### Author: ![NobbZ](https://discourse.nixos.org/user_avatar/discourse.nixos.org/nobbz/32/7022_2.png) [@NobbZ](https://discourse.nixos.org/u/NobbZ)
#### Post date: [August 22, 2023, 12:18pm UTC](https://discourse.nixos.org/t/what-is-the-correct-way-to-allow-binding-of-port-80-and-443/32037/7 "2023-08-22T12:18:47Z")

</div>

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…

---

<div class="post-metadata">

### Author: ![TLATER](https://discourse.nixos.org/user_avatar/discourse.nixos.org/tlater/32/4257_2.png) [@TLATER](https://discourse.nixos.org/u/TLATER)
#### Post date: [August 22, 2023, 12:37pm UTC](https://discourse.nixos.org/t/what-is-the-correct-way-to-allow-binding-of-port-80-and-443/32037/8 "2023-08-22T12:37:23Z")

</div>

> [@alexnortung](#):
>
> Why shouldn’t I run it on ports below 1024?

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](https://www.freedesktop.org/software/systemd/man/systemd.exec.html#Capabilities) (`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: [NixOS Search](https://search.nixos.org/options?channel=23.05&show=boot.kernel.sysctl&from=0&size=50&sort=relevance&type=packages&query=sysctl)

---

<div class="post-metadata">

### Author: ![gsmlg](https://discourse.nixos.org/user_avatar/discourse.nixos.org/gsmlg/32/12809_2.png) [@gsmlg](https://discourse.nixos.org/u/gsmlg)
#### Post date: [January 20, 2025, 2:21am UTC](https://discourse.nixos.org/t/what-is-the-correct-way-to-allow-binding-of-port-80-and-443/32037/9 "2025-01-20T02:21:31Z")

</div>

May be there is something missing in the `caddy` package.  
Should add like this:

```nix
systemd.services.caddy = {
    serviceConfig = {
      EnvironmentFile = [
        config.sops.templates."caddy.env".path
      ];
      SecureBits = "keep-caps";
      AmbientCapabilities = "CAP_NET_BIND_SERVICE CAP_NET_ADMIN";
      CapabilityBoundingSet = "CAP_NET_BIND_SERVICE CAP_NET_ADMIN";
    };
  };

```

---

<div class="post-metadata">

### Author: ![Mephist0phel3s](https://discourse.nixos.org/user_avatar/discourse.nixos.org/mephist0phel3s/32/30107_2.png) [@Mephist0phel3s](https://discourse.nixos.org/u/Mephist0phel3s)
#### Post date: [January 20, 2025, 2:43am UTC](https://discourse.nixos.org/t/what-is-the-correct-way-to-allow-binding-of-port-80-and-443/32037/10 "2025-01-20T02:43:01Z")

</div>

indeed.

But another option to expand on this tho is NAT, you can setup some NAT rules for your firewall in the nix config to accept connections on port 80/443 and internally redirect to whichever port you want, or visa versa. This would deal with both problems at once without tainting

If not NAT you could also just port forward/redirect to 127.0.0.1

---

<div class="post-metadata">

### Author: ![Nebucatnetzer](https://discourse.nixos.org/user_avatar/discourse.nixos.org/nebucatnetzer/32/5770_2.png) [@Nebucatnetzer](https://discourse.nixos.org/u/Nebucatnetzer)
#### Post date: [January 20, 2025, 9:39am UTC](https://discourse.nixos.org/t/what-is-the-correct-way-to-allow-binding-of-port-80-and-443/32037/11 "2025-01-20T09:39:25Z")

</div>

`—no-pure-eval` is “enough” and there was a PR recently that tried to get rid of the impurity entirely.

However AFAIK it is only needed to get the current working directory in order to set the `DEVEN_ROOT` env variable.

---

<div class="post-metadata">

### Author: ![NobbZ](https://discourse.nixos.org/user_avatar/discourse.nixos.org/nobbz/32/7022_2.png) [@NobbZ](https://discourse.nixos.org/u/NobbZ)
#### Post date: [January 20, 2025, 10:46am UTC](https://discourse.nixos.org/t/what-is-the-correct-way-to-allow-binding-of-port-80-and-443/32037/12 "2025-01-20T10:46:39Z")

</div>

I am aware that things changed in the nearly 2 years since my post.

It still is not fully pure. And despite me knowing what the impure part is used for, it doesn’t change, that the mere existence of `--impure` or `--no-pure-eval` can cause havoc on improperly written `import nixpkgs {}` stuations. Those are not always under your control.

As long as devenv is not usable without pure evaluation, it is simply not an option for me, and I will remain concerned about this fact.

I appreciate its value for other poeple though.

---

<div class="post-metadata">

### Author: ![Nebucatnetzer](https://discourse.nixos.org/user_avatar/discourse.nixos.org/nebucatnetzer/32/5770_2.png) [@Nebucatnetzer](https://discourse.nixos.org/u/Nebucatnetzer)
#### Post date: [January 20, 2025, 11:29am UTC](https://discourse.nixos.org/t/what-is-the-correct-way-to-allow-binding-of-port-80-and-443/32037/13 "2025-01-20T11:29:50Z")

</div>

Ah please excuse I missed the date on your reply.

---

<div class="post-metadata">

### Author: ![nokihe](https://discourse.nixos.org/letter_avatar_proxy/v4/letter/n/e99b99/32.png) [@nokihe](https://discourse.nixos.org/u/nokihe)
#### Post date: [December 14, 2025, 12:30pm UTC](https://discourse.nixos.org/t/what-is-the-correct-way-to-allow-binding-of-port-80-and-443/32037/14 "2025-12-14T12:30:29Z")

</div>

Hi there!

I stumbled upon this thread when looking for a way to do what the title says on my NixOS installation (to allow an ssh client running as my user to forward low ports, nothing to do with “caddy” - no idea what that is..)

To achieve that on my Manjaro installation I just ran this once:  
`sudo setcap 'cap_net_bind_service=+ep' "$(which ssh)"`

On my NixOS this doesn’t work:

> Invalid file ‘/run/current-system/sw/bin/ssh’ for capability operation.

But reading through the thread I found somebody said that running  
`sudo sysctl -w net.ipv4.ip_unprivileged_port_start=0`  
works for him though it does not stick. That’s not optimal but okay for my use case for now.

Would love to have something to write into my `configuration.nix` file that achieves this (permanently) - does something like that exist?

---

<div class="post-metadata">

### Author: ![TLATER](https://discourse.nixos.org/user_avatar/discourse.nixos.org/tlater/32/4257_2.png) [@TLATER](https://discourse.nixos.org/u/TLATER)
#### Post date: [December 14, 2025, 12:36pm UTC](https://discourse.nixos.org/t/what-is-the-correct-way-to-allow-binding-of-port-80-and-443/32037/15 "2025-12-14T12:36:19Z")

</div>

You can do this but it’s still a bad idea. My post further up still applies: [What is the correct way to allow binding of port 80 and 443? - #8 by TLATER](https://discourse.nixos.org/t/what-is-the-correct-way-to-allow-binding-of-port-80-and-443/32037/8)

Caddy is just another server someone wanted to run on a low port. Replace any mentions with caddy with ssh instead and everything here makes sense for your use case.

And, still:

> [@TLATER](#):
>
> 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: [NixOS Search](https://search.nixos.org/options?channel=25.11&query=sysctl)

That points to the [sysctl option](https://search.nixos.org/options?channel=25.11&query=sysctl); you can just set the `sudo sysctl` thing with that instead of doing it in a terminal.
