使用systemd部署golang web程序

#Golang #systemd

systemd 配置

  1. 编译您的 Golang 程序。假设您的程序名为delicious
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o delicious
  1. 将本地编译好的 myapp 二进制文件、配置文件和静态文件等上传到服务器的/var/www/delicious.yangpeiyuan.com目录下。目录结构如下:
.
|-- config
|   `-- config.toml
|-- delicious
|-- static
|   |-- css
|   |   |-- bulma.css
|   |   `-- style.css
|   |-- favicon.ico
|   `-- imgs
|       |-- apple-touch-icon.png
|       |-- favicon-32x32.png
|       `-- idev.png
`-- templates
    |-- add.html
    |-- close.html
    |-- detail.html
    |-- footer.html
    |-- head.html
    |-- index.html
    |-- login.html
    `-- partial.html
  1. /usr/lib/systemd/system/ 创建一个新的 systemd 服务文件:
sudo vim /usr/lib/systemd/system/delicious.service

在打开的编辑器中,添加以下内容:

[Unit]
Description=My Golang Web Application
After=network.target

[Service]
ExecStart=/var/www/delicious.yangpeiyuan.com/delicious
Restart=always
User=nobody
Group=nogroup
Environment="GO_ENV=production"
WorkingDirectory=/var/www/delicious.yangpeiyuan.com

[Install]
WantedBy=multi-user.target

对于 Golang 程序的 systemd 服务配置,User 和 Group 通常设置如下: 如果是 web 应用或需要网络访问的服务:

Group=www-data

如果是系统级服务或后台程序:

Group=nogroup

如果是特定用户运行的应用:

User=<specific_username>
Group=<specific_groupname>

如果需要 root 权限:

User=root
Group=root

这里需要注意Environment="GO_ENV=production" ,指在 systemd 服务文件设置程序所需的环境变量,以配合 gin 框架的 release 模式

	//设置 Gin 为发布模式
	if models.GetEnvironment() == "production" {
		gin.SetMode(gin.ReleaseMode)
	} else {
		fmt.Println(models.GetEnvironment())
	}

	func GetEnvironment() string {
	env := os.Getenv("GO_ENV")
	if env == "" {
		env = "development"
	}
	return env

}
  1. 依次执行下面的命令
//重新加载systemd
sudo systemctl daemon-reload

//启动服务
sudo systemctl start delicious

//启用服务自动启动
sudo systemctl enable delicious

//检查服务状态
sudo systemctl status delicious

//查看日志 (可选)
sudo journalctl -u delicious

//重启服务
sudo systemctl restart delicious

此时就可以打开浏览器输入http://服务器公网ip:端口查看应用程序的展示效果了。

  1. 如果报错很可能是可执行二进制文件的权限问题。(可选)
//增加二进制文件,可执行权限
sudo chmod +x delicious
  1. 检查日志:重启服务后,立即检查日志以查看是否有新的错误信息:
sudo journalctl -u memory.service -n 50 --no-pager

Nginx 配置

编辑/etc/nginx/sites-available/yangpeiyuan.com.conf

server {
    listen 80;
    server_name delicious.yangpeiyuan.com;

    location / {
        proxy_pass http://localhost:9090;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}

server {
    listen 80;
    server_name memory.yangpeiyuan.com;

    location / {
        proxy_pass http://localhost:9091;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}

server {
    listen 80;
    server_name yangpeiyuan.com www.yangpeiyuan.com;

    location / {
           root /var/www/yangpeiyuan.com;
           index index.html index.htm;
           try_files $uri $uri/ =404;
    }
}
//启用 Nginx 配置。创建一个符号链接到 sites-enabled 目录
sudo ln -s /etc/nginx/sites-available/your_domain /etc/nginx/sites-enabled/
//检查配置文件语法
nginx -t

//重启nginx
sudo systemctl reload nginx

在您的域名注册商的 DNS 设置中,添加 A 记录,将您的域名指向您服务器的 IP 地址。

进阶:使用 GitHub Action

使用 GitHub Action 自动编译和上传到服务器。

name: Build and Deploy

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Set up Go
        uses: actions/setup-go@v3
        with:
          go-version: 1.22.4

      - name: Build
        run: go build -v ./...

      - name: Build binary
        run: GOOS=linux GOARCH=amd64 go build -o delicious

      - name: Prepare static files
        run: |
          mkdir -p deploy/config
          cp -r static/ deploy/static
          cp -r templates/ deploy/templates
          cp config/config.toml deploy/config
          cp delicious deploy/

      - name: Deploy to VPS
        env:
          PRIVATE_KEY: ${{ secrets.SERVER_SSH_KEY }}
          HOST: ${{ secrets.SERVER_HOST }}
          USER: ${{ secrets.SERVER_USER }}
        run: |
          echo "$PRIVATE_KEY" > private_key && chmod 600 private_key
          scp -i private_key -o StrictHostKeyChecking=no -r deploy/* ${USER}@${HOST}:/var/www/deploy/
          ssh -i private_key -o StrictHostKeyChecking=no ${USER}@${HOST} '
            sudo rm -rf /var/www/delicious.yangpeiyuan.com/*
            sudo mv /var/www/deploy/delicious /var/www/delicious.yangpeiyuan.com/
            sudo mv /var/www/deploy/* /var/www/delicious.yangpeiyuan.com/
          '

参考

ruanyifeng 的 Systemd 入门教程:命令篇