SIGMA-SE Math & Tech Library

SIGMA-SE Math & Tech Library


数学と情報技術をテーマに、書籍や教材だけではつかみにくい考え方を具体例とともに簡潔にわかりやすく伝える解説サイトです。
技術の歴史や背景、関連知識の整理、学習のための覚書や要約記事も掲載しています。

VPSで作るDjangoサイト構築手順 - Apache編:4/4 PostgreSQL・Django本番設定と起動確認

概要

PostgreSQLの初期設定、Djangoのデータベース接続、settings.pyの本番向け設定、起動確認までを整理する。

Djangoサイトを公開する最後の段階では、データベース、マイグレーション、セキュリティ設定、静的ファイル、Apache連携をまとめて確認する必要がある。runserverと本番起動の違いも押さえておく。

この記事の構成

対象環境と利用上の注意

  • 本文記載時の環境
    2018年当時のCentOS 7.4環境の記録をもとに、Django 2.2、PostgreSQL 9.6、psycopg2 2.8系と整合するよう再構成した例。
    データベースはDjangoと同じVPSで動かす構成を前提とする。
  • 確認時期
    2026年8月にDjango、PostgreSQL、psycopgの公式資料と照合。
    現在の環境でデータベース作成からApache経由の起動まで一連の手順は再実行していない。
  • 現在そのまま利用できない箇所
    CentOS 7、Django 2.2、PostgreSQL 9.6、psycopg2 2.8系は旧環境である。
    PGDGのパッケージ名、認証方式、Djangoの設定要件も変わるため、新規構築ではサポート中の組合せと現行の公式手順を利用する。

前提環境

  • OS
    CentOS 7.4(サポート終了済み)
  • 言語
    Python
  • Webサーバー
    Apache
  • フレームワーク
    Django
  • データベース
    PostgreSQL 9.6(サポート終了済み)
  • ドメイン
    example.com

作業時の注意点

  • データベースユーザー
    作成したユーザー名とDjangoのDATABASES設定を一致させる。
  • DEBUG設定
    本番ではFalseにし、ALLOWED_HOSTSを正しく設定。
  • マイグレーション
    モデル変更後はmakemigrationsとmigrateを忘れない。
  • runserverとApache
    両方を混同すると、どちらで動いているか分かりにくくなる。

実施内容

データベースの環境構築

  • PostgreSQL 9.6インストール(旧環境の例)
    当時のPostgreSQL公式Yumリポジトリ(PGDG 9.6)を有効化した後、Django 2.2の要件を満たすPostgreSQL 9.6を導入。
    現在はPostgreSQL 9.6もサポート終了済みなので、このパッケージ名を新規構築へ流用せず、サポート中のOSとPostgreSQLを選ぶ。

    $ yum -y install postgresql96-server postgresql96-devel gcc
    
  • DjangoからPostgreSQLへ接続するドライバーをインストール
    この記事のPython 3.6環境では、対応するpsycopg2を仮想環境へ導入。新しい環境では、利用中のDjangoが対応するpsycopgまたはpsycopg2と公式の導入方法を確認。

    $ source /var/www/vops/bin/activate
    $ export PATH="/usr/pgsql-9.6/bin:$PATH"
    $ python -m pip install "psycopg2<2.9"
    
  • データベースとユーザーの作成
    データベースexampledbとアクセスユーザーappuserを作成。
    PostgreSQLでは引用符なしの識別子が小文字へ変換されるため、SQLとDjangoの設定で最初から小文字に統一する。

    $ /usr/pgsql-9.6/bin/postgresql96-setup initdb    # データベースの初期化
    $ systemctl start postgresql-9.6    # PostgreSQLを起動
    $ systemctl enable postgresql-9.6    # 自動起動を有効化
    $ sudo -u postgres /usr/pgsql-9.6/bin/psql    # postgresでログイン
    postgres=# CREATE USER appuser WITH PASSWORD '十分に長いパスワード';
    postgres=# CREATE DATABASE exampledb OWNER appuser;
    postgres=# ALTER ROLE appuser SET client_encoding TO 'utf8';
    postgres=# ALTER ROLE appuser SET default_transaction_isolation TO 'read committed';
    postgres=# ALTER ROLE appuser SET timezone TO 'Asia/Tokyo';
    
  • PostgreSQLを起動確認
    active (running) と表示されていれば成功。

    $ systemctl status postgresql-9.6
    

