Linux
PR

ローカルネットワークでWebアプリを公開する手順|React+Djangoのアプリを例に解説

えりる
記事内に商品プロモーションを含む場合があります

この記事では、DjangoバックエンドとReactフロントエンドで構成されるウェブアプリケーションをUbuntuローカルサーバーにデプロイし、同一ネットワーク内(同じWi-Fi内)からのみアクセスできるようにする方法を説明します。

前提

ウェブアプリのディレクトリ構成

ウェブアプリのフロントエンドはReact、バックエンドはDjangoで作ったものとして、以下のようなディレクトリ構成を想定します。

/home/user_name/sample_app/ # プロジェクトのルートディレクトリ(ホームディレクトリに配置)
├───.gitignore
├───.git/...
├───backend/ # Djangoのルートディレクトリ
│   ├───manage.py
│   ├───requirements.txt
│   ├───config/
│   │   ├───__init__.py
│   │   ├───asgi.py
│   │   ├───settings.py
│   │   ├───urls.py
│   │   ├───wsgi.py
│   │   └───...
│   └───media/...
├───frontend/ # Reactのルートディレクトリ
│   ├───.vite/
│   │   └───deps/...
│   ├───dist/... 
│   ├───node_modules/...
│   ├───public/...
│   ├───src/...
│   ├───eslint.config.js
│   ├───index.html
│   ├───package.json
│   └───...
└───venv/
    ├───bin/...
    ├───include/...
    └───lib/...

ウェブアプリ公開に使用するツール

この記事では以下のツールを使用してウェブアプリを公開する手順を示します。

  • Gunicorn: Djangoアプリケーションをサービスとして実行するためのWSGIサーバー。
  • Nginx: リバースプロキシとして機能し、静的ファイル(Reactビルド、Djangoの静的/メディアファイル)を配信します。

動作の流れ(リクエストのルート)

各ツールの役割をまとめると以下のようになります。

コンポーネント役割
React (フロントエンド)ブラウザ上で動くユーザーインターフェース(静的ファイル: HTML/CSS/JS)を提供
Django (バックエンド)APIエンドポイントを提供し、データベース操作や認証などを担当
Gunicorn (WSGIサーバ)Djangoアプリを実際にPythonで動かすアプリケーションサーバ
Nginx (リバースプロキシ/静的ファイルサーバ)外部からのリクエストを受け、静的ファイルやAPIリクエストを適切に振り分ける

データの流れは以下の通りです。

  1. ユーザーがブラウザでアクセス
    • 例: https://example.com にアクセス
    • → Nginx が最初にリクエストを受け取ります。
  2. Nginx がリクエストを振り分ける
    • //static/ に対するリクエスト → React のビルド済み静的ファイルindex.html, JS, CSS)を返す
    • /api/ などのリクエスト → Gunicorn 経由で Django に転送
  3. Gunicorn が Django を実行
    • Nginx から来た /api/... リクエストを Gunicorn が受け取り、
    • Gunicorn が Django アプリを実行してレスポンス(JSONやHTMLなど)を生成します。
  4. Nginx がレスポンスをクライアントへ返す
    • Django → Gunicorn → Nginx → ブラウザ という経路でレスポンスが返ります。

図にするとこんな感じですね。

ウェブアプリの公開準備

React アプリケーションのビルド

frontend ディレクトリに移動し、Reactアプリケーションを本番用にビルドします。これにより、最適化された静的ファイルが frontend/dist ディレクトリ(Viteの場合)に生成されます。

cd /home/user_name/sample_app/frontend 
npm install # 依存関係がインストールされていない場合 
npm run build

ビルドが完了すると、frontend/dist ディレクトリが作成され、その中に index.html やJavaScript/CSSファイルが生成されます。

Djangoの設定

settings.py の設定変更

sample_app/backend/config/settings.py ファイルを編集し、本番環境向けの設定を行います。
まず、DEBUGFalse に設定します。

# sample_app/backend/config/settings.py 
DEBUG = False

次に、ALLOWED_HOSTS にサーバーのIPアドレスとドメインを追加します。
ローカルネットワークへ公開するため、サーバーのローカルIPアドレス(例: 192.168.1.100) を追加します。avahi-daemon 等でmyserver.local のように名前をつけている場合は myserver.local を追加します。

