PR
PR

【Pythonの学習 Day11】UNIXドメインソケットを使ってGunicornとNginxを連携させる

記事内に広告が含まれています。

Python学習11日目です。

今日は、Flaskの開発サーバで動作させていたhtml変換サービスを、Gunicorn + Nginxで動作させる設定を行っていきます。

Nginxインストール

WebサーバーであるNginxを公式サイトの最新リポジトリを使用してインストールします。

前提条件パッケージのインストール

Nginxをインストールするために必要なパッケージをインストールします。

$ sudo apt update
$ sudo apt install curl gnupg2 ca-certificates lsb-release ubuntu-keyring

署名鍵のインポート

Nginxの署名鍵をインポートします。

$ curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor \
 | sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null

リポジトリ追加

Nginxのリポジトリを追加します。

$ echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \
http://nginx.org/packages/mainline/ubuntu `lsb_release -cs` nginx" \
 | sudo tee /etc/apt/sources.list.d/nginx.list

インストール

Nginxのインストールを行います。

$ sudo apt update
$ sudo apt install nginx

より詳しいインストールの説明を下記のページで説明しているので、よろしければ参考にしてみてください。

【Ubuntu Server 22.04】Nginx公式サイトのリポジトリを使用してインストール
Ubuntu Server 22.04では、apt-key addコマンドが非推奨(廃止予定)となりましたので、それにあわせたインストール手順を説明していきます。公式リポジトリを使用してNginxをインストールUbuntu Server 2...

Gunicornインストール

Flaskアプリケーションを動かすためのWSGIサーバー「Gunicorn」をインストールします。

インストール作業は、Pythonの仮想環境内で行います。

$ cd ~/project/html_converter
$ source .venv/bin/activate
(html_converter) $ uv pip install gunicorn

Gunicornでの動作確認

インストール後、以下のコマンドでGunicornを起動して動作確認を行います。

(html_converter) $ gunicorn --workers 3 --bind 127.0.0.1:8000 app:app
[2025-07-16 23:06:29 +0900] [33013] [INFO] Starting gunicorn 23.0.0
[2025-07-16 23:06:29 +0900] [33013] [INFO] Listening at: http://127.0.0.1:8000 (33013)
[2025-07-16 23:06:29 +0900] [33013] [INFO] Using worker: sync
[2025-07-16 23:06:29 +0900] [33014] [INFO] Booting worker with pid: 33014
[2025-07-16 23:06:29 +0900] [33015] [INFO] Booting worker with pid: 33015
[2025-07-16 23:06:29 +0900] [33016] [INFO] Booting worker with pid: 33016

ログに表示されているように、Webブラウザで「http://127.0.0.1:8000」にアクセスしてHTML変換サービスの画面が表示されることを確認します。

ここまでは、前回の時計サービスを作成した際にも行ったので、問題なく作業を完了することが出来ました。

【Nginx + Gunicorn】UNIXソケットとTCPソケットの違いと選び方

NginxとGunicornを連携させる設定には、主にUNIXドメインソケットTCPソケットという2つの通信方法があります。

以前、時計サービスを作成した際はTCPソケットを使用しましたが、今回は勉強のためにUNIXドメインソケットを使ってみたいと思います。

これまでは「ソケットはファイル」「TCPはネットワーク」という漠然としたイメージで使っていましたが、この機会に両者の違いと、どのような場合にどちらを選ぶべきかを詳しく学んでいくことにします。

UNIXドメインソケット通信とは

UNIXドメインソケット通信は、同じサーバー上で動作するプロセス同士が通信するための方法です。

これは、ネットワークを介さず「ソケットファイル」と呼ばれる特殊なファイルを使用してデータのやり取りを行います。

以下が実際のソケットファイルです。

$ ls -l html_converter.sock 
srwxrwxrwx 1 tamohiko tamohiko 0  7月 17 19:15 html_converter.sock

$ file html_converter.sock 
html_converter.sock: socket