Django周りの設定

以下、Djangoのモデル定義が終わっていることが前提。

  • マイグレーションファイルを作成
    ※ マイグレーションファイル(モデルの内容をデータベースに適用するファイル)

    $ /var/www/vops/bin/python /var/www/vops/ops/manage.py makemigrations
    
  • マイグレーションファイルをデータベースに反映
    マイグレーションファイルを基に、データベースの構造(テーブルの作成や更新)を変更。

    $ /var/www/vops/bin/python /var/www/vops/ops/manage.py migrate
    
  • スーパーユーザーの作成

    $ /var/www/vops/bin/python /var/www/vops/ops/manage.py createsuperuser
    
  • Djangoの開発用サーバーを外部公開しない
    runserverは動作確認専用であり、本番公開を目的としたサーバーではない。
    同じVPS内から127.0.0.1で確認し、8080番ポートをfirewalldで外部へ開放しない。

PostgreSQL周りの設定

  • postgresql.conflisten_addressesをローカル接続に限定
    DjangoとPostgreSQLが同じVPS上にあるため、インターネットから5432番ポートへ接続させる必要はない。

    $ vim /var/lib/pgsql/9.6/data/postgresql.conf
    listen_addresses = 'localhost'
    
  • pg_hba.conf(認証設定ファイル)にドメイン情報を追加
    ローカルホストからexampledbへ接続するルールを追加。
    アドレス欄はサーバー自身ではなく、接続元クライアントの範囲を表す。
    pg_hba.confは上から順に最初に一致したルールが使われるため、host all all 127.0.0.1/32 ...のような広いルールより前へ挿入する。

    $ vim /var/lib/pgsql/9.6/data/pg_hba.conf
    # ローカルホスト向けの広いhostルールより前へ追加
    host    exampledb    appuser    127.0.0.1/32    md5
    

    md5はこの旧環境に合わせた認証方式である。現行PostgreSQLではSCRAM認証を優先し、サーバーとクライアントの対応状況を公式ドキュメントで確認。

  • PostgreSQLの再起動
    listen_addressespg_hba.confを変更した後、PostgreSQLを再起動。
    5432番ポートはfirewalldで公開しない。データベースを別サーバーへ分離する場合だけ、接続元IP、TLS、クラウド側のセキュリティグループを含めて別途設計。

    $ systemctl restart postgresql-9.6
    

