2026年7月28日
2026年7月28日
VPSにOpenAPI対応のAPIサーバーを構築する方法|Node.js・Fastify・Swagger UI・Nginx
OpenAPIは、REST APIのエンドポイント、パラメーター、レスポンスの形を記述する仕様です(以前はSwagger仕様と呼ばれていました)。OpenAPIの仕様書があれば、ブラウザで読めるAPIドキュメント(Swagger UI)を表示したり、クライアントのコードを生成したりできます。
この記事では、VPS上に「OpenAPIの仕様書を自動で出力するAPIサーバー」を作ります。Node.jsのWebフレームワーク Fastify と、公式プラグインの @fastify/swagger(仕様書の生成)と @fastify/swagger-ui(ドキュメント画面)を使います。ルートに書いたスキーマから仕様書が作られるので、実装とドキュメントがずれにくい構成です。
想定する環境は2026年10月時点の次のとおりです。
- OS: Ubuntu 24.04 LTS
- Node.js: 24系(LTS)
- Fastify 5系、@fastify/swagger 9系、@fastify/swagger-ui 5系以上
- Webサーバー: Nginx(リバースプロキシとHTTPS)
1. Node.jsをインストールする
Fastify 5はNode.js 20以上が必要です。Ubuntu 24.04の標準リポジトリのNode.jsは18系で要件を満たさないため、NodeSourceのリポジトリから入れます。
sudo apt update
sudo apt install -y curl
curl -fsSL https://deb.nodesource.com/setup_24.x -o nodesource_setup.sh
sudo -E bash nodesource_setup.sh
sudo apt install -y nodejs
node -v
npm -v
NodeSourceの nodejs パッケージには npm も含まれています。Ubuntuの npm パッケージを別に入れると依存関係が衝突するので、apt install npm は実行しません。
2. APIサーバーを作る
アプリケーション用のディレクトリを作り、パッケージを入れます。
sudo mkdir -p /opt/openapi-server
sudo chown $USER:$USER /opt/openapi-server
cd /opt/openapi-server
npm init -y
npm install fastify @fastify/swagger @fastify/swagger-ui
/opt/openapi-server/server.js を次の内容で作ります。
'use strict'
const fastify = require('fastify')({ logger: true })
async function main () {
// OpenAPI ドキュメントの生成(ルート定義より前に登録する)
await fastify.register(require('@fastify/swagger'), {
openapi: {
openapi: '3.0.3',
info: {
title: 'Sample API',
version: '1.0.0'
}
}
})
// Swagger UI を /docs で表示する
await fastify.register(require('@fastify/swagger-ui'), {
routePrefix: '/docs'
})
fastify.get('/hello', {
schema: {
description: 'あいさつを返す',
querystring: {
type: 'object',
properties: {
name: { type: 'string', maxLength: 50 }
}
},
response: {
200: {
type: 'object',
properties: {
message: { type: 'string' }
}
}
}
}
}, async (request) => {
const name = request.query.name || 'World'
return { message: `Hello ${name}!` }
})
const port = Number(process.env.PORT || 3000)
const host = process.env.HOST || '127.0.0.1'
await fastify.listen({ port, host })
}
main().catch((err) => {
fastify.log.error(err)
process.exit(1)
})
ポイントは次のとおりです。
@fastify/swaggerは、ルートより前にawaitを付けて登録する。後から登録したルートは仕様書に載らない- 各ルートの
schemaが、そのまま仕様書のパラメーターとレスポンスになる。querystringのスキーマは入力の検証にも使われ、条件に合わないリクエストには400が返る hostを127.0.0.1にして、外からは直接つながらないようにする(外向きはNginxが受ける)
動作を確かめます。
node server.js
別の端末から次を実行します。
curl "http://127.0.0.1:3000/hello?name=Taro"
# {"message":"Hello Taro!"}
# OpenAPI の仕様書(JSON と YAML)
curl http://127.0.0.1:3000/docs/json
curl http://127.0.0.1:3000/docs/yaml
/docs/json に "openapi":"3.0.3" と /hello の定義が出ていれば成功です。仕様書をファイルとして配りたい場合は curl -s http://127.0.0.1:3000/docs/json > openapi.json で保存できます。確認できたら Ctrl+C で止めます。
3. systemdで常駐させる
アプリケーションを動かす専用のユーザーを作り、systemdのサービスとして登録します。
sudo useradd --system --no-create-home --shell /usr/sbin/nologin apiuser
/etc/systemd/system/openapi-server.service を作ります。
[Unit]
Description=OpenAPI sample server (Fastify)
After=network.target
[Service]
Type=simple
User=apiuser
WorkingDirectory=/opt/openapi-server
Environment=NODE_ENV=production
Environment=HOST=127.0.0.1
Environment=PORT=3000
ExecStart=/usr/bin/node server.js
Restart=on-failure
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now openapi-server
sudo systemctl status openapi-server
# ログの確認
sudo journalctl -u openapi-server -f
apiuser はファイルを読むだけなので、/opt/openapi-server の所有者は作業ユーザーのままでかまいません。コードを更新したら sudo systemctl restart openapi-server で反映します。
4. Nginxでリバースプロキシする
Nginxを入れ、外からのリクエストを 127.0.0.1:3000 に転送します。APIドキュメント(/docs)は誰でも見られる必要がなければ、Basic認証をかけておきます。
sudo apt install -y nginx apache2-utils
# ドキュメント閲覧用のユーザーを作る(パスワードを聞かれる)
sudo htpasswd -c /etc/nginx/.htpasswd-docs docsuser
/etc/nginx/sites-available/openapi-server を作ります。api.example.com は自分のドメインに置き換えます。
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /docs {
auth_basic "API docs";
auth_basic_user_file /etc/nginx/.htpasswd-docs;
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
sudo ln -s /etc/nginx/sites-available/openapi-server /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
ブラウザで http://api.example.com/docs を開き、Basic認証のあとにSwagger UIが表示されれば完成です。画面の「Try it out」から /hello を実際に呼び出せます。
5. ファイアウォールとHTTPS
ufwを使う場合は、SSHとHTTP/HTTPSだけを開けます。Node.jsの3000番は 127.0.0.1 で待ち受けているので、開ける必要はありません。
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable
sudo ufw status
ドメインのDNSがVPSを向いていれば、certbotでLet's Encryptの証明書を取得してHTTPSにできます。
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d api.example.com
Basic認証のパスワードはHTTPSでないと平文で流れるので、ドキュメントを外に出すならHTTPS化までを1セットで行ってください。
運用での注意
- APIの認証: この例の
/helloは誰でも呼べます。データを返すAPIには、APIキーやトークンによる認証をアプリケーション側で実装する - ドキュメントの公開範囲: Swagger UIはエンドポイントの一覧そのものなので、社内向けのAPIなら上の例のように認証をかけるか、
/docsをNginxで外から見えないようにする - 依存パッケージの更新:
npm outdatedで古いパッケージを確認し、npm auditで既知の脆弱性を確認する。Fastifyのメジャーバージョンを上げるときは、プラグインの対応バージョンも合わせる(@fastify/swagger 9系と@fastify/swagger-ui 5系以上がFastify 5系に対応) - Node.jsのサポート期限: Node.jsは偶数版がLTSになり、期限が切れる前に次のLTSへ上げる。2026年10月時点では24系と26系がLTS
まとめ
- Node.jsはNodeSourceから24系(LTS)を入れる。Ubuntu標準の18系はFastify 5の要件を満たさない
- Fastifyに
@fastify/swaggerをルートより先に登録すると、ルートのスキーマからOpenAPIの仕様書が作られる @fastify/swagger-uiで/docsにSwagger UI、/docs/jsonと/docs/yamlに仕様書が出る- アプリは
127.0.0.1で待ち受けてsystemdで常駐させ、外向きはNginxで受けてHTTPS化する - ドキュメントとAPIには、用途に合わせて認証をかける
関連記事: