LoginSignup
8

More than 3 years have passed since last update.

さくらVPSで Apache + Pipenv + Flask + SQLAlchemy をサクっと構築

Last updated at Posted at 2020-01-29

はじめに

さくらVPS(CentOS7)上でPythonのwebサーバーを構築するメモ
Apache → gunicorn → Pipenv → Flask + SQLAlchemy(おまけでphpMyAdmin)
サーバーインスタンス作成から最短でDBを扱うwebサーバーをPythonで構築します。

完全に初心者向けの記事ですが、最低限必要な知識は

  • viの基本的な使い方
  • クライアントからのssh接続方法

程度です。

サーバー構築、Python初心者の方(自分です)の参考になればと思います。

テスト用webサーバーを最短で構築するための記事なのでセキュリティ等は考慮しません

最終的には以下をインストールします。

  • CentOS7
  • Apache2.4
  • Python3.8.0
  • Pipenv
  • gunicorn
  • Flask
  • SQLAlchemy
  • PhpMyAdmin7.2

それではサクっといってみましょう。

OSインストール

さくらVPSの管理者画面から以下の設定でOSインストール
各種設定>OSインストール

  • 標準OS
  • CentOS7 x86_64
  • 管理ユーザー名 : root
  • 新しい管理ユーザのパスワード : rootのパスワードを作成
  • スタートアップスクリプトを利用しない
  • パケットフィルタ
    • SSH
    • Web
    • FTP

コンソールへログイン

さくらVPSのコンソールかクライアントのssh接続からrootでログイン
macのクライアントからログイン時に

Offending ECDSA key in /Users/'ユーザー名'/.ssh/known_hosts:1

と出たら ~/.sshのknown_hostsを削除する

MySQLインストールと設定

さくらVPSのマニュアルを参考に
https://www.sakura-vps.net/centos7-setting-list/mysql-settings-for-sakura-vps-centos7

MariaDBの削除

$ yum remove -y mariadb-libs
$ rm -rf /var/lib/mysql

MySQL公式リポジトリの追加

$ rpm -Uvh http://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm

MySQLのインストール

$ yum -y install mysql-community-server

バージョン確認

$ mysqld --version

MySQLの起動と自動起動の設定

$ systemctl start mysqld.service
$ systemctl enable mysqld.service

MySQL初期パスワードを確認
MySQL5.7では、初回起動時に初期パスワードが生成されますので、その初期パスワードを下記コマンドで確認します。
※(ぱすわーど)部分が初期パスワードです。
このあと再入力するためにとっておきましょう

$ cat /var/log/mysqld.log | grep password
[Note] A temporary password is generated for root@localhost: (ぱすわーど)

MySQLのセキュリティ設定

[root@ ~]# mysql_secure_installation

Securing the MySQL server deployment.

Enter password for user root: ”先程の初期パスワードを入力します”

The existing password for the user account root has expired. Please set a new password.

New password: ”新しいパスワードを入力(英字大小文字、数字、記号を含める)”

Re-enter new password: ”確認のためパスワードを再入力”
The 'validate_password' plugin is installed on the server.
The subsequent steps will run with the existing configuration
of the plugin.
Using existing password for root.