settings.pyの設定

  • デバッグモードの無効化
    DEBUG = False    # 開発モードのTrueからFalseに修正
    
  • ALLOWED_HOSTSを自身のドメインに設定
    ALLOWED_HOSTS = ['example.com']    # 自身のドメインに修正
    
  • INSTALLED_APPSにアプリケーション名を追加
    INSTALLED_APPS = [
        'webapp',    # アプリケーション名を追加
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
    ]
    
  • SSL/TLS周りの設定を追加
    SECURE_SSL_REDIRECT = True
    SESSION_COOKIE_SECURE = True
    CSRF_COOKIE_SECURE = True
    

    SECURE_PROXY_SSL_HEADERは、TLSを終端する信頼済みリバースプロキシがX-Forwarded-Protoを設定し、外部から届いた同名ヘッダーを除去できる場合にだけ設定。
    ApacheのHTTPS VirtualHostからmod_wsgiへ直接渡す今回の構成では不要となる。

  • ROOT_URLCONFの修正
    ROOT_URLCONF = 'ops.urls'    # URLとビューを対応付けるURLconfモジュールを指定
    
  • DATABASESの設定
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.postgresql',
            'NAME': 'exampledb',
            'USER': 'appuser',
            'PASSWORD': os.environ['DJANGO_DB_PASSWORD'],
            'HOST': '127.0.0.1',
            'PORT': '5432'
        }
    }
    

    パスワードやSECRET_KEYはソースコードへ直接書かず、環境変数や権限を制限した設定ファイルから読み込む。
    この例ではDJANGO_DB_PASSWORDが未設定だとDjango起動時にエラーになるため、manage.pyを実行するシェルだけでなく、Apacheサービスの起動環境にも同じ値を安全に渡す必要がある。
    具体的な受渡し方法はOSやサービス管理方法に合わせ、権限を制限した環境ファイルやシークレット管理機能を利用。

  • 日本語化、タイムゾーンの設定
    LANGUAGE_CODE = 'ja'
    TIME_ZONE = 'Asia/Tokyo'
    USE_I18N = True
    USE_L10N = True
    USE_TZ = True
    
  • 静的ファイル、メディアファイルのパス設定
    STATIC_URL = '/static/'
    STATIC_ROOT = os.path.join(BASE_DIR, 'static')
    MEDIA_URL = '/media/'
    MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
    

    MEDIA_ROOTはアップロードファイルの保存先を定めるだけで、DEBUG=Falseの環境でApacheから自動配信されるわけではない。
    メディア機能を使う場合は、アップロードされた内容を実行させない安全なApache設定またはオブジェクトストレージを別途用意する。

    STATIC_ROOTを設定した後、Apacheが配信する静的ファイルを集約。

    $ /var/www/vops/bin/python /var/www/vops/ops/manage.py collectstatic --noinput
    
  • ログの設定(任意)
    まずは標準エラーへ出力するStreamHandlerを使うと、Apache側のエラーログやサービス管理機能へ集約しやすい。
    FileHandlerを使う場合は、mod_wsgiの実行ユーザーが出力先へ書き込める権限とSELinux設定を別途用意する。
    LOGGING = {
        'version': 1,
        'disable_existing_loggers': False,
        'formatters': {
            'all': {
                'format': ' *** '.join([
                    "[%(levelname)s]",
                    "asctime:%(asctime)s",
                    "module:%(module)s",
                    "message:%(message)s",
                    "process:%(process)d",
                    "thread:%(thread)d",
                ])
            },
        },
        'handlers': {
            'console': {
                'class': 'logging.StreamHandler',
                'formatter': 'all'
            },
        },
        'loggers': {
            'django': {
                'handlers': ['console'],
                'level': 'INFO',
                'propagate': False,
            },
        },
    }
    

起動確認

  • Django単体の診断
    manage.pyrunserverをループバックアドレスだけにバインドし、VPS内から確認。
    これは問題の切り分け用であり、本番トラフィックには使用しない。
    上記のSECURE_SSL_REDIRECT=Trueが有効なため、このHTTPリクエストではHTTPSへのリダイレクトが返ればDjangoが応答していることを確認できる。
    画面内容まで確認する場合は、本番設定を弱めず、リダイレクトを無効にした開発用設定を別途使用。

    $ /var/www/vops/bin/python /var/www/vops/ops/manage.py runserver 127.0.0.1:8080
    $ curl -I -H 'Host: example.com' http://127.0.0.1:8080/
    
  • 本番環境の起動確認
    DjangoのデプロイチェックとApacheの構文確認を行い、ApachePostgreSQLを再起動。
    その後、https://example.comへアクセスし、作成したアプリがApache経由で表示されれば成功となる。

    $ /var/www/vops/bin/python /var/www/vops/ops/manage.py check --deploy
    $ apachectl configtest
    $ systemctl restart postgresql-9.6 httpd
    $ curl -I https://example.com/
    

    モデルを修正した場合は、manage.pymakemigrationsmigrateを実行。
    runserverとApacheは通常は別ポートで動くため競合するわけではないが、確認先を取り違えないよう、単体診断後はrunserverを停止してApache経由の結果を確認。

まとめ

  • Djangoサイト公開の仕上げでは、PostgreSQL、マイグレーション、settings.pyをまとめて確認。
  • 本番環境ではDEBUGを無効化し、ALLOWED_HOSTSやSSL/TLS関連設定を整える。
  • 起動確認はrunserverではなく、最終的にApache経由で確認。

参考文献

この記事を共有
Xで共有 Facebookで共有 LINEで共有



Copyright SIGMA-SE All Rights Reserved.
s-hama@sigma-se.jp