LoginSignup
23
31

More than 3 years have passed since last update.

CentOSにApacheをインストールしてFlaskアプリケーションをデプロイする

Last updated at Posted at 2019-07-16

この記事では、Flaskで作成したアプリケーションをさくらのVPSを利用して公開する手順を書きます。

概要

さくらのVPS上に CentOS7 をインストールして、Apacheで Webサーバーを立て、gunicorn を AP サーバーとして、Flask アプリケーションを動かします。また、Heroku と同様に git を利用したデプロイを可能にします。

自分用のメモですが、手順通りに進めれば、ある程度、再現できるようになっていると思います。再現できない部分があれば、コメントにて教えて頂けると助かります。

なお、Webサーバーを運用するうえで必要なセキュリティ設定は、この記事に書かれている内容では不十分かもしれません。セキュリティには十分に配慮したうえで、必要な設定は適宜ご自身で補って頂くようにお願いいたします。

対象とする読者

  • さくらのVPSを使ってWebサービスを公開したい人
  • Herokuしか使ったことがなく、自分でサーバーを立ててデプロイまでやってみたい人
  • Webサービスを公開したい個人開発者

利用環境

  • さくらのVPS
  • CentOS7
  • Python 3.7.4
  • Flask 1.1.1
  • Apache 2.4.6
  • gunicorn 19.9.0

1. さくらのVPSを契約

まず さくらのVPSの公式サイトから、VPSを契約します。
今回は、1Gプランの東京第2ゾーン、ストレージSSD30GBを選択しました。
2週間は無料でお試しできるようです。

2. CentOS7をインストール

さくらのVPSを契約すると、さくらのVPSコントロールパネルにログインできるようになります。
コントロールパネルで先ほど契約したサーバーを選択します。

サーバーを起動する前に、OSの設定で CentOS7 をインストールするように変更します。

初期状態では、CentOS6 がインストールされるので注意が必要です(CentOS 6 と 7 で、使用可能なコマンドに差異があります。そのため、CenOS6では、この記事の通りに進められない可能性があります。CentOS7をインストールしましょう)。

コントロールパネルの右側にある「各種設定」ボタンをクリックして、「OSインストール」でインストール画面に遷移します。

標準OSインストールで「CentOS7 x86_64」を選択し、管理ユーザーのパスワードを設定します。
管理ユーザーのパスワードは必ず強固なものを設定しましょう。簡単なパスワードを設定していると、簡単に不正ログインされます。

また、ここで設定したパスワードは、インストール後、CentOSにログインする際に使用します。忘れないようにしましょう。

スタートアップスクリプトは設定せず、インストールを開始します。

サーバーの電源状態が「稼働中」になれば、インストールは完了です。

3. CentOS の初期設定

次に、CentOS の初期設定をします。

3.1. サーバーに ssh 接続

まず、vps上にインストールした CentOS に、sshで接続します。適当なターミナルで以下のコマンドを実行します。

ssh root@[契約したサーバーのIPアドレス]

IPアドレスは、コントロールパネルでサーバーの画面を開いた後、サーバー名の下に書いてあります。

まだ、何も設定もしていないため、rootユーザーでsshで接続します。
パスワードを求められるので、先ほど設定したパスワードでログインします。

3.2. 一般ユーザーを作成

ログインしたら、一般ユーザーを作成します。rootユーザーは権限が大きく、rootユーザーですぐにログインできる状態は、セキュリティ上、非常に危険なためです。

限られた権限だけを持つ一般ユーザーを作成して、必要最低限の権限を与え、rootユーザーでのログインは制限します。

3.2.1 一般ユーザーを作成

以下のコマンドを実行します。

adduser [ユーザー名]

ユーザー名を qiita にするなら、以下のようにします。

adduser qiita 

これで、qiitaという名前のユーザーが作成されました。

※ここでは簡単に qiita という名前にしていますが、実際には推測されにくい名称を付けるべきです。特に、admin や root-admin などといった名称は、辞書攻撃に弱く、セキュリティ上のリスクになります。

3.2.2 一般ユーザーにパスワードを設定

作成したユーザーにパスワードを設定します。以下のコマンドを実行します。

passwd [ユーザー名]

ユーザー名が qiita なら

passwd qiita 

で設定できます。

Changing password for user qiita.
New password:
Retype new password:

