以其他用户身份在80/443端口运行Golang服务器的实现方法

以其他用户身份在80/443端口运行Golang服务器的实现方法 有什么好方法可以让用Go编写的服务器以非root用户的身份在80/443端口上运行?我可以将其放在nginx后面并使用端口转发,但如果可能的话我宁愿不这样做。我想在Linux系统上实现这个需求。

3 回复

这里有一个很好的解释

更多关于以其他用户身份在80/443端口运行Golang服务器的实现方法的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


谢谢。setcap 看起来是个不错的解决方案。我之前从未听说过它,但它在我的 CentOS 机器上已经安装了。

在Linux系统中,要让Golang服务器以非root用户身份绑定到80或443端口,有几种常见方法。以下是两种主要实现方式:

方法1:使用setcap设置网络权限(推荐)

通过给Go二进制文件设置网络绑定权限,允许非root用户绑定特权端口:

package main

import (
    "fmt"
    "log"
    "net/http"
)

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "服务器运行在80端口,用户:%s", "非root用户")
    })
    
    log.Println("服务器启动在 :80")
    log.Fatal(http.ListenAndServe(":80", nil))
}

编译后设置权限:

# 编译Go程序
go build -o myserver main.go

# 设置网络绑定权限
sudo setcap 'cap_net_bind_service=+ep' myserver

# 以非root用户运行
sudo -u nobody ./myserver

方法2:使用authbind工具

安装并配置authbind:

# 安装authbind
sudo apt-get install authbind  # Ubuntu/Debian
sudo yum install authbind     # CentOS/RHEL

# 配置80端口权限
sudo touch /etc/authbind/byport/80
sudo chmod 500 /etc/authbind/byport/80
sudo chown nobody:nogroup /etc/authbind/byport/80

然后使用authbind运行:

authbind --deep ./myserver

或者直接在代码中指定用户:

sudo -u nobody authbind --deep ./myserver

方法3:使用systemd socket激活

创建systemd服务文件 /etc/systemd/system/myserver.socket

[Unit]
Description=My Go Server Socket

[Socket]
ListenStream=80
Accept=yes

[Install]
WantedBy=sockets.target

创建服务文件 /etc/systemd/system/myserver.service

[Unit]
Description=My Go Server
Requires=myserver.socket

[Service]
Type=simple
User=nobody
Group=nogroup
ExecStart=/path/to/your/myserver
StandardInput=socket

[Install]
WantedBy=multi-user.target

启用服务:

sudo systemctl enable myserver.socket
sudo systemctl start myserver.socket

完整示例代码

package main

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

func main() {
    http.HandleFunc("/", handler)
    
    port := "80"
    if len(os.Args) > 1 {
        port = os.Args[1]
    }
    
    log.Printf("启动服务器在 :%s,用户ID: %d", port, os.Geteuid())
    err := http.ListenAndServe(":"+port, nil)
    if err != nil {
        log.Fatalf("启动失败: %v", err)
    }
}

func handler(w http.ResponseWriter, r *http.Request) {
    user := "unknown"
    if name, err := os.Hostname(); err == nil {
        user = name
    }
    fmt.Fprintf(w, "服务器运行在特权端口\n当前用户UID: %d\n主机: %s", os.Geteuid(), user)
}

setcap方法是最简单直接的解决方案,只需要一次性设置权限,之后就可以普通用户身份运行。编译后的二进制文件保持权限设置,部署时无需额外配置。

回到顶部