メリット

  • 高性能:

    TCPソケット通信に比べてネットワークを経由しないため、オーバーヘッドが非常に少なくデータ転送速度が高速です。

  • 高セキュリティ:

    通信がサーバー内部で完結しており、ネットワークポートを公開する必要がないのため、外部からの直接アクセスされる心配がありません。

  • 設定の簡素化:

    TCPソケット通信とは違い、ポート番号の衝突を気にする必要がありません。

デメリット

  • 同一サーバー内でのみ使用可能:

    同じサーバー上にある場合のみ通信でき、異なるサーバ間では通信できません。
    NginxとGunicornが別のサーバーで稼働している構成では選択できません。

  • ファイルパーミッションの管理:

    ソケットファイルのパーミッションを適切に設定しないと、Nginxがソケットに接続できなかったり、他のユーザーに不要なアクセスを許してしまったりする可能性があります。

TCPソケット通信とは

TCP/IPプロトコルを使って、IPアドレスポート番号を使用してネットワーク経由で通信する方法です。

ローカルホスト(127.0.0.1)経由で通信することも、インターネットやLANを介して、異なるサーバー間で通信することも可能です。

メリット

  • 高い柔軟性:

    異なるサーバー間で通信できるため、NginxとGunicornを別々のマシンに分散させるようなスケーラブルなシステム構成が可能です。

  • 簡単な設定:

    IPアドレスとポート番号を指定するだけで通信が可能です。

デメリット

  • 性能オーバーヘッド:

    ネットワークを介するため、UNIXドメインソケットに比べてオーバーヘッドがあり、わずかにパフォーマンスが劣る可能性があります。

  • セキュリティリスク:

    ポートを公開することになるため、ローカルホスト(127.0.0.1)で通信する場合でも、ファイアウォールによる適切なアクセス制限が不可欠です。
    もし誤って外部からアクセス可能な状態でポートを公開してしまうと、Gunicornに直接攻撃されるリスクが生じます。

どちらを選ぶべきか?

UNIXドメインソケット通信とTCPソケット通信の、どちらを選べばよいかの判断基準は以下のとおりです。

GunicornとNginxが同じサーバー上にある場合

特別な理由がない場合は、UNIXドメインソケット通信の方が性能面とセキュリティ面で優れているので利用を推奨します。
複数のサービスをを公開する場合にも、ポート番号を管理する必要がなくなります。

GunicornとNginxが異なるサーバーに分散している場合

この構成の場合は、TCPソケット通信が唯一の選択肢になります。
ただし、Gunicornが待ち受けるポートには、Nginxサーバーからのアクセスのみを許可するよう、厳重なファイアウォール設定が必須です。

Nginx + GunicornをUNIXドメインソケットで連携させる2つの方法

「Nginx + Gunicorn」をUNIXドメインソケットで連携させる設定には、主に2つの方法があります。

  • Gunicornにソケット作成を任せる方法:

    手軽ですぐに試せるため、開発環境やシンプルな構成に向いています。

  • systemdでソケットとGunicornを管理する方法:

    より堅牢でセキュアなため、本番環境での運用に最適です。

両方の方法について、具体的な手順とそれぞれのメリット・デメリットを解説していきます。

ソケットファイルの作成場所について

一般的な場所は「プロジェクトディレクトリの直下」や、「/tmp」「/run」「/var/run」といったディレクトリ内で、ソケットのファイル名は、通常「アプリケーション名.sock」のようにします。

Gunicornにソケット作成を任せる方法では、プロジェクトディレクトリの直下に「html_converter.sock」という名前で作成することにします。

ソケットファイル名: /home/tamohiko/project/html_converter/html_converter.sock

systemdでソケットとGunicornを管理する方法では、「/run」ディレクトリ内にソケットを作成することにします。

ソケットファイル名: /run/tamohiko/project/html_converter/html_converter.sock

Gunicornにソケットの作成をまかせて起動する方法

開発環境などで手軽に試したい場合に最適な方法です。

gunicornコマンドの--bindオプションを使うことで、Gunicorn自身がソケットを作成し起動します。

こちらの場合、ソケットの作成もGunicornが行ってくれるので、「gunicorn」コマンドだけで起動できて、とても手軽に試すことができます。