という表示になるので、パスワードを設定します。ここでも、推測されにくい複雑なパスワードを設定しましょう。「***」のような文字は出てきませんが、入力されています。

パスワードが設定できると

passwd: all authentication tokens updated successfully.

と表示されます。

3.3. 一般ユーザーでログイン

パスワードを設定したら、一般ユーザーでログインし直します。exitコマンドでいったん接続を切ります。

exit

その後、再度、一般ユーザーで ssh 接続します。

ssh [ユーザー名]@[サーバーのIPアドレス]

パスワードを求められるので、先ほど設定したパスワードを入力します。正しくユーザーが追加できていれば、ssh 接続できます。

3.4. rootログインを禁止する

一般ユーザーでログインできるようになりましたが、
このままでは、一般ユーザーでも root ユーザーでもログインできてしまいます。

rootユーザーによるログインを禁止しましょう。

設定のため、rootユーザーでログインします。
rootユーザーでログインしたら、以下のコマンドを実行します。

cd /etc/ssh
vim sshd_config

Linux系の OS では、etcディレクトリに、設定ファイルが配置されます。

その下の ssh のディレクトリに ssh の設定ファイルがあります。

cd (= change directory) コマンドで /etc/ssh に移動し、sshd_config (= ssh daemon configuration) ファイル を vim で開きます。

vimsshd_config ファイルを編集します。

40行目前後に以下のようなコメントアウトされた行があります。

#PermitRootLogin yes

PermitRootLogin (rootログインを許可する)という設定を書いている行です。この先頭の # を削除し、「yes」を「no」に変更します。

PermitRootLogin no

変更したら :wq で保存して終了します。

このままだと変更が反映されていないので、以下のコマンドでsshd を再起動します。

systemctl restart sshd.service

注:CentOS6の場合は systemctl ではなく service コマンドを使います。

3.4. 公開鍵認証に変更

rootユーザーによるログインを禁止したら、公開鍵認証によるログインに変更します。そして、パスワードによるログインは禁止します。

3.4.1. 公開鍵と秘密鍵を作成

まずは、公開鍵と秘密鍵のペアを作成します。
ローカルのターミナルで、以下のコマンドを実行します。

ssh-keygen

デフォルトでは .ssh 以下のディレクトリに id_rsa (秘密鍵) , id_rsa.pub (公開鍵) が作られます。必要があれば、パスやファイル名を変更しましょう。

3.4.2. 公開鍵をリモートにコピー

公開鍵/秘密鍵ファイルを作成したら、公開鍵を VPS 上の CentOS に scp コマンドでコピーします。 scp コマンドは、ssh 通信を利用して、ファイルをコピーするコマンドです。

scp id_rsa.pub [ユーザー名]@[サーバーのIP]:[保存先のパス]

リモートに ssh でログインして、コピーした公開鍵を authorized_keys という名称に変更し ~/.ssh ディレクトリにコピーします。

.ssh ディレクトリがなければ、以下のように作成します。

mkdir /home/qiita/.ssh
cat /home/qiita/id_rsa.pub >> /home/qiita/.ssh/authorized_keys

その後 id_rsa.pub は削除します。

rm /home/qiita/id_rsa.pub

3.4.3. パスワード認証を禁止

公開鍵認証を使えるようになったので、パスワードによる認証は禁止します。

リモートの CentOS に一般ユーザーでログインした後、su - コマンドでスーパーユーザーに切り替え、下記のコマンドで設定ファイルを開きます。

vim /etc/ssh/sshd_config

60行目くらいにある PasswordAuthentication を no に変更します。

PasswordAuthentication yes  => PasswordAuthentication no

:wq で保存して終了し、以下のコマンドで再起動して、変更を反映させます。

systemctl  restart  sshd.service

3.4.4. ssh 接続を楽にする

さて、ここまで ssh 接続で ssh [ユーザー名]@[ip] のようなコマンドを打ってきましたが、
毎回このコマンドを打つのは面倒なので、手続きを簡単にします。ローカルで、以下のコマンドを実行し、~/.ssh 以下に、設定ファイル config を作ります。

touch ~/.ssh/config

vimでこれを開き、編集します。

vim ~/.ssh/config

そして、以下のように設定を記述します。