Estimated strength of the password: 100
Change the password for root ? ((Press y|Y for Yes, any other key for No) : y ”yを入力(※1)”

New password: ”上記で設定した同じパスワードを入力”

Re-enter new password: ”確認のためパスワードを再入力”

Estimated strength of the password: 100
Do you wish to continue with the password provided?(Press y|Y for Yes, any other key for No) : y ”設定したパスワードで良いかの確認なのでyを入力”
By default, a MySQL installation has an anonymous user,
allowing anyone to log into MySQL without having to have
a user account created for them. This is intended only for
testing, and to make the installation go a bit smoother.
You should remove them before moving into a production
environment.

Remove anonymous users? (Press y|Y for Yes, any other key for No) : y ”匿名ユーザーを削除して良いかの確認なのでyを入力”
Success.

Normally, root should only be allowed to connect from
'localhost'. This ensures that someone cannot guess at
the root password from the network.

Disallow root login remotely? (Press y|Y for Yes, any other key for No) : y ”リモートからrootでログインできないようにして良いかの確認なのでyを入力”
Success.

By default, MySQL comes with a database named 'test' that
anyone can access. This is also intended only for testing,
and should be removed before moving into a production
environment.

Remove test database and access to it? (Press y|Y for Yes, any other key for No) : y ”テストデータベースを削除して良いかの確認なのでyを入力”
 - Dropping test database...
Success.

 - Removing privileges on test database...
Success.

Reloading the privilege tables will ensure that all changes
made so far will take effect immediately.

Reload privilege tables now? (Press y|Y for Yes, any other key for No) : y ”今すぐ権限テーブルを読み込んで設定を有効にするかの確認なのでyを入力”
Success.

All done!

MySQLの設定変更(my.cnf)

$ vi /etc/my.cnf

my.cnfファイルに下記のハイライト部分を追加してください。

「character-set-server = utf8」⇒MySQLデータベースで利用する文字コードをUTF8に指定します。
「default_password_lifetime = 0」⇒MySQL5.7からユーザーのパスワード有効期限がデフォルトで360日のため、この有効期限を0に設定して無効にします。

MySQLを再起動して設定を反映します。

$ systemctl restart mysqld.service

データベースの作成
MySQLへログイン

$ mysql -u root -p

test_dbを作成します

mysql>CREATE DATABASE test_db;
mysql>SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| test_db            |
+--------------------+

MySQLからログアウト

mysql> QUIT;

Apacheインストール

yum インストール

$ yum install httpd

自動起動設定

$ systemctl enable httpd.service

Apache 起動

$ systemctl start httpd

ブラウザから確認
http://'サイトのアドレス'

Apache_HTTP_Server_Test_Page_powered_by_CentOS.b990541ca636492391a260894dc36024.png

pyenvとPythonをインストール

必要なパッケージをyum install

$ yum install gcc bzip2 bzip2-devel openssl openssl-devel readline readline-devel
$ yum update -y
$ yum groupinstall "Development Tools"
$ yum install libffi-devel
$ yum install mariadb-devel

pyenvインストール
パス通したりするので場所はこちらへ

$ cd /usr/local/

pyenvをgitからクローン

$ git clone https://github.com/pyenv/pyenv.git ./pyenv
$ mkdir -p ./pyenv/versions ./pyenv/shims

PATHの設定

$ echo 'export PYENV_ROOT="/usr/local/pyenv"' | sudo tee -a /etc/profile.d/pyenv.sh
$ echo 'export PATH="${PYENV_ROOT}/shims:${PYENV_ROOT}/bin:${PATH}"' | sudo tee -a /etc/profile.d/pyenv.sh
$ source /etc/profile.d/pyenv.sh

pyenvのバージョンを確認

$ pyenv --version

Python3.8.0をインストール
なんとなくwsgi用のオプションを指定してインストール

$ env PYTHON_CONFIGURE_OPTS="--enable-shared" pyenv install 3.8.0

バージョンの切り替え

$ pyenv global 3.8.0
$ pyenv rehash

確認

$ python --version
Python 3.8.0

pipenvで仮想環境構築

インストール

$ pip install --upgrade pip
$ pip install pipenv

仮想環境作成
「test」プロジェクト作成

$ mkdir -p /var/www/app/test
$ cd /var/www/app/test
$ pipenv install

pipenvのシェルを起動

$ pipenv shell

インストール確認

$ python --version

今回使うパッケージをインストール
pipenv shell中は左側にフォルダ名が表示される

(test) $ pipenv install gunicorn
(test) $ pipenv install flask
(test) $ pipenv install sqlalchemy
(test) $ pipenv install mysqlclient

Apacheの設定とFlaskアプリの作成

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

$ vi /etc/httpd/conf/httpd.conf

最終行に追加

httpd.conf
ProxyPass /test http://localhost:8000/

apache再起動

$ systemctl restart httpd.service

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

.pyファイル作成

/var/www/app/testにFlask起動とsqlの.pyファイルを2つ作成します。

$ vi app.py
app.py
from flask import Flask
from testsql import *
import datetime

app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello World! "

@app.route("/insert")
def insert():
    # テーブルがない場合 CREATE TABLE 文が実行される
    Base.metadata.create_all(bind=ENGINE)

    data = TestTable()
    ret = data.create_date.strftime("%Y-%m-%d %H:%M:%S")
    session.add(data)
    session.commit()
    session.close()

    return "insert data "+ret

@app.route("/select")
def select():
    # 最新のデータを取得
    res = session.query(TestTable).order_by(desc(TestTable.create_date)).all()

    ret = ""

    print("ret len "+str(len(res)))

    if 0 < len(res):
        ret = str(res[0].create_date)

    return "select "+ret


if __name__ == "__main__":
    # webサーバー立ち上げ
    app.run(debug=True)

次はDBを扱うファイルの作成

$ vi testsql.py
testsql.py
from sqlalchemy import *
from sqlalchemy.orm import sessionmaker, scoped_session
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, Float, DateTime, Text
from datetime import datetime, timedelta, timezone

# mysqlのDBの設定
DATABASE = 'mysql://%s:%s@%s/%s?charset=utf8' % (
    "root",             # ユーザー
    最初にメモしたmysqlのパスワード,         # パスワード
    "localhost",        # host ip
    "test_db", # DB名
)

ENGINE = create_engine(
    DATABASE,
    encoding = "utf-8",
    echo=False # Trueだと実行のたびにSQLが出力される
)

# Sessionの作成
session = scoped_session(
            sessionmaker(
                autocommit = False,
                autoflush = True,
                bind = ENGINE))

# ベースモデル作成
Base = declarative_base()
Base.query = session.query_property()

# ベースモデルを継承してモデルクラスを定義します
class TestTable(Base):
    __tablename__ = 'tbl_test'

    id          = Column('id', Integer, primary_key = True)

    create_date = Column('create_date', DateTime)

    def __init__(self):
        # タイムゾーンの生成
        JST = timezone(timedelta(hours=+9), 'JST')

        self.create_date = datetime.now(JST)

gunicornを起動

gunicorn [ファイル名]:[変数名]で起動します(ファイル変更で再読み込みオプション付)

(test) $ gunicorn --reload app:app

http:'サイトのアドレス'/test
で表示を確認します

http:'サイトのアドレス'/test/insert
でデータベースへ書き込み

http:'サイトのアドレス'/test/select
でデータベースへ書き込んだデータを返します(日付と時刻)

/select時にgunicornのログに
ret len [インサートされたレコード数]
が表示されます

gunicorn 終了

(test) $ pkill gunicorn

今回はやりませんでしたが
サーバー起動時に gunicorn を起動する
参考:https://qiita.com/sti320a/items/c196387d405272cce46e

【おまけ】phpMyAdmin

DB関連GUIで触りたい人向け

remiリポジトリからPHPインストール

$ rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-7.rpm
$ yum install --enablerepo=remi,remi-php71 php php-devel php-mbstring php-mysqlnd php-pdo php-gd

phpMyAdminインストールと設定
参考:https://knowledge.sakura.ad.jp/9006/

インストール

$ yum --enablerepo=remi-php72 install phpmyadmin

アクセス設定

$ vi /etc/httpd/conf.d/phpMyAdmin.conf

下記のハイライト箇所に「Require all granted」を追記します。
この設定で外部からphpMyAdminにアクセスできるようになります。
phpMyAdminの設定(CentOS_7)___さくらインターネットのVPS設定マニュアル.788d26d3be1946519eb2e0a13e9bd233.png

apache再起動

$ systemctl restart httpd

http://'サイトのアドレス'/phpmyadmin/

さいごに

Pythonでwebサーバーを構築するために色々と調査していると

  • FTPのインストール
  • sshでのrootの接続禁止とパスワード接続禁止
  • ssh用のユーザーやftp用のユーザーの追加
  • ユーザーをrootグループに追加してsudoコマンドを実行できるようにする

この辺はだいたいどの記事にも共通した内容でした。

本来の目的ではない部分で躓いて調査に時間がとられ、結局最初からやり直す、、、
ということがかなり多かったので
余計な作業や説明は省いてとにかくサクッと構築する
というところにフォーカスしてみました。

さらにPython環境のpyenvとpipenvの違いや
仮想環境がどこに作られ、どのように機能するのか
gunicornのapサーバーの仕組み等など
調べ始めるとさらに奥深く、興味が湧くと同時にどんどん目的から遠ざかっていきました...

今回の記事 + selenium 等を使って処理を自動化した
各マンガアプリでイッキ読みできるマンガを集めたサイト
マンガイッキ
を運営しています。
良かったらこちらも見てみてください。

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
8