ただし、ソケットを作成するディレクトリに、Gunicornを実行するユーザーの書き込み権限が必要になります。

gunicorn --workers ワーカー数 --bind unix:ソケットファイル Pythonファイル名:Flaskインスタンス名
  • --bind unix:ソケットファイル Gunicornが指定したソケットファイルを作成し接続を待ち受けます。
    • unix: UNIXソケットを使用することを示します。
    • ソケットファイル Gunicornが作成するソケットファイルの絶対パスを指定します。
  • Pythonファイル名 今回の場合「app.py」の場合.pyを抜いた「app」となります。
  • Flaskインスタンス名 「app.py」内で、「app = Flask(__name__)」とFlaskのインスタンス名を指定しているので「app」となります。

Gunicorn起動

実際にGunicornを起動させてみます。

コマンドの実行はPythonの仮想環境の中で行います。

(html_converter) $ .venv/bin/gunicorn --workers 3 --bind unix:/home/tamohiko/project/html_converter/html_converter.sock app:app

プロジェクトのディレクトリ直下を確認すると、UNIXドメインソケットが作成されていることを確認できます。

$ ls -l html_converter.sock 
srwxrwxrwx 1 tamohiko tamohiko 0  7月 17 19:15 html_converter.sock

/etc/hostsを設定

今回は現在開発を行っているノートPCから、「conv.server-memo.net」という名前でWebブラウザでアクセスできるようするために、「/etc/hosts」に以下の設定を追加します。

$ sudo vi /etc/hosts

追加する設定は以下のとおりです。

127.0.0.1 conv.server-memo.net

この設定により、「conv.server-memo.net」は自分自身(127.0.0.1)のことだと名前解決することができるようになります。

Nginx設定

NginxとGunicornを連携させるための基本的な設定を追加します。

リバースプロキシ設定

これらの設定は、Nginxがリクエストを中継する際に失われてしまう「クライアントの元の情報」をバックエンドに伝えるための設定です。

$ sudo vi /etc/nginx/proxy_params

設定内容は以下のとおりです。

proxy_set_header Host $http_$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;

Gunicornとの連携設定

Gunicornと連携させるための設定を行います。

$ sudo vi /etc/nginx/conf.d/html_converter.conf

設定内容は以下のとおりです。

upstream app_server {
    server unix:/home/tamohiko/project/html_converter/html_converter.sock fail_timeout=0;
}

server {
    listen 80;
    server_name conv.server-memo.net;
    index index.html;

    access_log /var/log/nginx/html_converter.access.log;
    error_log /var/log/nginx/html_converter.error.log;

    location / {
        include proxy_params;
        proxy_pass http://app_server;

    }
}

upstreamブロックで、転送先となるバックエンドサーバを設定しています。

「server unix:/home/tamohiko/project/html_converter/html_converter.sock fail_timeout=0;」部分で、接続させたいソケットファイルを指定します。

「fail_timeout=0」は、Nginxがバックエンドサーバーを「ダウンしている」と見なす機能を無効化し、接続失敗後も即座に次のリクエストで再試行させるための設定です。

この設定がない場合は、Nginxは接続に失敗したサーバーを一定時間(デフォルト10秒)「故障中」と判断し、その間リクエストを送るのをやめます。

Nginx起動

設定ファイルの作成が完了したら、書式チェックを行ってからNginxを起動します。

$ 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 start nginx

Nginxが正常に起動しているか確認しておきましょう。

