C# / .NET アプリのデプロイ(Kestrel + Nginx)
『C# / .NET』アプリのデプロイは、『dotnet publish』で発行した成果物を Kestrel(.NET 内蔵の Web サーバー)で起動し、Nginx をリバースプロキシとして前段に置く構成が一般的です。Kestrel は systemd サービスとして登録することで、サーバー再起動後も自動起動させることができます。本ページでは KOF ファイターの草薙京をモデルにした Web アプリ『kyo-dotnet』を例に、発行からサービス化・Nginx 設定までの流れを解説します。
構文
# -----------------------------------------------
# .NET SDK のインストール(Ubuntu / Debian 系)
# -----------------------------------------------
# Microsoft パッケージリポジトリを追加します
wget https://packages.microsoft.com/config/ubuntu/22.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb
rm packages-microsoft-prod.deb
# パッケージリストを更新して .NET SDK をインストールします
sudo apt update
sudo apt install dotnet-sdk-8.0
# インストール確認
dotnet --version
# -----------------------------------------------
# dotnet publish — アプリを発行する
# -----------------------------------------------
# dotnet publish [プロジェクトパス]
# → アプリをリリース用にビルドして発行ディレクトリに出力します
# オプション:
# -c Release : リリース構成でビルドします(最適化済み)
# -r linux-x64 : ターゲットランタイムを指定します
# --self-contained : ランタイムを同梱します(true: 同梱 / false: 非同梱)
# -o {出力ディレクトリ}: 発行先ディレクトリを指定します
#
# 例: sudo 権限不要のユーザーディレクトリで実行します
# 例: dotnet publish ./KyoApp -c Release -r linux-x64 --self-contained false -o /var/www/kyo-dotnet
cd /home/kyo/KyoApp
dotnet publish -c Release -r linux-x64 --self-contained false -o /var/www/kyo-dotnet
# -----------------------------------------------
# Kestrel の systemd サービス登録
# -----------------------------------------------
# /etc/systemd/system/{サービス名}.service を作成して
# systemctl enable で自動起動を有効化します
# 例: sudo systemctl enable kyo-dotnet.service
sudo nano /etc/systemd/system/kyo-dotnet.service
# -----------------------------------------------
# サービスの有効化と起動
# -----------------------------------------------
# systemd にサービスファイルの変更を通知します
sudo systemctl daemon-reload
# OS 起動時に自動起動するよう登録します
sudo systemctl enable kyo-dotnet.service
# サービスを今すぐ起動します
sudo systemctl start kyo-dotnet.service
# 動作状態を確認します
sudo systemctl status kyo-dotnet.service
# -----------------------------------------------
# Nginx リバースプロキシ設定
# -----------------------------------------------
# /etc/nginx/sites-available/{設定ファイル名} を作成します
sudo nano /etc/nginx/sites-available/kyo-dotnet.conf
# sites-enabled にシンボリックリンクを作成して設定を有効化します
sudo ln -s /etc/nginx/sites-available/kyo-dotnet.conf /etc/nginx/sites-enabled/kyo-dotnet.conf
# Nginx の設定構文を検証します
sudo nginx -t
# 設定を反映します
sudo systemctl reload nginx
# -----------------------------------------------
# appsettings.Production.json — 本番環境設定
# -----------------------------------------------
# ASPNETCORE_ENVIRONMENT=Production のとき自動的に読み込まれます
# データベース接続文字列やログレベルをここで上書きします
# appsettings.json と appsettings.Production.json の両方が
# マージされて適用されます(後者が優先されます)
構文一覧
| 手順 | 説明 |
|---|---|
dotnet publish -c Release -r linux-x64 --self-contained false -o {出力先} | アプリをリリース構成で発行します。--self-contained false はサーバー側に .NET ランタイムがインストール済みの場合に指定します。成果物は -o で指定したディレクトリに出力されます。 |
dotnet publish --self-contained true | ランタイムを同梱して発行します。サーバーに .NET がインストールされていない環境でも動作しますが、ファイルサイズが大きくなります。 |
ASPNETCORE_ENVIRONMENT=Production | 本番環境を指定する環境変数です。appsettings.Production.json が自動的に読み込まれ、ログレベルやデータベース接続文字列を本番用に切り替えられます。 |
ASPNETCORE_URLS=http://localhost:5000 | Kestrel がリッスンするアドレスとポートを指定します。Nginx からのリバースプロキシを受け付けるため、localhost のみに制限するのが安全です。 |
WorkingDirectory=(systemd) | サービスの作業ディレクトリを指定します。dotnet publish の出力先(発行ディレクトリ)を設定します。 |
ExecStart=(systemd) | サービス起動コマンドを指定します。dotnet {DLL名}.dll または発行済み実行ファイルのパスを記述します。 |
Restart=always(systemd) | プロセスが異常終了した場合に自動再起動します。本番サービスでは設定することを推奨します。 |
proxy_pass http://localhost:5000(Nginx) | 受け取ったリクエストを Kestrel へ転送します。Nginx が SSL 終端を担い、バックエンドの Kestrel には HTTP で渡します。 |
proxy_set_header X-Forwarded-For(Nginx) | クライアントの実 IP アドレスを Kestrel へ伝えるヘッダーです。.NET の UseForwardedHeaders ミドルウェアと組み合わせて使います。 |
appsettings.Production.json | ASPNETCORE_ENVIRONMENT=Production 時に appsettings.json を上書きする設定ファイルです。接続文字列・ログレベル・外部 API キーなど環境固有の値を記述します。 |
systemctl daemon-reload | systemd サービスファイルを作成・編集した後に実行します。変更内容が systemd に読み込まれます。 |
systemctl enable {サービス名} | OS 起動時にサービスを自動起動するよう登録します。 |
nginx -t | Nginx の設定ファイルの構文を検証します。syntax is ok が表示されれば問題ありません。systemctl reload nginx の前に必ず確認してください。 |
使用例
/etc/systemd/system/kyo-dotnet.service
[Unit] # サービスの説明。journalctl のログ表示にも使われます Description=KyoApp - 草薙京 .NET Web アプリ(Kestrel) # ネットワーク起動後にこのサービスを起動します After=network.target [Service] # サービスの実行タイプ。フォアグラウンドで動作するプロセスに指定します Type=simple # アプリを実行するユーザーとグループ(root は使わないこと) User=kyo Group=kyo # dotnet publish の出力先ディレクトリを作業ディレクトリとして指定します WorkingDirectory=/var/www/kyo-dotnet # Kestrel を起動するコマンドです # 発行済み DLL を dotnet コマンドで実行します ExecStart=/usr/bin/dotnet /var/www/kyo-dotnet/KyoApp.dll # 本番環境を明示します。appsettings.Production.json が自動的に読み込まれます Environment=ASPNETCORE_ENVIRONMENT=Production # Kestrel のリッスン先を localhost のみに制限します # 外部への直接公開は Nginx に任せます Environment=ASPNETCORE_URLS=http://localhost:5000 # プロセスが落ちたとき自動再起動します Restart=always RestartSec=10 # 標準出力とエラーを systemd のジャーナルに記録します StandardOutput=journal StandardError=journal [Install] # multi-user.target(通常起動モード)のときに有効化します WantedBy=multi-user.target
/etc/nginx/sites-available/kyo-dotnet.conf
server {
# HTTP(ポート80)へのアクセスを HTTPS にリダイレクトします
listen 80;
server_name kyo.example.com;
return 301 https://$host$request_uri;
}
server {
# HTTPS(ポート443)でリクエストを受け付けます
listen 443 ssl;
server_name kyo.example.com;
# SSL 証明書のパスを指定します(Let's Encrypt など)
ssl_certificate /etc/letsencrypt/live/kyo.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/kyo.example.com/privkey.pem;
location / {
# Kestrel(localhost:5000)にリクエストを転送します
proxy_pass http://localhost:5000;
proxy_http_version 1.1;
# WebSocket(SignalR 等)をサポートするためのヘッダーです
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
# Kestrel にホスト名・クライアント IP・プロトコルを伝えます
# .NET の UseForwardedHeaders() ミドルウェアで参照できます
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# バッファリングを無効化してリアルタイム応答を改善します
proxy_buffering off;
# キャッシュをバイパスします
proxy_cache_bypass $http_upgrade;
}
}
実行するコマンドは次の通りです。
$ sudo systemctl daemon-reload
$ sudo systemctl enable kyo-dotnet.service
Created symlink /etc/systemd/system/multi-user.target.wants/kyo-dotnet.service → /etc/systemd/system/kyo-dotnet.service.
$ sudo systemctl start kyo-dotnet.service
$ sudo systemctl status kyo-dotnet.service
● kyo-dotnet.service - KyoApp - 草薙京 .NET Web アプリ(Kestrel)
Loaded: loaded (/etc/systemd/system/kyo-dotnet.service; enabled; vendor preset: enabled)
Active: active (running) since Wed 2026-03-25 10:00:00 JST; 3s ago
Main PID: 12480 (dotnet)
Tasks: 22 (limit: 4915)
Memory: 68.5M
CPU: 1.241s
CGroup: /system.slice/kyo-dotnet.service
└─12480 /usr/bin/dotnet /var/www/kyo-dotnet/KyoApp.dll
Mar 25 10:00:00 server kyo-dotnet[12480]: info: Microsoft.Hosting.Lifetime[14]
Mar 25 10:00:00 server kyo-dotnet[12480]: Now listening on: http://localhost:5000
Mar 25 10:00:00 server kyo-dotnet[12480]: Application started. Press Ctrl+C to shut down.
$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
$ sudo systemctl reload nginx
$ curl -I http://localhost:5000
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Server: Kestrel
Date: Wed, 25 Mar 2026 01:00:05 GMT
概要
『C# / .NET』の本番デプロイは、『dotnet publish』でリリースビルドを生成し、Kestrel を systemd ユニットとして登録・管理するのが定石です。Kestrel は高性能な組み込み Web サーバーですが、SSL 終端・静的ファイル配信・ロードバランシングといった機能は Nginx リバースプロキシに委ねるのがベストプラクティスです。『ASPNETCORE_ENVIRONMENT=Production』を systemd の『Environment=』に設定することで『appsettings.Production.json』が自動的に読み込まれ、接続文字列・ログレベルを本番用に切り替えられます。『proxy_set_header X-Forwarded-For』と .NET 側の『app.UseForwardedHeaders()』を組み合わせることで、Nginx 越しでもクライアントの実 IP アドレスをアプリ内で正しく取得できます。デプロイ後は『systemctl status』と『journalctl -u kyo-dotnet.service -f』でログをリアルタイム確認するとトラブルシュートがスムーズです。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。