さくらVPSでDjangoアプリを公開する手順の備忘録

さくらVPSでDjangoアプリを公開したのでその手順のメモとして残してみます。

1. さくらVPSの契約

まずVPSを契約。とりあえず一番安いプランでいいかな。

キャプチャ3

さくらVPSを選んだ理由は、金額が固定だから。AWSだとどのくらいかかるか不明だし、サーバー構成とかよくわからないので練習がてらVPSでやってみることにしました。そのうち勉強する。

2. ドメイン契約

ドメインはXドメインで契約。もともとXサーバーでレンタルサーバーを借りていたこともあったので、その時に契約していたので。

さくらのドメインで契約してもいいけどちょっと高めなのでこっちのを使う。

ただネームサーバーをさくらの方にしておく。

キャプチャ4

さくらの方の設定は以下のリンクにやり方があったのでそれを参考にして作業。

3. 起動

基本的にマニュアルを見ながら作業。

とりあえずサーバーのコントロールパネル開いて起動させる

キャプチャ5


4. OSインストール(CentoOS7)

初期状態でインストールされているのがCentoOS6なので7にしておく。

OSのインストールからCentoOS7を選んでrootユーザーのパスワードを設定して再インストール。

キャプチャ6

スタートアップスクリプトも設定できるようだけど、余計な設定ファイルが作られるのでインストールなしで。最初は設定していたけど、他の参考ブログ通りに動かなかった。どれが必要でどれが必要でないのかが分かってないうちは余計なことはしない方がいい。

5. 初期設定(セキュリティ等)

セキュリティの強化はこれを参考

1. SSH接続

コンソールから作業してもいいですが面倒なのでSSH接続して作業。windowsなのでTera Termをインストールします。

起動したら自分のサーバーのネットワーク情報のアドレスをホストに打ち込んでrootユーザー、設定したパスワードを打ち込んで接続。

キャプチャ7

2. OSのアップデート

インストールしたては最新版ではないのでアップデートします。

yum update

いっぱい文字列が並んでインストールするか聞かれるのでyを打ち込む。

キャプチャ8

ついでにパケットフィルタをオフにしておきます。

キャプチャ9

これがあると通信ポート変更ができなくなるので。(これの設定のせいで結構時間を無駄にした)マニュアルではポート変更する手順はあるけどそこにパケットフィルタについての記述はなかったので完全に罠でした。

オフにしたらファイアウォールを起動しておきます。あと自動起動設定もしておきます。

systemctl start firewalld.service

systemctl enable firewalld.service

firewall-cmd --state

runningが出たらOK。

2.一般ユーザーの作成

セキュリティ的にrootユーザーでのログイン、パスワード認証はよろしくないので一般ユーザーを作って作業します。あと公開鍵を作って認証できるようにします。

useradd xxxxx #create user
passwd xxxx # set passward

※xxxxは好きなユーザー名


3. sudo設定

次に一般ユーザーでsudoができるようにします。これでroot権限での操作が一般ユーザーでも可能になります。

usermod -G wheel xxxx

ここで一度SSH接続を切って、作ったユーザーで接続しなおします。

4. 公開鍵認証

一般ユーザーでログインしたら、公開鍵認証できるようにします。

TeraTermでSSH鍵生成を生成します。生成方法は参考参照。(さくらの方はバージョンが若干古かった)


で、TeraTermに作った鍵ファイル(.pub)をドラッグアンドドロップしてサーバーに送り込みます。で、マニュアルに書いてあるコマンドを実行

cd                                  
mkdir .ssh                       
chmod 700 .ssh/                      
mv id_rsa.pub .ssh/authorized_keys   
chmod 600 .ssh/authorized_keys 

で、いったんログアウトして、今度は公開鍵認証でログインする。パスフレーズはサーバーのユーザーではなくて公開鍵を作った時のものなので注意(最初結構間違えた)

あとは rootログイン、パスワード認証の禁止、ポートの変更をしていきます。

sudo vi /etc/ssh/sshd_config

でコンフィグファイルを開いて編集。

Linuxのコマンドは普段使っているテキストエディタと違うので慣れるのが大変……

PermitRootLogin no

PasswordAuthentication no 

Port xxxx

それぞれ変更します。port番号は1024以降を使えばいいそうです。ただ使われているポートもあるのでバッティングしないように決めておきましょう。

次にファイアウォールの方の設定も変えておきます。

sudo vi /usr/lib/firewalld/services/ssh.xml

port=”22″の部分にさっき設定したポート番号を入力。設定が終わったら設定を有効にするためのコマンドを入力。

sudo systemctl restart sshd
sudo firewall-cmd --reload

これで大体のセキュリティ設定は完了。