Host [接続時に使う名前]
  HostName     [hostのIPアドレス]
  Port         [Port番号]
  User         [ユーザー名]
  IdentityFile [秘密鍵ファイルのパス]

例として、以下のように書きます。

注:本来ならポートは 22 以外のポートに変更すべきです。その方法は後で追記するかも。

Host vpsapp
  HostName     xxx.xx.xxx.xx
  Port         22
  User         qiita
  IdentityFile ~/.ssh/id_rsa

このように設定を書くと、以下のコマンドだけで、ssh 接続できるようになります。

ssh vpsapp

ホスト名やユーザー名を毎度入力しなくて済みます。

4. Apacheをインストール

ssh 接続の設定を終えたら、続いて Apache HTTP Server をインストールします。Apacheは、サーバーソフトウェアであり、これをインストールすることによって、ただの Linuxマシンが Webサーバーとしての役割を果たすようになります。

サーバーソフトウェアとしては、nginx がナウいですが、今回は、Apacheをインストールします。

以下のコマンドで Apache HTTP Server をインストールします。

yum install httpd

yum は CentOS のパッケージ管理システムです。 yum install [パッケージ名] で指定したパッケージをインストールできます。

コマンド実行後、yes/no を問われたら yes を選択します。

インストールしたら、下記コマンドで、Apache を起動します。

systemctl start httpd

コマンド実行後、以下のコマンドで起動できたか確認します。

systemctl status httpd

Active: active (running) と表示されれば、起動できています。

5. Firewallの設定

続いて Firewall の設定をします。Firewallは、ネットワーク間のアクセスを制御するソフトウェアです。下記コマンドで Firewalld が起動していることを確認します。

firewall-cmd --state

状態がnot runningなら、下記コマンドで起動します。

systemctl start firewalld.service

起動したら、必要な設定を行います。ここでは publicゾーンに対して http と https の通信を許可します。必要に応じて Firewall の設定を追加してください。

firewall-cmd --add-service=http --zone=public --permanent
firewall-cmd --add-service=https --zone=public --permanent

設定後 Firewalld を再起動します。

systemctl restart firewalld.service

ここでブラウザのアドレスバーに ip アドレスを入力してアクセスすると、Apacheのデフォルトのページが表示されると思います。

※2019年06月27日から、さくらのVPSがパケットフィルタ機能を導入しており、コントロールパネルから Web (80/443) の接続を別途許可する必要があるようです。デフォルトでは、22番ポートのみ、アクセスが許可されています。

6. ドキュメントルートの権限を設定して html を返す

Firewallが設定できたら、htmlのページを返せるようにします。その前に、権限設定をします。

具体的には、Apacheのドキュメントルート(/var/www/html)に html ファイルを配置して、ブラウザからアクセスした時に html のページが表示されるようにします。

以下のように、適当なhtmlファイルを作成します。

index.html
<html>
  <head>
    <title>Test</title>
  </head>
  <body>
    Test
  </body>
</html>

これを scp コマンドでリモートの /var/www/html ディレクトリにコピーします。ローカルで、以下のコマンドを実行します。

scp index.html [ユーザー名]@[ホスト]:/var/www/html

前述の方法で config ファイルに ssh 接続の設定を書いている場合は、以下のように実行することができます。

scp index.html vpsapp:/var/www/html

現時点では、権限設定ができていないため、以下のようなエラーが出て、コピーできません。

scp: /var/www/html/index.html: Permission denied

そこで、リモートにログインして権限設定をします。
一般ユーザーでログインした後、su - コマンドで root ユーザーに切り替えます。

ssh testvps
su -

以下のコマンドで /var/www 以下のファイルやディレクトリの権限設定を確認します。

ls -l /var/www 

以下のような表示になります。

drwxr-xr-x 2 root root 4096 Apr 24 22:46 cgi-bin
drwxr-xr-x 2 root root 4096 Apr 24 22:46 html

drwxr-xr-x の部分が、ファイルのパーミッションを示しています。

現時点では、所有者である root ユーザーのみ、htmlディレクトリへの書き込みが許可されていることがわかります。

以下のコマンドで、所有者/所有グループを変更します。

chown apache:qiita /var/www/html

chown は change owner の意で、所有者/所有グループを変更するコマンドです。

次に、以下のコマンドで、権限を変更します。

chmod 775 /var/www/html