$ sudo systemctl status nginx
● nginx.service - nginx - high performance web server
     Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; preset: en>
     Active: active (running) since Sat 2025-07-19 23:18:18 JST; 1 day 22h ago
       Docs: https://nginx.org/en/docs/
    Process: 1914 ExecStart=/usr/sbin/nginx -c ${CONFFILE} (code=exited, status>
   Main PID: 1923 (nginx)
      Tasks: 5 (limit: 9373)
     Memory: 2.2M (peak: 6.6M swap: 3.8M swap peak: 4.0M)

起動に問題がなければ、自動起動の設定を行っておきます。

$ sudo systemctl enable nginx

動作確認

Webブラウザで「http://conv.server-memo.net」にアクセスしてHTML変換サービスの画面が表示されて、実際にhtmlを入力して変換されることを確認します。

問題なく動作していることが確認できました。

これで、とりあえずはUnixドメインソケットを使用してGunicornとNginxを連携させることが出来ました。

こちらの方法は、gunicornコマンドを実行するだけでソケットも作成してもらえるので、とても簡単にNginxと連携させることができました。

systemdでソケットの作成とGunicornを管理する方法

gunicornコマンドの「--bind」を使ってソケット作成し、Nginxと連携させることは出来ましたので、次はsystemdでソケットの作成・管理を行う方法を試してみます。

systemdでソケットを管理することには、以下のようなメリットとデメリットがあります。

メリット

セキュリティの向上

systemd (root権限) が先にソケットを作成し、Gunicornを権限の低い一般ユーザー (nginx) で起動できる。
これにより、アプリケーションが乗っ取られた際のリスクを低減することができます。

堅牢なサービス管理

systemdがGunicornの起動、停止、異常時の自動再起動などを管理してくれるので、非常に安定した運用が可能となります。

ゼロダウンタイムでの更新

ソケットをsystemdが保持してくれるので、Gunicornのアプリケーションを更新・再起動する際に、接続を取りこぼすことなくシームレスに切り替えることができ、ダウンタイムなしでのデプロイが実現しやすくなります。

デメリット

設定の複雑さ

.socketと.serviceという2つの設定ファイルが必要になり、Gunicorn単体で動かすよりsystemdの学習コストが多くかかります。

プラットフォーム依存

systemdがインストールされているLinux環境でしか使えません。

Gunicorn用のsystemd設定ファイルの作成

systemdでGunicornを管理するために、.socketと.serviceという2つの設定ファイルを作成します。

この2つは、拡張子を除いて必ず同じファイル名にしてください。

  • .socketファイル: UNIXドメインソケットの作成と管理を担当します。
  • .serviceファイル: ソケットへのアクセスを契機にして、Gunicornアプリケーションを起動・管理します。

この仕組みにより、OS起動時にはソケットだけが待機状態となり、最初のアクセスがあった時にsystemdがGunicornを自動で起動してくれます (ソケットアクティベーション)

ソケットファイル (.socket) の作成

ソケット自体の設定ファイルを以下の名前で作成します。

$ sudo vi /etc/systemd/system/html_converter.socket

設定内容は下記のとおりです。

[Unit]
Description=html_converter socket

[Socket]
ListenStream=/run/html_converter/html_converter.sock
SocketUser=nginx
SocketGroup=nginx
SocketMode=0660

[Install]
WantedBy=sockets.target
  • ListenStream:

    作成するソケットファイルの絶対パス
    今回は「/run/html_converter/html_converter.sock」としています。

  • SocketUser/SocketGroup:

    ソケットファイルを所有するユーザーとグループ。
    Nginxの実行ユーザに合わせて設定します。

  • SocketMode:

    ソケットファイルのパーミッション。
    0660は、所有ユーザーとグループに読み書きを許可します。

Nginxの実行ユーザ・グループの調べ方は下記のページで説明しているので、良ければ参考してみてください。

Nginxの実行ユーザーとグループを確認する2つの方法
Nginxの実行ユーザとグループを確認するための2つの方法を紹介します。 実行中のプロセスから確認する (psコマンド)実際に動作しているNginxプロセスのユーザーとグループを確認する、最も確実な方法です。psコマンドの「o」オプションを...

サービスファイル (.service) の作成

Gunicornをサービスとして起動するための設定ファイルを作成します。

$ sudo vi /etc/systemd/system/html_converter.service
[Unit]
Description=html_converter service with Gunicorn
After=network.target
Requires=html_converter.socket

[Service]
User=nginx
Group=nginx

WorkingDirectory=/home/tamohiko/project/html_converter
ExecStart=/home/tamohiko/project/html_converter/.venv/bin/gunicorn --workers 3 app:app
Restart=on-failure

[Install]
WantedBy=multi-user.target

ExecStartのgunicornには--bindオプションは不要です。

systemdがソケットを引き渡してくれるため、Gunicornはそれを自動で認識してくれます。

systemdへ設定反映・起動・自動起動設定

作成した「.socket」と「.service」ファイルを、「systemctl daemon-reload」でsystemdに読み込ませて管理できるようにし、ソケットを起動させます。

$ sudo systemctl daemon-reload
$ sudo systemctl start html_converter.socket

「systemctl status」コマンドで、ソケットが作成されていることを確認します。

$ sudo systemctl status html_converter.socket
● html_converter.socket - html_converter socket
     Loaded: loaded (/etc/systemd/system/html_converter.socket; disabled; preset: enabled)
     Active: active (listening) since Sat 2025-07-19 23:03:46 JST; 13s ago
   Triggers: ● html_converter.service
     Listen: /run/html_converter/html_converter.sock (Stream)
      Tasks: 0 (limit: 9373)
     Memory: 0B (peak: 256.0K)

「Active: active (listening)」と表示されていればソケットが作成されて、リクエストを待ち受けている状態です。

正常にソケットが作成されることを確認したあとに、ソケットが自動起動するように設定を行います。

$ sudo systemctl enable html_converter.socket
Created symlink /etc/systemd/system/sockets.target.wants/html_converter.socket → /etc/systemd/system/html_converter.socket.

.serviceファイルを有効化(enable)しない理由

systemdのソケットアクティベーションでは、「.socket」ファイルと「.service」ファイルが連携して動作します。

そのため、OS起動時に起動(enable)しておく必要があるのは、通信を待ち受ける「.socket」ファイルだけです。

今回作成した「html_converter.service」は、あくまで「html_converter.socket」から呼び出される存在になります。

Nginx設定変更

「/etc/nginx/conf.d/html_converter.conf」のupstreamブロックで指定しているソケットファイルのパスを、systemdが作成・管理するパスに変更します。

変更点はこの一行だけです。

upstream app_server {
    server unix:/run/html_converter/html_converter.sock fail_timeout=0;
}

server {
    listen 80;
    server_name conv.server-memo.net;
    index index.html;

    access_log /var/log/nginx/html_converter.access.log;
    error_log /var/log/nginx/html_converter.error.log;

    location / {
        include proxy_params;
        proxy_pass http://app_server;

    }
}

設定ファイルを変更したら、文法チェックを行い、Nginxを再起動して設定を反映させます。

$ 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 restart nginx

動作確認

Webブラウザで、設定したドメイン名(例: http://conv.server-memo.net)にアクセスし動作確認を行います。

無事HTML変換サービスが動作していることを確認できました。

まとめ

今回は、NginxとGunicornをUNIXドメインソケットで連携させる、以下の2つの方法を実践しました。

それぞれの方法についての比較を簡単にまとめてみました。

  • gunicornコマンドの--bindオプションを使う方法
  • systemdでソケットとサービスを管理する方法
比較項目 gunicorn--bind systemdで管理
手軽さ ◎ とても簡単 △ 設定ファイルが必要
セキュリティ ○ 注意が必要 ◎ 高い(権限分離)
安定性 ○ 手動管理 ◎ 高い(自動起動/再起動)
おすすめの用途 開発環境 本番環境

gunicornコマンドの--bindオプションを使用する方法は、コマンド1行で起動させることができ、開発段階の動作確認にはとても便利に使えることがわかりました。

一方、ystemdで管理する方法は、.socketと.serviceという2つのファイルの作成が必要で、最初は少し手間がかかります。

しかし、その手間をかけることで得られるセキュリティと安定性の向上は、本番環境での運用においてメリットがあることも学習できました。

結論として、「開発中は手軽なgunicornコマンド」、「本番運用に移行する段階でsystemd管理」という使い分けが良いみたいなので、今後はこの方法で開発を行っていくことにします。

コメント

タイトルとURLをコピーしました