Djangoプロジェクトをuwsgi, nginxを使ってデプロイする

NO IMAGE

今回は、Djangoで作成したアプリケーションを、VPSにデプロイする方法を説明したいと思います。

まずは、環境ですが、

  • Ubuntu 18.04
  • Python 3.7.0
  • Django 2.2
  • PostgreSql
  • PosGis
  • Nginx
  • uwsgi

今回は、ConohaのVPSを選びました。

サーバーを作成して、サーバーのIPアドレスを調べます。

$ ssh root@(ipアドレス)
(パスワード入力)
root@(アドレス):~# 

rootユーザーでサーバーに接続できる状態はセキュリティ上好ましくないので、sudo権限を持つユーザーを作成します。-mオプションで、新規ユーザーとそのホームディレクトリを作成します。

$ useradd -m (ユーザー名)
$ passwd (ユーザー名)
$ usermod -aG sudo (ユーザー名)

作成したので、一度exitして、

$ ssh (ユーザー名)@(ipアドレス)

で、新しく作ったユーザーで入ってください。

デフォルトのシェルはshなのですが、個人的にzshにしたいのでzshにします。

$ echo $SHELL
/bin/bash
$ sudo apt install zsh
$ chsh -s $(which zsh)

一度サーバーから出て、再び入るとzshに変わっていると思います。~/.zshrcを作り、以下のようなものを入れてみました。(こちらを参考にしました。)

setopt IGNOREEOF

export LANG=ja_JP.UTF-8

autoload -Uz colors
colors

autoload -Uz compinit
compinit

bindkey -v

setopt share_history

setopt histignorealldups

HISTFILE=~/.zsh_history
HISTSIZE=10000
SAVEHIST=10000

setopt auto_cd

setopt auto_pushd

setopt pushd_ignore_dups

setopt correct

chpwd() { ls -ltr --color=auto }

cdpath=(~)

PROMPT="%(?.%{${fg[green]}%}.%{${fg[red]}%})%n${reset_color}@${fg[blue]}%m${reset_color}(%*%) %~
%# "

RPROMPT="%{${fg[blue]}%}[%~]%{${reset_color}%}"
autoload -Uz vcs_info
setopt prompt_subst
zstyle ':vcs_info:git:*' check-for-changes true
zstyle ':vcs_info:git:*' stagedstr "%F{yellow}!"
zstyle ':vcs_info:git:*' unstagedstr "%F{red}+"
zstyle ':vcs_info:*' formats "%F{green}%c%u[%b]%f"
zstyle ':vcs_info:*' actionformats '[%b|%a]'
precmd () { vcs_info }
RPROMPT=$RPROMPT'${vcs_info_msg_0_}'
$ source ~/.zshrc

と打つと、設定を反映できると思います。

ssh接続の度にパスワードを打つのは面倒なので、公開鍵認証で接続できるようにします。

まず、自分のパソコンでssh鍵のペアを作成します。(以下のコマンドでできます。)

$ ssh-keygen -t rsa

サーバー上に、先ほど作成したssh鍵の公開鍵(.pub)を登録していきます。

$ cd ~
$ mkdir .ssh
$ touch .ssh/authorized_keys
$ chmod 700 .ssh
$ chmod 600 .ssh/authorized_keys

一度exitし、自分のPCのターミナルから、

$ cat ~/.ssh/id_rsa.pub | ssh (user名)@(ipアドレス) 'cat >> .ssh/authorized_keys'

とすると、サーバー上に自分の公開鍵を登録することができます。この状態で、sshをするとパスワードを打たずに入れると思います。ssh接続の設定も変更します。

$ sudo vi /etc/ssh/sshd_config

PasswordAuthentication no
PermitRootLogin no

sshするportはデフォルトでは22番ですが、これもセキュリティ上よろしくないので、ポート番号を変更します。

$ sudo vim /etc/ssh/sshd_config

# Port 22
Port [任意の番号(49152~65535がよろしい)]

$ sudo /etc/init.d/ssh restart

それに伴って、ローカルからsshをする時の設定を加えましょう。

$ vim ~/.ssh/config

Host (適当な名前)↲
  Hostname (IPアドレス or ドメイン名)
  User (ユーザー名)
  IdentityFile ~/.ssh/id_rsa↲
  Port (さっき決めた番号)

$ ssh (適当な名前)

ファイアウォールも設定しておきましょう!

