Net bind capability with systemd

Solution 1:

I know this isn't exactly what you wanted and adds "another piece" to the puzzle but you could consider creating a systemd .service file and moving the applications listening port to >1023 (this allows non-root to bind to it), then create an iptables rule that redirects all traffic from port 443 to your new custom port like this:

iptables -t nat -A PREROUTING -i <incoming_interface> -p tcp --dport 443 -j REDIRECT --to-port 8443

In this example, all tcp traffic to port 443 would be transparently redirected to port 8443.

Solution 2:

The reason Solution 1: using a systemd socket doesn't work is that the binary must be built to accept the socket from systemd. It doesn't "just work" unfortunately.

Systemd passes the socket as file descriptor 3 (after stdin, stdout, stderr). Here's an example program (from my blog post here)

package main

import (
    "log"
    "net"
    "net/http"
    "os"
    "strconv"
)

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("Hello World!"))
    })

    if os.Getenv("LISTEN_PID") == strconv.Itoa(os.Getpid()) {
        // systemd run
        f := os.NewFile(3, "from systemd")
        l, err := net.FileListener(f)
        if err != nil {
            log.Fatal(err)
        }
        http.Serve(l, nil)
    } else {
        // manual run
        log.Fatal(http.ListenAndServe(":8080", nil))
    }
}

You would have to ask goldfish to add support.

For the systemd capabilities (Solution 2) I don't know, but could it be that you also need SecureBits=keep-caps ? systemd should set that automatically, but maybe your version of systemd (8 months ago) didn't? Vault uses it: https://learn.hashicorp.com/vault/operations/ops-deployment-guide#step-3-configure-systemd

Another option would be to use SELinux, although that might be a "now you have two problems".

Personally in your situation I think I would put nginx in front of it. What did you end up doing?