🤖

Nginx + Systemd +Github Actionsを用いたローカルGO(Echo)APIをVPSに自動デプロイ

に公開

初めまして!サーバーサイドの勉強をしているもちです。
今回チーム開発をしているときに初めて簡単なCI/CDパイプラインを構築したため、構築手順と遭遇したエラーなどまとめていきたいと思います。

システム構成

  • 開発:ローカル(Mac)
  • ソース管理:GitHub
  • VPS:ubuntu
  • Webサーバー:Nginx(リバースプロキシ)
  • プロセス管理:Systemd
  • CI/CD:GitHub Actions

Part1:VPS環境の構築

自動化をする前に手動で完璧に動作する環境をVPS上に構築します。

Step1:Goアプリの準備とビルド

  1. ソースコードの準備
    githubなどにソースコードを準備しておいてVPSにSSH接続し、GitHubからプロジェクトをクローンします。
Bash
ssh YOUR_USER@YOUR_VPS_IP
cd /path/to/project
git pull origin main

API実行のテストになるGo(echo)のコードを置いておきます。

main.go
package main

import (
       "net/http"
       "github.com/labstack/echo/v4"
)

func main() {
	e := echo.New()
	e.GET("/", func(c echo.Context) error {
		message := "Hello, goApi"
		data := map[string]string{
			"message": message, 
		}
		return c.JSON(http.StatusOK, data)
})
	e.Logger.Fatal(e.Start(":8001"))
}
  1. Goアプリのビルド
    APIのソースコードがあるディレクトリに移動して、go buildで実行ファイルを作成します。-oフラグで出力ファイル名をmy-api(任意の名前)に固定するのがポイントとなります。
Bash
cd /your-goproject-path
go build -v -o my-api .

Step2:systemdでアプリをサービス化

Goアプリが常にバックグラウンドで稼働し、クラッシュしても再起動するようにsystemdに登録をします。

  1. サービスファイルの作成
    sudoでサービス定義ファイルを作成します。
Bash
sudo nano /etc/systemd/system/go-api.service
  1. サービスファイルの内容
    User,Group,WorkingDirectory,ExecStartを自身の環境に合わせてください
ini,TOML
[Unit]
Description=Go Echo API Server
After=network.target

[Service]
User=YOUR_USER
Group=YOUR_USER
WorkingDirectory=/path/to/project/goApi
ExecStart=/path/to/project/goApi/my-api
Restart=always

[Install]
WantedBy=multi-user.target
  1. サービスの有効化と起動
Bash
sudo systemctl daemon-reload
sudo systemctl enable go-api.service
sudo systemctl start go-api.service

