Ubuntu + Nginx + MySQLでDjangoアプリをデプロイ（構築編）

GMOクラウドALTUS(アルタス)と契約して、開発したDjangoアプリケーションを Nginx + uWSGI + MySQL + Python3 の環境にデプロイしたので、実行した操作を備忘録として残したいと思います。単なる作業メモなので、必ずしもベストプラクティスではないことにご注意下さい。間違いや不足があれば遠慮なくご指摘下さい（笑）

#運用環境
まず、WSGI(Web Server Gateway Interface)とは、Pythonで記述したアプリケーションとWebサーバーの間の標準インターフェース(PEP333)で、uWSGIはWSGI仕様に従ったWebアプリケーションを動かすことができるWebサーバーを指します。

Djangoで作成したアWebプリケーションはWSGIで動作するように設計していて、様々な構成で運用できるのですが、今回はPycon2015のYuri Umezakiさんの発表（[uWSGI/Dockerを利用したWebサービス運用事例](https://www.youtube.com/watch?v=zsoqAf-c3_s&index=23&list=PLMkWB0UjwFGkE3BIm4qpwaK5oPrmLLJoT)）を参考に以下の構成で構築しました。

- GMOクラウドALTUS Basicプラン
- Ubuntu 16.04.1 LTS (GNU/Linux 4.4.0-47-generic x86_64)
- Nginx 1.11.6
- uWSGI 2.0.14
- MySQL 5.7.16
- Python 3.5.2
- Django 1.10.3


# アプリケーション構成
Web Browser <--> Nginx <--> socket <--> uWSGI <--> Djnago <--> MySQL


#ディレクトリ構成
```
/
└── var/
    └── www/
        └── example.jp/           <- デプロイ先のフォルダ
            ├── venv/             <- 仮想環境のディレクトリ
            │   ├── app           <- Djangoアプリケーションのプロジェクトルート(django-admin startproject app で作成)
            │   │   └ main        <- Djangoアプリケーションのアプリケーションルート(python manage.py startapp main)
            │   ├── uwsgi.ini     <- uwsgiの起動オプションを管理するINIファイル
            │   └── uwsgi_params  <- uswgiの変数を格納するファイル
            └── static            <- 静的ファイルを格納するディレクトリ
```

#サーバーの初期設定
####1. ファイアウォールの設定
***
GMOクラウドALTUSにはファイアウォールを画面から設定できる機能があるので、[GMOクラウド ALTUSアルタス Basicシリーズ ガイド - セキュリティグループの新規作成](https://support.gmocloud.com/pf/guide/basic/console/make_security.html)に従って、設定します。まず、「22」と「80」のみポートを解放しました。


####2. 仮想サーバーにログイン
***
GMOクラウドALTUS - BasicプランのUbuntuのテンプレートで仮想サーバーを作成します。作成できたら、「cloud」というユーザーでログインできます。仮想サーバー作成後に、仮想サーバーのログインパスワードをダイアログに表示します。他の画面で確認することができないので、忘れないようメモします。


####3. SSHポートの変更とrootユーザーによるログインの禁止
***
SSHのポート番号「22」はよくハッキング攻撃を受けるので、22から他の番号(今回は2222)に変更します。また、rootユーザーによるパスワード認証については、「PermitRootLogin prohibit-password」で、デフォルトでもできない状態にあるので、最低限必要な設定は完了した状態ですが、念のため、root ユーザーによる SSH ログインは一切禁止します。

```
# sshd_configファイルを編集
[cloud]$ sudo vi /etc/ssh/sshd_config
[sudo] password for cloud:          <- cloudユーザーのパスワードを入力
```

```diff:/etc/ssh/sshd_config
# What ports, IPs and protocols we listen for
-Port 22
+Port 2222
(中略)

# Authentication:
(中略)
-PermitRootLogin prohibit-password
+PermitRootLogin no
```


####4. SSHサービスの再起動
***
今までの変更を反映するためにSSHサービスを再起動します。

```
[cloud]$ sudo service ssh restart
```

再起動できたら、ファイアウォールで「22」のポートを閉じて、「2222」のポートを開放します。ポートの開閉ができたら、

- ポート「22」による接続は拒否すること
- ポート「2222」、rootユーザーでログインできないこと
- ポート「2222」、cloudユーザーでログインできること

を確認します。


####5. 公開鍵認証によるSSH接続
***
[SSHポートの変更とrootユーザーによるログインの禁止](#3-sshポートの変更とrootユーザーによるログインの禁止)でrootユーザーで直接ログインすることを禁止し、一般ユーザーでのみログインできるように設定変更しましたが、より安全に使うために公開鍵認証を使ってログインするように設定します。

公開鍵認証について知りたい方は[「よく分かる公開鍵認証」～初心者でもよくわかる！VPSによるWebサーバー運用講座(2)](http://knowledge.sakura.ad.jp/beginner/3543/)を参考にして下さい。

また、僕はSSHクライアントとしてTera Termを利用しているのですが、Tera Termにおける公開鍵認証の設定方法については[公開鍵認証によるSSH接続 - Tera Termの使い方](http://webkaru.net/linux/tera-term-ssh-login-public-key/)や[SSH公開鍵暗号化方式－Tera Termで公開鍵認証ログイン](http://www.j-oosk.com/teraterm/authorized_keys/306/)を参考にして下さい。

上記リンク先に従って、Tera Termで公開鍵認証の設定が完了したら、

```diff:/etc/ssh/sshd_config
# Change to no to disable tunnelled clear text passwords
-#PasswordAuthentication yes
+PasswordAuthentication no
```

を編集します。

編集できたら、[4. SSHサービスの再起動](#4-sshサービスの再起動)のようにSSHサービスを再起動して、認証方法がパスワード認証から公開鍵認証に切り替わったことを確認します。


####6. パッケージ管理システムの更新
***
apt-getはDebian系のディストリビューション（DebianやUbuntu）のパッケージ管理システムであるAPT(Advanced Package Tool)ライブラリを利用してパッケージを操作・管理するコマンドで、インストールしたいアプリケーションの依存関係も含めて一括でインストール/アンインストールできます。

```
# パッケージを管理するデータベースを更新（パッケージ自体は更新しない）
[cloud]$ sudo apt-get update

# インストール済みのパッケージを更新
[cloud]$ sudo apt-get upgrade
```
参考：
[【Ubuntu】apt-getでパッケージをinstall / uninstall / upgrade](http://kawatama.net/web/296)
[apt-getの使い方](http://d.hatena.ne.jp/liquidfunc/20110503/1304349183)
[apt-get - パッケージの操作・管理 - Linuxコマンド](http://webkaru.net/linux/apt-get-command/)
[APT HOWTO (Obsolete Documentation) 第3章 - パッケージの管理](https://www.debian.org/doc/manuals/apt-howto/ch-apt-get.ja.html)
[Ubuntu/aptコマンドの操作ログの在処と確認方法](http://linux.just4fun.biz/Ubuntu/apt%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%81%AE%E6%93%8D%E4%BD%9C%E3%83%AD%E3%82%B0%E3%81%AE%E5%9C%A8%E5%87%A6%E3%81%A8%E7%A2%BA%E8%AA%8D%E6%96%B9%E6%B3%95.html)


####7. ロケール(言語など)を日本向けに変更
***
デフォルトのロケールが英語圏向けで、メッセージや日付を英語圏向けに表示するので、ロケールを日本向けに変更する。

```
# 変更前のロケールを確認
[cloud]$ locale

# 英語圏のロケールであることを確認
[cloud]$ date
Fri Dec 16 10:01:01 JST 2016

# 日本語パックをインストール
[cloud]$ sudo apt-get install language-pack-ja

# ロケールを更新
[cloud]$ sudo update-locale LANG=ja_JP.UTF-8

# OSの再起動
[cloud]$ sudo shutdown -r now

# 変更後のロケールを確認
[cloud]$ locale

# 日本語圏のロケールに変わったことを確認
[cloud]$ date
```


####8. 時刻の同期
***
Ubuntuは15.04まではntpdateを使って時刻の同期を行っていましたが、15.10からはSystemdの機能を使って時刻の同期を行っています。初期設定では時刻の同期に「ntp.ubuntu.com」というNTPサーバーを使っているので、NICT(情報通信研究機構)のNTPサーバー(ntp.nict.jp)に変更します。

```
# 時刻同期の設定を確認
[cloud]$ systemctl -l status systemd-timesyncd

# 時刻の取得先を変更
[cloud]$ sudo sed -i 's/#NTP=/NTP=ntp.nict.jp/g' /etc/systemd/timesyncd.conf

? # OSの再起動
? sudo shutdown -r now

# 時刻同期サービスを再起動
[cloud]$ sudo systemctl restart systemd-timesyncd.service

# 時刻同期の設定を確認
[cloud]$ systemctl -l status systemd-timesyncd

# 時刻を表示
[cloud]$ date
```
※参考：
[Ubuntu 16.04と15.10で時刻合わせの設定を変更する](http://sicklylife.hatenablog.com/entry/2016/02/03/201557)
[systemdわからん](http://qiita.com/lastcat_/items/0344315894db41e1836a)


# Nginxユーザーの作成
後程、Nginxをインストールするにあたり、NginxというグループとNginxというログインできないユーザーを作成します。下記の割り当てポリシーに従って、100番代のグループIDとユーザーIDを設定します。

| 用途              | 範囲 |
| ----------------- |------------|
| システム管理者     | 0 - 99 |
| システムアカウント | 100 - 999 |
| ユーザーアカウント | 1000 - 29999 |
| 予約              | 30000 - 59999 |

```
# 使用済みのグループIDを確認
[cloud]$ cat /etc/group

# nginxグループを作成
[cloud]$ sudo groupadd -g [グループID] nginx

# 使用済みのユーザーIDを確認
[cloud]$ cat /etc/passwd

# nginxグループに属するnginxユーザーを作成
[cloud]$ sudo useradd -g nginx -u [ユーザーID] -d /nonexistent -s /bin/false nginx
```

#共用ユーザーの作成
アプリケーションを実行するユーザーとしてappユーザーを作成します。

```
# appユーザーを追加
[cloud]$ sudo useradd app -g nginx

# appユーザーを確認
[cloud]$ sudo cat /etc/passwd

# appユーザーの所属グループを確認
[cloud]$ sudo groups app

# appユーザーのパスワードを設定
[cloud]$ sudo passwd app

# appユーザーに切り替えできることを確認
[cloud]$ su app

# appユーザーからログアウト
[app]$ exit
```


# Pythonの設定
パッケージはグローバルにインストールするのではなく、プロジェクトごとに独立してインストールして使いたいと思います。Python3.3からvirtualenvに代わりpyvenvというのが使用できるようなので、pyvenvを使う。
#####
```
# GMOクラウドALTUSのUbuntu 16.04のテンプレートにはPythonがインストール済み。
# インストール済みのPythonを確認。
[cloud]$ python3 -V

# pipをインストール
[cloud]$ sudo apt install python3-pip

# pipを更新
[cloud]$ pip3 install --upgrade pip

# pyvenvをインストール
[cloud]$ sudo apt install python3-venv
```
参考：
[pyenvとvenvでPython3開発環境を整える](http://blog.muuny-blue.info/b3ddb7c5b10be95dbc3f9152c58becce.html)
[Windowsでpyenvとかvirtualenvを使おうと思ったときに学んだことのメモ](http://qiita.com/nobolis/items/12a464557f2ae007e9a1)


# Nginxの設定
後々、WEBサイトの高速化・最適化も実施したいので、今回はGoogleが開発したPageSpeedモジュール(ngx_pagespeed)をNginxに組み込んで利用することにします。Googleが用意したシェルスクリプトを使ってNginx + ngx_pagespeedをソースからインストールします。

```
# unzipコマンドをインストール
[cloud]$ sudo apt-get install unzip

# OpenSSLのライブラリをインストール
[cloud]$ sudo apt-get install libssl-dev

# PCREのライブラリは正規表現ライブラリ
# URLのrewriteやLocationの指定で正規表現によるマッチングができるようになる
[cloud]$ sudo apt-get install libpcre3-dev

# バッファのキャッシュ先ディレクトリを作成
[cloud]$ sudo mkdir -p /var/cache/nginx/client_temp

# バッファのキャッシュ先ディレクトリの所有者を変更
[cloud]$ sudo chown nginx:root /var/cache/nginx/client_temp

# バッファのキャッシュ先ディレクトリの権限を変更
[cloud]$ sudo chmod 700 /var/cache/nginx/client_temp

# rootユーザーに切り替え
[cloud]$ sudo su -

# 最新のNginxとPageSpeedモジュール(ngx_pagespeed)をインストール
[root]$ bash <(curl -f -L -sS https://ngxpagespeed.com/install) --nginx-version latest -b /usr/local/src

# 途中で追加のconfigureオプションを指定できるダイアログが出るので、追加のオプションを指定する
(中略)
About to build nginx.  Do you have any additional ./configure
arguments you would like to set?  For example, if you would like
to build nginx with https support give --with-http_ssl_module
If you don't have any, just press enter.
> --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-file-aio --with-threads --with-ipv6 --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_ssl_module --with-cc-opt='-g -O2 -fstack-protector-strong -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -Wl,--as-needed'

# rootユーザーからログアウト
[root]$ exit

# Nginxのバージョンを確認
[cloud]$ nginx -V

# Nginxを起動
[cloud]$ sudo nginx
```

Nginxを起動後、http://[IPアドレス]にブラウザで接続して、NginxのWelcomeページが表示できればOK！

ngx_pagespeedの設定については、後日UPする運用編で紹介するとして、今回は取り敢えず機能を有効にする部分のみを確認したいと思います。

/etc/nginx/nginx.confのserverディレクティブにPageSpeedを有効にする設定を追記します。nginx.confのserverディレクティブに

```diff:/etc/nginx/nginx.conf
http {
    (中略)
    server {
         (中略)
+        pagespeed on;
+        pagespeed RewriteLevel CoreFilters;
+        pagespeed FileCachePath /var/cache/ngx_pagespeed_cache;
+        pagespeed EnableFilters collapse_whitespace,trim_urls,remove_comments;
         (中略)
    }

}
```

を追記できればNginxを再起動して、リクエストをレスポンスを確認します。レスポンスヘッダに「X-Page-Speed:1.11.33.4-0」があればOK！

```
# Nginxを再起動
[cloud]$ sudo nginx -s reload

# リクエストを投げ、レスポンスヘッダーをチェック
[cloud]$ curl -I 'http://localhost/' | grep X-Page-Speed
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
X-Page-Speed: 1.11.33.4-0
```

参考：
[Build ngx_pagespeed From Source](https://developers.google.com/speed/pagespeed/module/build_ngx_pagespeed_from_source)
[Nginx + PageSpeed(ngx_pagespeed)を導入して WEBサイトを高速化する方法](http://www.e-agency.co.jp/column/20130621.html)
[nginx連載1回目: nginxの紹介](https://heartbeats.jp/hbblog/2012/01/nginx01.html)
[PageSpeedを使ってWebサイトを最適化・高速化しよう](http://knowledge.sakura.ad.jp/tech/1599/)
[NGINX-1.5.12. コンパイル　インストール手順](http://face-web.websample.jp/2014/07/nginx-1-5-12/)
[[Debian][CentOS][Ubuntu]ユーザIDのポリシー、割り当てルールについて調べる](http://d.hatena.ne.jp/spidy_spidy/20080411/1207924144)
[Ubuntu Policy Manual - 9.2.2 UID and GID classes](http://people.canonical.com/~cjwatson/ubuntu-policy/policy.html/ch-opersys.html#s9.2.2)


#MySQLの設定
```
# MySQL5.7をインストール
$ sudo apt-get -y install mysql-server-5.7

# rootユーザーでログイン
$ mysql -u root -p

# データベースを作成
mysql> CREATE DATABASE `[データベース名]` DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;

# mysqlデータベースを選択
mysql> USE 'mysql';

# ユーザー情報を表示
mysql> select user,host from mysql.user;

# ユーザーの作成＆作成したデータベースに対して権限(CREATE, ALTER, REFERENCES, INDEX, SELECT, UPDATE, INSERT, DELETE)付与
mysql> GRANT CREATE,ALTER,REFERENCES,INDEX,SELECT,UPDATE,INSERT,DELETE ON [データベース名].* TO '[ユーザー名]'@'localhost' IDENTIFIED BY '[パスワード]';

# 作成したユーザーの権限を確認
mysql> SHOW GRANTS for '[ユーザー名]'@'localhost';

# MySQLからログアウト
mysql> exit
```
※参考
[MySQL インストール](https://www.server-world.info/query?os=Ubuntu_16.04&p=mysql)
[Using MySQL with Django - Access denied for user '@'localhost](http://stackoverflow.com/questions/11170133/using-mysql-with-django-access-denied-for-user-localhost)
[MySQL/ユーザとDB作成](http://wiki.minaco.net/index.php?MySQL%2F%E3%83%A6%E3%83%BC%E3%82%B6%E3%81%A8DB%E4%BD%9C%E6%88%90)


# デプロイ先のディレクトリの作成
```
# デプロイ先のディレクトリを作成
[cloud]$ sudo mkdir -p /var/www/example.jp

# デプロイ先のディレクトリの所有者を変更
[cloud]$ sudo chown root:nginx /var/www/example.jp

# デプロイ先のディレクトリの権限を変更
[cloud]$ sudo chmod g+w /var/www/example.jp

# appユーザーへ切り替え
$ su app

# venvという仮想環境を作成。
[app]$ /usr/bin/pyvenv /var/www/example.jp/venv

# 作成した仮想環境を有効化。仮想環境が有効化になると「([evn名])」がシェルの先頭につく。
[app]$ source /var/www/example.jp/venv/bin/activate

# 仮想環境のpipを最新に更新
(venv)[app]$ pip install --upgrade pip

# 仮想環境にDjangoをインストール
(venv)[app]$ pip install Django

# 仮想環境にuWSGIをインストール
(venv)[app]$ pip install uwsgi

# DjangoからMySQLに接続できるようにするため、仮想環境にPyMySQLをインストール
(venv)[app]$ pip install PyMySQL

# 一旦仮想環境を無効にする
(venv)[app]$ deactivate
```
作成したDjangoアプリケーションをデプロイする方法としてはGitを使ったりFTPソフトを使ったり色々方法はあると思いますが、今回は取り敢えず、FTPソフトを使ってサーバーにアップロードします。

作成したDjangoアプリケーションをFTPソフトで「/var/www/example.jp/venv/」配下にappユーザーでアップロードします。しかし、[公開鍵認証によるSSH接続](#5-公開鍵認証によるssh接続)でパスワード認証を禁止して公開鍵認証でログインするように変更したので、FTPソフトでも公開鍵認証できるように設定しなければなりません。

僕はFTPソフトとしてWinSCPを使っているのですが、WinSCPではPuTTY形式の秘密鍵にしか対応していないので、[公開鍵認証によるSSH接続](#5-公開鍵認証によるssh接続)で作成した秘密鍵をPuTTY形式に変換しました。

ログイン画面から編集ボタンをクリックして、「高度なサイトの設定」を画面を表示します。ナビゲーションの「SSH」⇒「認証」をクリックして、「秘密鍵」の「ファイル選択」ボタンをクリックすると、「秘密鍵の選択」画面が出現するので、[公開鍵認証によるSSH接続](#5-公開鍵認証によるssh接続)で作成した秘密鍵を選択すると、自動的にPuTTY形式の秘密鍵に変換します。

# uWSGIの設定
```
# appユーザーからログアウト
[app]$ exit

# uWSGIのsocketファイルとpidファイルを格納するディレクトリを作成
[cloud]$ sudo mkdir -p /var/run/uwsgi

# uWSGIのsocketファイルとpidファイルを格納するディレクトリの所有者を変更
[cloud]$ sudo chown root:nginx /var/run/uwsgi

# uWSGIのsocketファイルとpidファイルを格納するディレクトリの権限を変更
[cloud]$ sudo chmod g+w /var/run/uwsgi

# uWSGIのログファイルを格納するディレクトリを作成
[cloud]$ sudo mkdir -p /var/log/uwsgi
```

uWSGIのための変数を定義するファイル(uwsgi_params)を、/var/www/example.jp/venv/配下に作成します。

```vim:/var/www/example.jp/venv/uwsgi_params
uwsgi_param  QUERY_STRING       $query_string;
uwsgi_param  REQUEST_METHOD     $request_method;
uwsgi_param  CONTENT_TYPE       $content_type;
uwsgi_param  CONTENT_LENGTH     $content_length;

uwsgi_param  REQUEST_URI        $request_uri;
uwsgi_param  PATH_INFO          $document_uri;
uwsgi_param  DOCUMENT_ROOT      $document_root;
uwsgi_param  SERVER_PROTOCOL    $server_protocol;
uwsgi_param  REQUEST_SCHEME     $scheme;
uwsgi_param  HTTPS              $https if_not_empty;

uwsgi_param  REMOTE_ADDR        $remote_addr;
uwsgi_param  REMOTE_PORT        $remote_port;
uwsgi_param  SERVER_PORT        $server_port;
uwsgi_param  SERVER_NAME        $server_name;
```

uWSGIの起動オプションを設定したuwsgi.iniを作成します。

```vim:/var/www/example.jp/venv/uwsgi.ini
[uwsgi]
uid = nginx
gid = nginx

# Django-related settings
# the base directory (full path)
# 自分の環境に合わせて変更して下さい
chdir = /var/www/example.jp/venv/app

# Django's wsgi file
# 自分の環境に合わせて変更して下さい(基本的には「Djangoのプロジェクト名.wsgi」を設定)
module = app.wsgi

# the virtualenv (full path)
# 自分の環境に合わせて変更して下さい
home = /var/www/example.jp/venv


# process-related settings
# master
master = true

# maximum number of worker processes
processes = 2

threads = 1

# the socket (use the full path to be safe
socket = /var/run/uwsgi/master.sock

pidfile = /var/run/uwsgi/master.pid

# ... with appropriate permissions - may be needed
chmod-socket = 666

# clear environment on exit
vacuum = true

thunder-lock = true

max-requests = 6000
max-requests-delta = 300

# log
logto = /var/log/uwsgi/uwsgi.log
deamonize = /var/log/uwsgi/uwsgi-@(exec://date +%Y-%m-%d).log
log-reopen = true
```

# Nginxの設定
今後、複数のアプリケーションを同一サーバーで運用する場合も想定して仮想ホストの設定を行います。

「/etc/nginx/sites-available」と「/etc/nginx/sites-enabled」というディレクトリを作成して、
「/etc/nginx/sites-available」には仮想ホストの設定ファイルを格納します。

Nginxが起動した時に「/etc/nginx/sites-enabled」配下を読み込むようにして、「/etc/nginx/sites-enabled」では「/etc/nginx/sites-available」配下の設定ファイルへシンボリックリンクを張ったり削除したりすることで、仮想ホストの設定を有効にしたり無効にしたりできるようにし管理を楽にします。

```
# 仮想ホストの設定ファイルを格納するディレクトリを作成する
[cloud]$ sudo mkdir /etc/nginx/sites-available

# 有効にしたい仮想ホストの設定ファイルへのシンボリックリンクを格納するディレクトリを作成する
[cloud]$ sudo mkdir /etc/nginx/sites-enabled
```

「/etc/nginx/sites-available/」配下に仮想ホストの設定ファイルを作成します。

```vi:/etc/nginx/sites-available/example.jp
# the upstream component nginx needs to connect to
upstream django {
    # for a file socket
    server unix:///var/run/uwsgi/master.sock;
}

# configuration of the server
server {
    # the port your site will be served on
    listen      80;
    # the domain name it will serve for
    # substitute your machine's IP address or FQDN
    server_name [IPアドレスまたはドメイン];
    charset     utf-8;

    # max upload size
    # Django media
    location /static {
        # your Django project's static files - amend as required
        # 自分の環境に合わせて変更して下さい。
        alias /var/www/example.jp/static;
    }

    # Finally, send all non-media requests to the Django server.
    location / {
        uwsgi_pass  django;
        # the uwsgi_params file you installed
        # 自分の環境に合わせて変更して下さい。
        include     /var/www/example.jp/venv/uwsgi_params;
    }
}
```

仮想ホストの設定ファイルが作成できたら、シンボリックリンクを張ります。

```
# 有効にしたい仮想ホストの設定ファイルへシンボリックリンクを張る
[cloud]$ sudo ln -s /etc/nginx/sites-available/example.jp /etc/nginx/sites-enabled/example.jp
```

「/etc/nginx/sites-enabled/」配下を読み込むようにhttpディレクティブに追加します。

```diff:/etc/nginx/nginx.conf
http {
     (中略)
     #gzip  on;
+    include /etc/nginx/sites-enabled/*;
     (中略)
}
```

OSを再起動してもNginxを自動で起動するように設定します。「/etc/systemd/system/nginx.service」を作成します。

```vim:/etc/systemd/system/nginx.service
[Unit]
Description=The NGINX HTTP and reverse proxy server
After=syslog.target network.target remote-fs.target nss-lookup.target

[Service]
Type=forking
PIDFile=/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t
ExecStart=/usr/sbin/nginx
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true

[Install]
WantedBy=multi-user.target
```

「/etc/systemd/system/nginx.service」が作成出来たら、

```
# Nginxが起動した状態なので、停止する
# もし「PIDファイルを開くことができない」などのエラーが出た場合はOSを再起動する
[cloud]$ sudo nginx -s stop

# サービスの開始
[cloud]$ sudo systemctl start nginx

# サービスの停止
[cloud]$ sudo systemctl stop nginx

# サービスの自動起動の有効化
[cloud]$ sudo systemctl enable nginx

# サービスの開始
[cloud]$ sudo systemctl start nginx
```

を実行して、サービスの開始／停止を実行できることを確認後、Nginxをサービスとして登録します。

```vim:サービスの他のコマンド
# サービスの再起動
$ sudo systemctl restart [サービス名]

# サービスの自動起動の無効化
$ sudo systemctl disable [サービス名]

# サービスの稼動状態を確認
$ sudo systemctl status [サービス名]

# サービスに含む全てのプロセスをKillする
$ sudo systemctl kill -s9 [サービス名]
```

参考：
[軽量で高速なウェブサーバNginxを、Ubuntu 12.04に導入する(設定編その１)](http://blog.kondoyoshiyuki.com/2012/12/09/setting-1-nginx-on-ubuntu-12-04/)
[NGINX systemd service file](https://www.nginx.com/resources/wiki/start/topics/examples/systemd/)

# Djnagoの初期設定

MySQLにデータベースやテーブルを作成したいので、DjangoのDBマイグレーションを実行します。

```
# 仮想環境を有効化
[app]$ source /var/www/example.jp/venv/bin/activate

# マイグレーションのファイルを作成
(venv)[app]$ python /var/www/example.jp/venv/pornstar/manage.py makemigrations app

# 実行するマイグレーションをSQLの形式で確認
(venv)[app]$ python /var/www/example.jp/venv/pornstar/manage.py sqlmigrate app 0001

# マイグレーションを実行
(venv)[app]$ python /var/www/example.jp/venv/pornstar/manage.py migrate
```

また静的ファイルに関しても運用環境で公開しやすい状態にするために、それぞれのアプリケーションから特定のディレクトリにコピーして集めます。以下のコマンドでに指定したディレクトリに静的ファイルをコピーします。

Djangoアプリケーションのsettings.pyを編集してSTATIC_ROOTを追加して、STATICFILES_DIRSをコメントアウトします。

```diff:/var/www/example.jp/venv/app/app/settings.py
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.10/howto/static-files/

STATIC_URL = '/static/'
+STATIC_ROOT = '/var/www/example.jp/static/'
(中略)
-STATICFILES_DIRS = (
-    os.path.join(BASE_DIR, "static"),
-)
+#STATICFILES_DIRS = (
+#    os.path.join(BASE_DIR, "static"),
+#)
```

```
# 静的ファイルのコピー
(venv)[app]$ python /var/www/example.jp/venv/app/manage.py collectstatic

# 仮想環境を無効化
(venv)[app]$ deactivate
```
参考：
[静的ファイルの公開方法](http://docs.djangoproject.jp/en/latest/howto/static-files.html)


#uWSGIの自動起動の設定
Nginxと同様、OSを再起動してもuWSGIも自動で起動するように「/etc/systemd/system/uwsgi.service」を作成します。

```vim:/etc/systemd/system/uwsgi.service
# uwsgi.service
[Unit]
Description=uWSGI
After=syslog.target

[Service]
ExecStartPre=/bin/bash -c 'mkdir -p /var/run/uwsgi; chown root:nginx /var/run/uwsgi; chmod g+w /var/run/uwsgi;'
ExecStart=/bin/bash -c 'source /var/www/example.jp/venv/bin/activate; uwsgi --ini /var/www/example.jp/venv/uwsgi.ini'
#Restart=always
Restart=on-failure
KillSignal=SIGQUIT
Type=notify
StandardError=syslog
NotifyAccess=all

[Install]
WantedBy=multi-user.target
```

「ExecStartPre」はサービス起動前に実行するコマンドを指定するオプションですが、実行するコマンドとしてuWSGIのpidファイルとsocketファイルを格納するディレクトリ(/var/run/uwsgi)を作成するよう指定しています。

なぜなら、「/var/run」は「/run」へのシンボリックリンクであり、さらに「/run」がtmpfsファイルシステムでマウントしています。すると、OSを再起動すると「/run(=/var/run)」配下のファイルを全て削除しますので、ディレクトリが無い時に備えて、ディレクトリを作成するコマンドを指定しています。

サービスの開始／停止を実行できることを確認して、自動起動を有効化します。

```
# サービスの開始
[cloud]$ sudo systemctl start uwsgi

# サービスの停止
[cloud]$ sudo systemctl stop uwsgi

# サービスの自動起動の有効化
[cloud]$ sudo systemctl enable uwsgi

# サービスの開始
[cloud]$ sudo systemctl start uwsgi
```


# Djangoの設定ファイルを更新
```diff:/var/www/example.jp/venv/app/app/settings.py
(中略)
# SECURITY WARNING: don't run with debug turned on in production!
-DEBUG = True
+DEBUG = False
-ALLOWED_HOSTS = []
+ALLOWED_HOSTS = ['IPアドレスまたはドメイン']
(中略)
```

ブラウザでhttp://[IPアドレスまたはドメイン]にアクセスして、アプリケーションが表示できればOK！

#動作しない時
- Internal Error (サーバー内部エラー)

Nginxのエラーのログファイル(/var/log/nginx/error.log)やuWSGIのログファイル(/var/log/uwsgi/uwsgi.log)を確認して、エラーを特定する。


#参考文献
1. [Nginx に uWSGI + Django アプリ を組み込む](https://www.saintsouth.net/blog/setup-django-app-with-uwsgi-and-nginx/)
1. [nginx + uWSGI + Flaskを試してみる](http://d.hatena.ne.jp/plasticscafe/20110331/1301543987)
1. [CentOS 7 + Nginx で Django アプリを公開するまでの手順](http://kodak-ism.com/how-to-release-django-app-on-centos7-and-nginx/)
1. [uWSGI で Django を使う方法](http://docs.djangoproject.jp/en/latest/howto/deployment/wsgi/uwsgi.html)
1. [Django ベストプラクティス - デプロイ - サーバー](http://django-best-practice-ja.readthedocs.io/ja/latest/deployment/servers.html)
1. [Djangoの環境構築(Ubuntu Server, Apache, PostgreSQL)](http://yura2.hateblo.jp/entry/2015/04/05/Django%E3%81%AE%E7%92%B0%E5%A2%83%E6%A7%8B%E7%AF%89(Ubuntu_Server,_Apache,_PostgreSQL))
1. [ApacheのインストールからDjangoのデプロイまで](http://akiniwa.hatenablog.jp/entry/2013/09/24/150412)
1. [便利で超強力なWSGIサーバー uWSGI を使ってみよう](http://d.hatena.ne.jp/m-hiyama/20120312/1331513519)
1. [Python Flaskアプリを nginx + uWSGI 環境下へデプロイしたのでメモ](https://zafiel.wingall.com/archives/7513)
1. [Setting up Django and your web server with uWSGI and nginx](https://uwsgi-docs.readthedocs.io/en/latest/tutorials/Django_and_nginx.html)