$ sudo ufw enable
$ sudo ufw default deny
$ sudo ufw allow https/tcp
$ sudo ufw allow http/tcp
$ sudo ufw allow ftp
$ sudo ufw allow (先ほどのポート番号)
$ sudo ufw allow 8000 (あとで使います)

$ sudo ufw status verbose (設定されたか確認)

$ sudo ufw reload

次にUbuntuを最新状態にします。

$ sudo apt update
$ sudo apt dist-upgrade
$ sudo apt autoremove

Ubuntu上にPython環境をpyenvを用いて構築します。Pythonのビルドツール・ライブラリをインストールします。(参考サイト

$ sudo apt install build-essential libbz2-dev libdb-dev \
  libreadline-dev libffi-dev libgdbm-dev liblzma-dev \
  libncursesw5-dev libsqlite3-dev libssl-dev \
  zlib1g-dev uuid-dev tk-dev

Pyenvをインストールします。

$ sudo apt-get install -y git
$ git clone https://github.com/pyenv/pyenv.git ~/.pyenv
$ echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zshrc
$ echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.zshrc
$ echo 'eval "$(pyenv init -)"' >> ~/.zshrc
$ source ~/.zshrc

Pythonをインストールします。今回は、3.7.0をインストールしてみます。

$ pyenv install --list | grep 3.7
$ pyenv install 3.7.0
ちょっと時間かかる
$ pyenv global 3.7.0
$ source ~/.zshrc

Postgresql・Posgisのインストールを行います。aptで行うようにします。

$ echo "deb http://apt.postgresql.org/pub/repos/apt/ bionic-pgdg main" | sudo tee -a /etc/apt/sources.list.d/pgdg.list
$ curl https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
$ sudo apt update
$ sudo apt install postgresql-11
$ sudo apt install postgresql-11-postgis-2.5 postgresql-11-postgis-2.5-scripts

Postgresqlで、djangoで使用するUserとDBを作成します。

$ sudo su - postgres
$ psql -V
確認
$ psql -c "alter user postgres with password 'password'" 
$ createuser (user名)
$ createdb (DB名) -O (user名)
$ psql -c "alter user (user名) with password '(パスワード)'"

そしたら、DBでPosgisを扱えるようにします。

$ psql  -d (DB名)
DBに入ったら
# CREATE EXTENSION postgis;

Django、nginx、uWSGIを用いてDjangoのプロジェクトをデプロイしていきましょう。こちらを参考にしました。

その前に、githubにサーバーのssh鍵を登録しておきましょう。

$ ssh-keygen -t rsa 

そしたら、~/.ssh/id_rsa.pubの値を、githubのSettings>SSH and GPG keysで登録してください。

$ cd
$ git clone git@github.com:(リポジトリのclone with SSHをみて)
$ cd my-project
$ python -m venv .
$ source bin/activate
$ pip install -r requirements.txt
$ cd (project名)

ここは、適宜設定して下さい。私は、environを使っているので、.envファイルを作成しました。DEBUGはFalseにする必要があります。

Postgresqlにmigrateしようとした時にエラーが出る場合は、

$ sudo apt install python-psycopg2 libpq-dev
$ pip install psycopg2

とすると、migrateができます。準備が終わったら、先ほど空けていた8000ポートを使って、

$ python manage.py runserver 0.0.0.0:8000

とすると、(ipアドレス):8000とURLに打つと何かは表示されると思います。

uWSGIのインストール

uWSGI(ウイスキー?)をインストールしましょう。

$ pip install uwsgi
$ uwsgi --http :8000 --module mysite.wsgi

ここで、mysite.wsgiの「mysite」は、wsgi.pyが入っているディレクトリの名前に変えてください。

nginxのインストール

最新版のnginxをaptでインストールします。

$  curl http://nginx.org/keys/nginx_signing.key | sudo apt-key add -
$ sudo sh -c "echo 'deb http://nginx.org/packages/ubuntu/ bionic nginx' >> /etc/apt/sources.list"
$ sudo sh -c "echo 'deb-src http://nginx.org/packages/ubuntu/ bionic nginx' >> /etc/apt/sources.list"
$ sudo apt update
$ sudo apt install nginx
$ sudo service nginx start

これより、ipアドレスをURLに打ち込むと、「Welcome to nginx!」と出るはずです。

nginxの設定

projectディレクトリ(manage.pyがあるとこ)に、uwsgi_paramsというファイルを作成してください。

$ vi 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;

次にnginxの設定ファイルを作成します。

$ sudo mkdir /etc/nginx/sites-available
$ sudo mkdir /etc/nginx/sites-enabled
$ sudo vi /etc/nginx/sites-available/mysite_nginx.conf


# the upstream component nginx needs to connect to
upstream django {
    # server unix:///path/to/your/mysite/mysite.sock;
    server 127.0.0.1:8001;
}

# configuration of the server
server {
    # the port your site will be served on
    listen      8000;
    # the domain name it will serve for
    server_name (ipアドレス or ドメイン名);
    charset     utf-8;

    # max upload size
    client_max_body_size 75M;   # adjust to taste

    # Django media
    location /media  {
        alias /home/(user名)/(mediaディレクトリのpath)/media;
    }

    location /static {
        alias /home/(user名)/(staticディレクトリのpath)/static;
    }

    location / {
        uwsgi_pass  django;
        include /home/(user名)/(uwsgi_paramsのpath)/uwsgi_params;
    }
}

その後、projectディレクトリにコピーし、シンボリックリンクを貼ります。

$ cp /etc/nginx/sites-available/mysite_nginx.conf ~/(githubのproject名)/(djangoのproject名)
$ sudo ln -s ~/(githubのproject名)/(djangoのproject名)/mysite_nginx.conf /etc/nginx/sites-enabled

ここで、/etc/nginx/nginx.confをみて、以下の行がなければ追加してください。

include /etc/nginx/sites-enabled/*;

Djangoの静的ファイルを全て、staticディレクトリに収集する必要があります。従って、settings.pyに以下の行を追加してください。

STATIC_ROOT = os.path.join(BASE_DIR, "static/")

そして、以下のコマンドを実行してください。

$ python manage.py collectstatic
$ sudo service nginx restart
$ uwsgi --socket :8001 --module mysite.wsgi

こうすると、(ipアドレス):8000でサイトを見ることができると思います。

Unixソケットの利用

$ vi mysite_nginx.conf

以下の部分を変更

upstream django {
    server unix:///path/to/your/mysite(project名)/mysite(どんな名前でも良い).sock;
    # server 127.0.0.1:8001;
}

$ sudo service nginx restart

その後

$ uwsgi --socket mysite.sock --module mysite.wsgi --chmod-socket=666

とすると、再び同じようにサイトを見ることができると思います。

uWSGIのiniファイルの作成

いちいちコマンドでオプションを打っていたらめんどくさいので、iniファイルを作成し、それを使って実行します。

$ vi mysite_uwsgi.ini   (manage.pyと同じ階層)


[uwsgi]

# Django-related settings
# the base directory (full path)
chdir           = /path/to/project
# Django's wsgi file
module          = (project name).wsgi
# the virtualenv (full path)
home            = /path/to/venv

# process-related settings
# master
master          = true
# maximum number of worker processes
processes       = 10
# the socket (use the full path to be safe
socket          = /path/to/mysite.sock
# ... with appropriate permissions - may be needed
chmod-socket    = 666
# clear environment on exit
vacuum          = true


$ uwsgi --ini mysite_uwsgi.ini

これで、随分と楽になりました。

さらに楽にするために、SystemdでuWSGIプロセスを管理する。

$ sudo vi /etc/systemd/system/uwsgi.service

[Unit]
Description = uwsgi
After=network.target

[Service]
Restart = always
ExecStart = /path/to/venv(仮想環境のbinへのpath)/bin/uwsgi --ini=/path/to/mysite_uwsgi.ini
ExecReload = /bin/kill -s HUP ${MAINPID}
KillSignal = QUIT

[Install]
WantedBy = multi-user.target

$ sudo systemctl start uwsgi

これで、コマンドを打たなくても表示されるようになりました。

今だと8000ポートでlistenしているので、それを80番ポートにして8000番ポートに渡すようにしましょう。

$ vi mysite_nginx.conf


# listen      8000;
    listen      80;

location / {
        proxy_pass http://127.0.0.1:8000;  <-追加
    }

$ sudo service nginx restart

こうすると、ポート番号を指定せずに、アクセスできると思います。

最後に自動起動の設定をしておきましょう。

$ sudo systemctl enable nginx
$ sudo systemctl enable uwsgi

もう8000番は使わないので、firewallの設定を更新しときましょう。

$ sudo ufw deny 8000

$ sudo ufw status verbose (設定されたか確認)

$ sudo ufw reload

以上で基本的な設定は完了です。あとは、色々設定してみてください!