これらを実行したのちsudo systemctl status go-api.serviceactive(running)`になっていれば成功です。

Step3:Nginxでリバースプロキシ設定

外部からのアクセス(80番ポート)を、内部で動いているGoアプリ(今回は8001番ポート)に中継させます。

  1. Nginx設定ファイルの作成
Bash
sudo nano /etc/nginx/sites-available/go-api
  1. 設定内容
    /testというパスでAPIを公開する設定です。
Nginx
server {
    listen 80;
    server_name YOUR_DOMAIN_OR_IP;

    location /reference/ {
        # 末尾のスラッシュが重要!
        proxy_pass http://127.0.0.1:8001/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}
  1. 設定の有効化とNginxの再起動
Bash
sudo ln -s /etc/nginx/sites-available/go-api /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx
  1. ファイアウォールの設定
Bash
sudo ufw allow 'Nginx Full'
sudo ufw reload

この時点で、http://YOUR_BOMAIN_OR_IP/test/にアクセスしてAPIが応答すれば、VPS側の設定は完了です。

Part2:GitHub Actionsによるデプロイを自動化

vpsで手動作業でgit pullをしている作業をローカルからgit pushだけで完結するようにします。

Step4:GitHub ActionsとVPSの連携

  1. SSHキーの作成(ローカルPC)
Bash
ssh-keygen -t rsa -b 4096 -f ~/.ssh/github_actions_vps_key -N ""
  1. 公開鍵の登録
    ローカルの公開鍵 (~/.ssh/github_actions_vps_key.pub) の中身を、VPSの~/.ssh/authorized_keysに追記します。
  2. GitHub Secretsの登録
    リポジトリの Settings > Secrets and variables > Actions で、以下の4つのSecretを登録します。
  • GO_HOST: VPSのドメインまたはIP
  • GO_USER: VPSのSSHユーザー名
  • PROJECT_PATH: VPS上のプロジェクトの絶対パス (例: /home/user/project)
  • GO_SSH_PRIVATE_KEY: ローカルの秘密鍵 (~/.ssh/github_actions_vps_key) の中身
  1. sudoのパスワードなしで実行設定(VPS)
    sudo visudoでファイルを開き、末尾に以下を追記します
    YOUR_USER ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart go-api.service

Step5:ワークフローファイルの作成

ローカルPCのプロジェクトルートに.github/workflows/deploy.ymlを作成します

YAML
name: Deploy Go API to VPS

on:
  push:
    branches: [ "main" ]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Deploy to VPS and Restart Service
        uses: appleboy/ssh-action@v1.0.3
        with:
          host: ${{ secrets.GO_HOST }}
          username: ${{ secrets.GO_USER }}
          key: ${{ secrets.GO_SSH_PRIVATE_KEY }}
          script: |
            cd ${{ secrets.PROJECT_PATH }}
            git pull origin main
            cd goApi
            go build -v -o my-api .
            sudo systemctl restart go-api.service
            echo "🚀 Deployment Successful!"

このファイルをgit pushすれば、CI/CDパイプラインの完成です。

Part3:トラブルと対処法

私が構築中に遭遇したトラブルと対処法です

問題1:APIにアクセスすると404 Not Foundになる

  • 症状:http://.../test/にアクセスしてもAPIの応答ではなく、Nginxの404エラーページが表示される
  • 原因:proxy_passの末尾のスラッシュ抜け
  • 調査:Nginxの設定ファイルを確認。proxy_pass http://127.0.0.1:8001となっていた
  • 解決策:/test/の部分を剥がして転送するために、proxy_pass http://127.0.0.1:8001/;のように末尾にスラッシュを追加した。

問題2:GitHub Actionsのgit pullでPermission denied

  • 症状:ワークフローのgit pull origin mainのステップでPermission denied (publickey)エラーが発生して失敗する。
  • 原因:GitHub ActionsからVPSへの接続は成功したが、その後VPSからGitHubへのアクセスが許可されていなかった。
  • 解決策:VPS上で専用のSSHキーを作成し、GitHubリポジトリのDeploy Keyとして公開鍵を登録する必要があった。

問題3:Deploy KeyがGitHub上で無効にされていた

  • 症状:リポジトリのSettingsDeploy keysのメニュー自体が表示されない、または「Disabled by ...」と表示される。
  • 原因:所属しているOrganization全体のセキュリティポリシーで、Deploy Keyの使用が禁止されていた。
  • 解決策:代替案としてPersonal Access Tokenを利用した
    1. 自分のGitHubアカウントでrepo権限を持つPATを発行
    2. VPS上でgitの接続先URLを、トークンを含んだHTTPS形式に変更した。
Bash
git remote set-url origin https://<YOUR_TOKEN>@github.com/ORG/REPO.git

問題4:git pullを手動で実行するとパスフレーズを聞かれる

  • 症状:VPSにログインして手動でgit pullすると、Enter passphrase for key ...と表示され、自動化の妨げになる。
  • 原因:VPSがGitHubに接続する際、パスフレーズ付きのデフォルトキー(~/.ssh/id_rsa)を優先して使おうとしていた。
  • 解決策:~/.ssh/configファイルを作成し、GitHubへの接続にはパスフレーズなしで作成した専用キー(github_deploy_key)を明示的に使うよう設定した。
# ~/.ssh/config の内容
Host github.com
  IdentityFile ~/.ssh/github_deploy_key
舞鶴高専 プログラマーズコミュニティ部

Discussion