# sample_app/backend/config/settings.py 
# ALLOWED_HOSTS = ['127.0.0.1', 'localhost', 'あなたのサーバーのローカルIPアドレス']
# 以下は一例。'192.168.1.100', 'myserver.local'はどちらか一方だけで良い。
ALLOWED_HOSTS = ['127.0.0.1', 'localhost', 'myserver.local']

最後に、静的ファイルとメディアファイルのルートを設定します。 これらはNginxが配信するディレクトリになります。

# sample_app/backend/config/settings.py 
import os 

# Djangoの静的ファイルを収集するディレクトリ 
STATIC_URL = '/static/' 
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') 

# フロントエンドの静的ファイルディレクトリ
# ここに指定したディレクトリはcollectstaticでまとめて集めることができる。
STATICFILES_DIRS = [
    os.path.join(BASE_DIR.parent, "frontend", "dist"),
]

# ユーザーアップロードファイルを保存するディレクトリ
MEDIA_URL = '/media/' 
MEDIA_ROOT = os.path.join(BASE_DIR, 'media') 

settings.py を本番用に設定するときの補足

  • INSTALLED_APPS'whitenoise.runserver_nostatic' (開発用のみ) や 'whitenoise.middleware.WhiteNoiseMiddleware' を追加する必要はありません。Nginxが静的ファイルを処理するためです。
  • DEBUG=False などをsettings.py に直接記述する(ハードコーディングといいます)ことはセキュリティ上あまり良くないので、適宜.env ファイルに書き出したり環境変数として設定したりすると良いです。ただ、今回はローカルネットワーク上での公開なのでそのままでも良い気がします。

静的ファイルの収集

Djangoプロジェクトのルートディレクトリ(sample_app/backend)で以下のコマンドを実行し、静的ファイルを STATIC_ROOT で指定したディレクトリに収集します。

cd /home/user_name/sample_app/backend 
python manage.py collectstatic

ウェブアプリを公開する

NginxがReactフロントエンドの index.html を提供し、APIリクエストはGunicorn経由でDjangoバックエンドにルーティングされるように設定します。

Nginx のセットアップ

まず、Nginx をインストールします。

sudo apt update 
sudo apt install nginx

インストールができたら、Nginx サーバーブロックの設定を行います。
まず、新しいNginxサーバーブロックファイルを作成します。

sudo vi /etc/nginx/sites-available/sample_app

以下の内容を貼り付け、パスを適宜修正してください。

server {
    listen 80; # 別のポートも指定可能
    server_name myserver.local; # あるいはIPアドレス 127.0.0.1など

    # アップロード許容サイズ 
    client_max_body_size 10000M;

    # Djangoの静的ファイルを提供 (collectstaticで収集されたもの)
    location /static/ {
        alias /home/user_name/sample_app/backend/staticfiles/; # collectstaticで指定したSTATIC_ROOT
    }

    # Djangoのメディアファイルを提供 (ユーザーアップロードファイル)
    location /media/ {
        alias /home/user_name/sample_app/backend/media/; # settings.pyで指定したMEDIA_ROOT
    }

    # Django APIへのリクエストをGunicornにプロキシ
    location /api/ {
        include proxy_params;
        proxy_pass http://unix:/run/gunicorn/sample_app.sock;
    }

    # ==== SPA (React/Vue) の配信 ====
    location / {
        root /home/user_name/sample_app/backend/staticfiles;
        index index.html;
        try_files $uri $uri/ /index.html;
    }

    error_page 500 502 503 504 /500.html; # エラーページの設定 (オプション)
    location = /500.html {
        root /usr/share/nginx/html;
    }
}

設定ファイルを有効化します。

sudo ln -s /etc/nginx/sites-available/sample_app /etc/nginx/sites-enabled/
sudo nginx -t # 設定ファイルのシンタックスチェック
sudo systemctl restart nginx

これでフロントエンドの準備は完了です。

Gunicorn のインストールと設定

まずはGunicornをインストールします。

pip install gunicorn

GunicornでDjangoアプリケーションを実行できるかテストします。sample_app/backend ディレクトリで実行してください。