あとはこまごました設定を行います。

・OSの自動アップデート設定

・SELinuxの無効

・ロケールの変更

sudo yum install yum-cron
sudo vi /etc/yum/yum-cron.conf
apply_updates = yes
sudo systemctl start yum-cron.service
sudo systemctl enable yum-cron.service

sudo setenforce 0

sudo localectl status

sudo localectl set-locale LANG=ja_JP.utf-8
source /etc/locale.conf

6. Nginxインストール+設定

ということで次。Nginxを入れていきます。

Djangoの構成としてよく使われているのがNginx+Gunicornだそうなので自分もそれでやっていきます。

sudo yum install -y nginx

sudo systemctl start nginx
sudo systemctl enable nginx

sudo firewall-cmd --add-service=http --permanent
sudo firewall-cmd --reload

最初がインストールコマンド、あとの2行が起動と自動起動の設定、最後の2行がファイアウォールにhttp通信を許可するコマンド。

7. https化とドメイン設定

Let’s Encryptを使ったhttps化と取得したドメインでアクセスできるようにしていきます。

sudo yum install epel-release
sudo yum install certbot

sudo systemctl stop nginx
sudo certbot certonly --standalone -d eveningmoon.net
sudo systemctl start nginx

sudo vim /etc/nginx/conf.d/eveningmoon.net.conf

eveningmoon.netは私が取得したドメイン名で、他の人がやる場合はこの部分を書き換えてください。

/etc/nginx/conf.d/eveningmoon.net.conf

server {
       listen 80;
       listen [::]:80;
       server_name eveningmoon.net;
       return 301 https://$host$request_uri;
}

server {
       listen  443 ssl;
       server_name     eveningmoon.net;
       #ssl on;
       ssl_certificate         /etc/letsencrypt/live/eveningmoon.net/fullchain.pem;
       ssl_certificate_key     /etc/letsencrypt/live/eveningmoon.net/privkey.pem;
}

設定し終えたらファイアウォールにhttpsを許可、再起動

sudo firewall-cmd --add-service=https --permanent
sudo firewall-cmd --reload

キャプチャ10

アドレスにドメイン名を打ち込んで鍵マーク出ればOK。

3か月で有効期限が切れるのでcronでの自動更新を設定しておきます。

sudo crontab -e

00 0 * * 0 certbot renew --pre-hook "systemctl stop nginx" --post-hook "systemctl start nginx"

8. Pythonインストール

ようやくpythonのインストールです……疲れた。でももう少し。頑張る。

CentoOSにはデフォルトではPython 2だけが入っているので新しいDjangoを使うためにpython3をインストールします。

インストールはソースファイルからビルドする方法か、yumでのインストールがあるみたいですが、yumは最新版がない場合もあるのでソースからの方がよさそうですね。自分がいれようとしている3.8も現時点ではないようなのでソースファイルから頑張ってみます。

下準備として外部のパッケージをインストール

sudo yum install zlib-devel libffi-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel libuuid-devel xz-devel

足りないものがあればあとでインストールしなおしてまたビルドすればいいとのこと。

今回はpython3.8.0をインストールします。

curl -O https://www.python.org/ftp/python/3.8.0/Python-3.8.0.tgz
tar xf Python-3.8.0.tgz
cd Python-3.8.0
./configure
make
sudo make altinstall

インストールが終わったらパスを追加してpythonコマンドを使えるようにします。

sudo visudo

#以下を書き換え
Defaults    secure_path = /sbin:/bin:/usr/sbin:/usr/bin
↓
Defaults    secure_path = /sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin

Python3.8と打ち込んでpythonのバージョンが出ればOKです。これでPythonが使えるようになりました。

9. Djangoアプリケーションファイルの転送

前提としてリモートリポジトリにDjangoアプリを事前に作っている状態だとします。それをサーバーに転送します。

自分はBitbucketに非公開リポジトリを作ってます。

git cloneコマンドでファイルをコピーしておきます。

10. Djangoインストールと設定

sudo pip3.8 install -r requirements.txt

事前にrequirements.txtを作っておいてそれをpipでまとめてインストールします。参考。

次にSQLiteを最新版にします。コマンドを使おうとすると最新版じゃないと怒られるので……(これの解決方法を調べるのに結構かかった)

sudo wget https://www.sqlite.org/2020/sqlite-autoconf-3310100.tar.gz
tar xvfz sqlite-autoconf-3310100.tar.gz

cd sqlite-autoconf-3310100
./configure --prefix=/usr/local
make
sudo make install
sudo find /usr/ -name sqlite3

cd

