さくらVPSでCentOS7の設定からDjangoのデプロイまで

　Djangoでサイトを作成しようとした際に、デプロイやstaticファイル(CSS/js)の反映あたりで色々詰まったのですが、一元化されている情報源がなかなか見つかりませんでした。

　そこでCentOS7の設定〜Djangoチュートリアルのサイトをデプロイし、staticファイルを反映させるまでの手順をまとめてみました。

※ [Djangoチュートリアルサイト](https://docs.djangoproject.com/ja/2.0/intro/)で作成するサンプルアプリ(pollsアプリ)をデプロイするので、このチュートリアルをこなしていることを前提としています。
※ 普段はWebを書く人では無いので、おかしな点などご指摘頂けると幸いです。

## 環境
* MacOS X 10.11.6
* CentOS 7 (さくらVPS)
* Apache 2.4.6
* Python 3.6
* Django 2.0

## CentOSの設定
　基本的な設定は[CentOS7.x 基本設定メモ](https://qiita.com/zaburo/items/c07a7fa6fa82e97f6b10)を参考にしました。

* 作業用ユーザの作成

```:VPS
[root@hogehoge ~]# useradd username
[root@hogehoge ~]# passwd username
```
* 作成したユーザをwheelグループに追加し、sudoコマンドを許可

```:VPS
[root@hogehoge ~]# usermod -G wheel username
[root@hogehoge ~]# visudo
## Same thing without a password
# %wheel  ALL=(ALL)       NOPASSWD: ALL
ここの行の#を外す

[root@hogehoge ~]# vi /etc/pam.d/su
#auth           required       pam_wheel.so use_uid
ここの行の#を外す
```
作成したusernameユーザでログインし、`sudo su`コマンド等が使える様に。

* sshの設定

　先にディレクトリを作成。

```:VPS
[username@hogehoge ~]$ mkdir /home/username/.ssh
[username@hogehoge ~]$ chmod 700 /home/username/.ssh
```
　mac側での鍵を作成。今回は/Users/usename/.ssh/id_rsa_djangoに指定しました。

```:Mac
$ ssh-keygen -C 'for_django'
Generating public/private rsa key pair.
Enter file in which to save the key (/Users/username/.ssh/id_rsa): /Users/username/.ssh/id_rsa_django
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
...

VPSに公開鍵持って行く
$ scp ~/.ssh/id_rsa_django.pub username@[VPSのIPアドレス]:/home/username/.ssh
```
　VPSで公開鍵を設定

```:VPS
[username@hogehoge ~]$ cd /home/username/.ssh
[username@hogehoge .ssh]$ cat id_rsa_django.pub >>  authorized_keys
[username@hogehoge .ssh]$ chmod 600 authorized_keys
```
　Mac側でssh接続が可能に。
(sshの接続は/Users/username/.ssh/configに設定を記述しておくと楽ですね。)

```:Mac
$ ssh -i id_rsa_django username@[VPSのIPアドレス]
```
　余談ですが、この時、サーバの設定で詰まった際に何度もCentOS7をインストールし直したりしてると

```
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
...略
```
みたいなエラーが出ることが。`ssh-keygen -R 123.456.789.33(ホストIP)`で解決する模様。
→参照：[SSH接続で WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! って言われて接続を拒否られるとき](https://qiita.com/wnoguchi/items/690f3f4651f8f11e4ed3)

* sshdの設定

```:VPS
[username@hogehoge ~]$ sudo vi /etc/ssh/sshd_config

# 以下変更点
# ポート番号を変更
Port 22(任意の数字)
# rootログイン不可
PermitRootLogin no
# pass無し不許可
PermitEmptyPasswords no
# 鍵認証許可
PubkeyAuthentication yes
# pass認証不可
PasswordAuthentication no

# 設定を反映
[username@hogehoge ~]$ sudo systemctl restart sshd.service

```

* firewallの設定変更

　firewallの起動と自動起動設定

```:VPS
[root@hogehoge ~]# systemctl start firewalld.service
[root@hogehoge ~]# systemctl enable firewalld
[root@hogehoge ~]# systemctl status firewalld
```
　http, https, sshでの外部アクセスの許可

```:VPS
[root@hogehoge ~]# firewall-cmd --permanent --add-service=http
[root@hogehoge ~]# firewall-cmd --permanent --add-service=https
[root@hogehoge ~]# firewall-cmd --permanent --add-port=1234(任意のポート番号)/tcp
[root@hogehoge ~]# systemctl restart firewalld
```
　SELinuxを有効にする場合はそちらでも別途設定が必要な様です。
→参照：[CentOS7でsshdのポート番号を変更する方法](https://weblabo.oscasierra.net/openssh-sshd-centos7-change-port/)

　基礎的ですがひとまずサーバ設定はこんな感じで。

## CentOSにPython、Djangoを入れる

* Python3とDjangoのインストール

　CentOSにPythonをインストールします。今回はpython3.6を使用する前提で進めます。
→参照：[Python3をCentOS7にyumでインストールする手順](https://weblabo.oscasierra.net/python3-centos7-yum-install/)

```:VPS
[username@hogehoge ~]$ sudo yum install -y https://centos7.iuscommunity.org/ius-release.rpm
[username@hogehoge ~]$ sudo yum search python36
[username@hogehoge ~]$ sudo yum install python36u
```

* venv仮想環境作成

```:VPS
[username@hogehoge ~]$ python3.6 -m venv venv

# activate
[username@hogehoge ~]$ cd venv/bin
[username@hogehoge ~]$ . activate
(venv)[username@hogehoge ~]$
```

* Django2.0のインストール

```:VPS
(venv)[username@hogehoge ~]$ pip install Django==2.0
```

## デプロイ

　ここではDjango公式サイトの[チュートリアル](https://docs.djangoproject.com/ja/2.0/intro/)で作成できるpollsアプリをデプロイします。

* 必要なライブラリをインストール

```:VPS
[username@hogehoge ~]$ sudo yum install httpd-devel
[username@hogehoge ~]$ sudo yum install python36u-mod_wsgi
``` 
　Django2.0のチュートリアルでは↓の様なフォルダ構成になっているかと思います。

```
sample
├── db.sqlite3
├── manage.py
├── mysite
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
└── polls
    ├── __init__.py
    ├── admin.py
    ├── apps.py
    ├── models.py
    ├── static
    ├── templates
    ├── tests.py
    ├── urls.py
    └── views.py
```

　settings.pyのALLOW_HOSTSにIPを指定(*では全て許可)。公開するサイトのドメイン名www.example.com等でも可能

```mysite/settings.py
ALLOWED_HOSTS = ['*']
```

　VPS側でdjango_sampleディレクトリを作り、このsampleディレクトリを配置します。今回はGitHubにあげて`git clone`しています。

```:VPS
[username@hogehoge ~]$ mkdir django_sample
[username@hogehoge ~]$ cd django_sample
[username@hogehoge django_sample]$ git clone https://github.com/userid/sample.git(仮)

# この様なディレクトリ構造になる。
username
├── django_sample
    └── sample
        ├── db.sqlite3
        .
        .
```

* DjangoのApache用の設定

　公式サイトの[DjangoをApacheとmod_wsgiとともに使うには？](https://docs.djangoproject.com/ja/2.0/howto/deployment/wsgi/modwsgi/)を参考に設定していきます。
　まずは/etc/httpd/conf.d/django.confを作成、内容は↓

```/etc/httpd/conf.d/django.conf
WSGIScriptAlias / /home/username/django_sample/sample/mysite/wsgi.py
WSGIPythonPath /home/username/django_sample/sample:/home/username/venv/lib/python3.6/site-packages
<Directory /home/username/django_sample/sample/mysite>
<Files wsgi.py>
Require all granted
</Files>
</Directory>
```
　WSGIScriptAliasの最初の/は、ルートURLの設定です。
/mysiteとかにするとhttp://123.456.789.33(仮)/mysite/ がルートURLになります。

　WSGIPythonPathでアプリのルートディレクトリ及び仮想環境のライブラリディレクトリを指定しています。

　今回はユーザーディレクトリにアプリを置いているので、/etc/httpd/conf.d/userdir.conf ファイルを編集します。
→参照：[CentOS7にPython3をインストールしてDjangoを動かす](http://typea.info/blg/glob/2017/05/centos7-python3-django.html)

```/etc/httpd/conf.d/userdir.conf
<IfModule mod_userdir.c>
    #
    # UserDir is disabled by default since it can confirm the presence
    # of a username on the system (depending on home directory
    # permissions).
    #
    UserDir enable
     
    #
    # To enable requests to /~user/ to serve the user's public_html
    # directory, remove the "UserDir disabled" line above, and uncomment
    # the following line instead:
    #
    #UserDir public_html
</IfModule>
```
　ユーザーディレクトリの権限を変更

```:VPS
[username@hogehoge ~]$ cd /home
[username@hogehoge home]$ sudo chmod 755 username

```
　httpdをリスタート
 
```:VPS
[username@hogehoge ~]$ sudo service httpd restart
```

　これでルートURL http://123.456.789.33(仮) 等へアクセスすると動作が確認出来る様になるかと思います。

## DBへのアクセス権限

　このままではadminページへ入る際等に、DBファイルへのアクセスが出来ないというエラーが出るのでdb.sqlite3への権限を変更する必要があります。

　色々試して、結局以下の様にその他に権限を与えて何とかしていますが、あまりよろしくない様やり方かと思うので、他のやり方等ご存知の方いましたらご指摘頂けると助かります…。

```:VPS
[username@hogehoge ~]$ cd django_sample
[username@hogehoge django_sample]$ sudo chmod 757 sample
[username@hogehoge django_sample]$ cd sample
[username@hogehoge sample]$ sudo chmod 756 db.sqlite3
[username@hogehoge ~]$ sudo service httpd restart
```

## staticファイルの反映

　また、adminページも含め、CSSやjavascriptが反映されていないかと思いますので、Apache等Webサーバからstaticファイルを配信する様設定する必要があります。　
　`manage.py collectstatic`コマンドを使って静的ファイルをSTATIC_ROOTに集め、WebサーバがSTATIC_ROOTをSTATIC_URLの場所で公開する様に設定する形になります。

　　Django公式サイトの[ファイルを配信する](https://docs.djangoproject.com/ja/2.0/howto/deployment/wsgi/modwsgi/#serving-files)を参考に設定していきます。まずはsettings.pyの編集。最下部に以下を記述。

```settings.py
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
```
　次に/etc/httpd/conf.d/django.confに以下を追記。
http://123.456.789.33(仮)/static/ 等でstaticファイルにアクセス出来る様になる。

```/etc/httpd/conf.d/django.conf
Alias /static/ /home/username/django_sample/sample/static/

<Directory /home/username/django_sample/sample/static>
Require all granted
</Directory>
```
　settings.pyのDEBUGをFalseに変更します。

```settings.py
DEBUG = False
```
　以上の設定を行い、collectstaticコマンドを使うと、/home/django_sample/sample/static下にstaticファイルが集められ、反映されると思います。

```:VPS
(venv) [username@hogehoge sample]$ ./manage.py collectstatic
(venv) [username@hogehoge sample]$ sudo service httpd restart
```
　以上でチュートリアルのpollsアプリがstaticファイルが反映された状態で動作確認出来るかと思います。


## 補足:複数のアプリで共通のstaticファイルがある場合

　例えばcommon下のstaticファイルをpolls/polls2/polls3アプリで利用している場合。

```
sample
├── db.sqlite3
├── manage.py
├── mysite
│   ├── __init__.py
│   ...
├── polls
├── polls2
├── polls3
└── common
    └── static
        ├── css
        ├── js
        ├── images
```

　settings.pyに次の様にSTATICFILES_DIRSを記述します。

```settings.py
STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'common/static/'),
)
```

```index.html
{% load static %}
<script src="{% static 'js/common.js' %}"></script>
```
の様な形で共通のstaticファイルを利用することができます。