gunicorn config.wsgi:application --bind 0.0.0.0:8000

ブラウザで http://localhost:8000 にアクセスし、Djangoアプリが動作することを確認してください。
問題なければ Ctrl+C で終了しておきましょう。

Gunicorn Systemd サービスファイルの作成

Gunicornをバックグラウンドで永続的に実行するためのSystemdサービスファイルを作成します。

sudo vi /etc/systemd/system/sample_app.service

以下の内容を貼り付け、パスを適宜修正してください。

[Unit]
Description=Gunicorn instance to serve sample_app
After=network.target

[Service]
User=user_name # ここにUbuntuのユーザー名を入力してください 
Group=www-data

# Djangoプロジェクトのルートディレクトリ
WorkingDirectory=/home/user_name/sample_app/backend 

# gunicornの起動コマンド。--workersで使用するスレッド数を指定する。
# --bind unix:/run/gunicorn/sample_app.sock でソケットファイルを指定する
# config.wsgi はDjangoプロジェクトのルートディレクトリ(WorkingDirectory)からwsgi.pyまでのの相対パス
ExecStart=/home/user_name/sample_app/venv/bin/gunicorn --workers 3 --bind unix:/run/gunicorn/sample_app.sock config.wsgi:application
UMask=002 # ソケットファイルにグループ書き込み権限を付与
ExecReload=/bin/kill -s HUP $MAINPID
KillMode=mixed
Restart=on-failure
StandardOutput=journal
StandardError=journal

# 以下の記述はrun/gunicornにソケットファイルを権限755で作成するということ。
RuntimeDirectory=gunicorn 
RuntimeDirectoryMode=0755

[Install]
WantedBy=multi-user.target

完了したらサービスファイルを有効化して起動します。

sudo systemctl daemon-reload 
sudo systemctl start sample_app 
sudo systemctl enable sample_app

最後に、Gunicornのステータスを確認します。

sudo systemctl status sample_app

Active: active (running) と表示されれば成功です。

ファイアウォール(ufw)の設定

通常はWi-Fiルーターが外部からのアクセスを遮断してくれるのでこれは任意ですが、ufw を使ってファイアウォールを設定し、外部からのアクセスをサーバー側でも遮断しておきます。

具体的な設定方法は以下の記事で解説していますので、こちらをご参照ください。
Raspberry Pi向けの記事ですが、Ubuntuでも同じ方法で設定できます。

あわせて読みたい
【Raspberry Pi】ローカルネットワークからの接続のみ許可する方法(ラズパイのセキュリティ設定)
【Raspberry Pi】ローカルネットワークからの接続のみ許可する方法(ラズパイのセキュリティ設定)

アクセス方法と動作確認

同一ネットワーク内の他のデバイスからウェブブラウザを開き、サーバーのローカルIPアドレス(またはサーバーURL)にアクセスします。(たとえば以下の通り)

  • http://myserver.local
  • http://192.168.1.100

まとめ

この記事では、DjangoバックエンドとReactフロントエンドで構成されるウェブアプリケーションをNginxとGunicornを使って、同一ネットワーク内からのみアクセスできるようにする方法を解説しました。

えりるさんが気になっている商品紹介コーナー

Minisforum のミニPC UN150P です。CPUは Intel N150 というもので基本的な消費電力は6Wくらいとかなり低消費電力でありながら、ネットサーフィンやYouTubeの動画視聴くらいなら困らないくらいの性能があります。Raspberry Pi 5 よりも性能が良いそうです。
消費電力が少ないので、Ubuntu等を入れてサーバー的に使うこともできますね。同じような用途だとRaspberry Piでもできますが、ケース等を買っていると結局同じくらいの値段になるので、それだったらミニPCにした方がいいかなと思います。
えりるさんはサーバー運用のお勉強に買ってみようかなあと計画中です。(Raspberry Pi 4 1GBだとちょっとスペックが足りなかった…)

えりるについて
えりる
えりる
日本のどこかに生息する平成生まれの研究者。とっても理論家と思いきや気分屋さんでもある。基本的にめんどくさがり。修士(工学)を持っている。 Windows, Mac, Linuxの三刀流。
記事URLをコピーしました