sudo mv /usr/bin/sqlite3 /usr/bin/sqlite3_old
sudo ln -s /usr/local/bin/sqlite3 /usr/bin/sqlite3

export LD_LIBRARY_PATH="/usr/local/lib"

sudo echo "/usr/local/lib" >> /etc/ld.so.conf.d/sqlite.conf
sudo ldconfig

これで多分大丈夫。/usr/local/libを追加するのがミソなよう。


終わったら作ったアプリのsettings.pyを開いて

ALLOWED_HOSTS = ["(ドメイン or IPアドレス)"]

にしておきます。DEBUG もFalseにしておきます。

静的ファイルを配信できるようにNginx用に設定をします。

STATIC_URL = '/static/'  # これは元からあります。
STATIC_ROOT = '/usr/share/nginx/html/static'

MEDIA_URL = '/media/'
MEDIA_ROOT = '/usr/share/nginx/html/media'

フォルダも作ります。

sudo mkdir /usr/share/nginx/html/media
sudo mkdir /usr/share/nginx/html/static

あとはstaticファイルを集めてそこに転送します。

sudo python3.8 manage.py collectstatic

開発環境で記事などを作っていた場合はメディアファイルもコピーしておきます。メディアフォルダに入って

sudo cp * /usr/share/nginx/html/media


そうしたらあとはmigrateと、createsuperuser でスーパーユーザーを作成しておきます。

python3.8 manage.py migrate
python3.8 manage.py createsuperuser

それが終わったらNginxの設定です。ちょっと前のファイルを編集

sudo vim /etc/nginx/conf.d/eveningmoon.net.conf

/etc/nginx/conf.d/eveningmoon.net.conf

server {
   listen 80;
   listen [::]:80;
   server_name eveningmoon.net;
   return 301 https://$host$request_uri;
}


server {
   listen  443 ssl;
   server_name eveningmoon.net;

   #ssl on;
   ssl_certificate         /etc/letsencrypt/live/eveningmoon.net/fullchain.pem;
   ssl_certificate_key     /etc/letsencrypt/live/eveningmoon.net/privkey.pem;

   location /static {
       alias /usr/share/nginx/html/static;
   }

   location /media {
       alias /usr/share/nginx/html/media;
   }

   location / {
       proxy_pass http://127.0.0.1:8000;
       proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
       proxy_set_header Host $http_host;
       proxy_redirect off;
       proxy_set_header X-Forwarded-Proto $scheme;
   }
}

eveningmoon.netの部分は各自のドメインにしてください。

ssl onはいつの間にか非推奨なよう

11. Gunicornインストール、起動

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

sudo pip3.8 install gunicorn

プロジェクトフォルダに入って、


sudo gunicorn --bind 127.0.0.1:8000 myblog.wsgi:application

myblogはプロジェクト名です。各自のプロジェクト名にしてください。

でドメインにアクセス。

キャプチャ

ちゃんと読み込まれてますね。


あとはデーモンモードで立ち上げにしておきます。(コマンドが効くようになります)

sudo gunicorn --daemon --bind 127.0.0.1:8000 myblog.wsgi:application

お疲れさまでした……

12. デプロイで詰まった点

資料はいっぱいありますが実際にやってみて詰まった点を挙げておきます。

実際、問題があって何回もOS再インストールしたり周回してようやくできたので多分同じようなところで躓く人多そうな気がします。

・ssh通信のポート変更ができない

→パケットフィルタが有効になっていたため。完全に罠だよ……

・公開鍵認証

→ユーザーとパスワードをそれぞれ別にしてごっちゃになっていた。(完全に自分のせい)

・nginxインストール後に上手く動かない。

→ssl on コマンドでエラーが出るようになったのでそこを消すかコメントアウトする必要がある。(参考にした資料にはこの記述が多かった)

・さくらが提供しているhttps通信のスクリプト。

→のちのち自分でconfファイルを作るので、利用してもいいけどスクリプトで作られたconfファイルの場所を確認しておくこと。同じドメインで複数の設定があるとうまくないよ。

・SQLITEのアップデート

→資料通りにやった後にパスを通すところがしばらくわからずsudoだけ古いSQLITEになっていた。

・静的ファイルのコレクション

→最初STATICFILES_DIRSをコメントアウトしていてコレクションされなかった。(完全に自分のせい)

・gunicornを起動するサイトの名前と作業場所

→プロジェクトフォルダでプロジェクト名で実行ということに気付きようやくできた。

実際やってみると色々と勉強になりますね。まだまだ知識が足りないけど……

13. 参考URL

今回の記事は主に以下の記事を参考にして作りました。

AWSだけどこの辺りも


良ければサポートお願いします。サポート費用はサーバー維持などの開発費に使わせていただきます。