chmod は change mode の意で、パーミッションを変更するコマンドです。

もう一度、ls コマンドでパーミッションが変更されたかを確認します。

ls -l /var/www 

以下のように変更されていればOKです。

drwxrwxr-x 2 apache qiita 4096 Apr 24 22:46 html

ここまでできたら、ローカルに戻って、もう一度、先ほどの scp コマンドを実行します。

$ scp index.html vpsapp:/var/www/html
index.html                  100%  108     8.3KB/s   00:00

これで、apacheのドキュメントルートに index.html が追加されました。試しに、ブラウザからアクセスしてみると、以下のように html で作った Test ページが表示されます。

image.png

7. git でデプロイできる環境をつくる

次に、Pythonファイルを含む、Flaskアプリケーションをリモートにデプロイできるようにします。

ここまで、リモートへのファイル転送には scp コマンドを使っていました。引き続き scp でファイル転送をしてもよいですが、git のコミット時に、自動的にデプロイされると便利です。そこで、今回は git でデプロイできる環境を作ります。

GitHub や Heroku に push するのと同様の手順で、サービスをデプロイできるようになります。

7.1. リモートリポジトリを作る

まず、リモートのサーバーに ssh 接続して、以下のように git のリモートリポジトリを作成します。

mkdir /home/qiita/gitremote
cd /home/qiita/gitremote
git init --bare vpsapp.git

git init コマンドに --bare オプションをつけると、bare リポジトリが作成されます。
bareリポジトリは、作業ディレクトリを含まず、commit や push の履歴を管理するリポジトリです。

7.2. ローカルで remote リポジトリを追加

次に、ローカルで remote リポジトリを追加します。

$ git init
$ git remote add origin vpsapp:/home/qiita/gitremote/vpsapp.git

GitHub 等のリモートリポジトリが既に追加されている場合、

fatal: remote origin already exists.

のように表示され、失敗します。

そこで、ローカルの .git/config を編集して、2つのリモートリポジトリに push できるように設定を追加します。

vim .git/config

[remote "origin"] のところを、以下のように編集します。

[remote "origin"]
  url = https://github.com/hogeuser/hoge.git
  url = testvps:/home/[ユーザー名]/gitremote/[プロジェクト名].git <-- 追加
  fetch = +refs/heads/*:refs/remotes/origin/*

これで push 時に両方のリモートリポジトリに push されます。
ローカルで適当にファイルを変更して commit してから push してみます。

git push origin master

追加したリモートリポジトリに push されたことを ssh 接続して確認します。

cd /home/qiita/gitremote/vpsap.git
git log

無事に push できていれば、これまでの commit ログが表示されるはずです。

7.3. ドキュメントルートに clone する

ここで push したリポジトリは、bareリポジトリなので、作業ディレクトリを持っていません。
代わりに commit されたとか、pushされた、という情報を持っています。

git push 時に変更がデプロイされるように、ドキュメントルートで、このディレクトリ clone できるようにします。

su - でルートユーザーに切り替えて操作します。

$ cd /var/www/html
$ git clone /home/qiita/gitremote/vpsapp.git

以下のような表示が出て clone が完了します。

Cloning into 'vpsapp'...
done.

そのまま、lsコマンドを打つと、ローカルにあったプロジェクトがコピーされていることが分かります。

$ ls
vpsapp

7.4. push 時に自動で clone する

push する度に手作業で clone するのは手間です。自動化しましょう。
自動化のために git hook を利用します。

cd /home/qiita/gitremote/vpsapp.git/hooks
vim post-receive

以下を記述します。

cd /var/www/html/vpsapp
git --git-dir=.git pull

実行権限を与えます。

chmod a+x hooks/post-receive

ローカルで適当に commit して push すると、ドキュメントルートに自動的に clone され、変更が反映されます。

8. Flaskアプリケーションを公開

さて、いよいよ、Pythonをインストールして、Flaskアプリケーションを公開できるようにします。流れは以下のようになります。

  1. pipenv で Python3 の環境構築
  2. Flask と Apache を接続

なお、今回公開する Flask アプリケーションは、以下のような構成で /var/www/html 以下に用意されているものとします。

vpsapp
  └── app
      ├── templates
      ├── static
      └── app.py  
  └── run.py

8.1. pipenv で Python3 の環境構築

まずは、Python3 を使えるようにします。そのままインストールしてもいいですが、今回は Pipenv を使います。

8.1.1. pipのインストール

まず、Python のパッケージ管理システム pip をインストールします。
get-pip.py を curl コマンドで取得して、実行します。

curl https://bootstrap.pypa.io/get-pip.py | sudo python

これで pip がインストールされます。

$ pip --version
pip 19.1.1 from /usr/lib/python2.7/site-packages/pip (python 2.7)

8.1.2. pyenvのインストール

pyenv のリポジトリをクローンします。

git clone https://github.com/pyenv/pyenv.git ~/.pyenv

pyenv に path を通します。

echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bash_profile
echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bash_profile
echo -e 'if command -v pyenv 1>/dev/null 2>&1; then\n  eval "$(pyenv init -)"\nfi' >> ~/.bash_profile
exec "$SHELL" -l

次のコマンドで、pyenvがインストールされたことを確認します。

$ pyenv --version
pyenv 1.2.13

また、開発に必要なもろもろのパッケージをインストールします。

sudo yum install gcc zlib-devel bzip2 bzip2-devel readline-devel sqlite sqlite-devel openssl-devel tk-devel libffi-devel

参考:pyenv を使うために必要なパッケージはここに書いてあります。

8.1.3. pipenvのインストール

最後に pipenv をインストールします。

sudo pip install pipenv

インストールできたか確認します。

$ pipenv --version
pipenv, version 2018.11.26

8.1.4. ドキュメントルートに Python3 環境を構築

以下のコマンドを実行し、Apache のドキュメントルートで、Python3.7.4 を指定します。
インストールされていなければインストールします。
しばらく時間がかかります。

$ cd /var/www/html
$ pipenv --python 3.7.4

Would you like us to install CPython 3.7.4 with pyenv? [Y/n]: Y

以下のようなメッセージが完了です。

OK Successfully created virtual environment! 

pipenv の仮想環境で、バージョンを確認します。

$ pipenv shell
$ python --version
Python 3.7.4

Python3.7.4 の環境が作れました。

8.2. Flask と Apache を接続

最後に Apache で受けたリクエストを Flask に渡して、動くようにします。

8.2.1. WSGIとは

Pythonでは、WSGIという仕様に従うことで、サーバーを選ばずに、Python の Webアプリケーションが動くように決められています。WSGIについてはこちら を参照してください。

8.2.2. uwsgi, gunicorn, mod_wsgi

WSGI 仕様に則った AP サーバーとして gunicorn や uwsgi があります。また mod_wsgiというモジュールを使うことによって、Apache で Flask を動かすこともできます。

gunicorn を APサーバーとして、Apache で受けたリクエストを gunicorn にプロキシするのが簡単なので、今回は gunicorn を使います。

8.2.3. gunicorn をインストール

/var/www/html/vpsapp 以下で

$ pipenv install gunicorn
$ pipenv shell
$ gunicorn run:app

で 8000番ポートで Flaskアプリケーションが動きます。

run:app は [Flaskオブジェクトのある.pyファイル]:[Flaskオブジェクトの入っている変数]という指定をしています。

8.2.4. Apache で受けたリクエストを gunicorn にプロキシ

Apache で 80番、443番で受けた http/https リクエストを gunicorn にプロキシします。

vim /etc/httpd/conf/httpd.conf

最終行に、以下のように追記します。

ProxyPass / http://localhost:8000/

これで、http リクエストが8000番ポートにプロキシされ、作成した Flask アプリケーションにブラウザからアクセスできるようになります。

8.2.5. サーバー起動時に gunicorn を起動する

※編集中

$ cd /etc/systemd/system/
$ sudo vim app.service

以下のように書きます。

[Unit]
Description=gunicorn daemon
After=network.target

[Service]
User=apache
Group=apache
WorkingDirectory=/var/www/html/vpsapp
ExecStart=/bin/pipenv gunicorn run:app

[Install]
WantedBy=multi-user.target

で、enable コマンドでサーバー起動時に gunicorn が起動するようにします。

$ systemctl enable app
$ systemctl start app

ついでに、サーバー起動時に apache が起動するようにしておきます。

$ systemctl enable httpd.service

質問・指摘はコメント欄か、twitterアカウント @sti320aにお願いいたします。

23
31
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
23
31