無料でHttps対応した自作Webサイトを公開する方法(GCP(Ubuntu) + Apache + Python(Flask) + WSGI + Freenom + Letsencrypt)

概要

Pythonを使ったブログを書いていると、「ブログだけではなく、自分の作ったアプリを公開したい!」という思いに駆られるのですが、それを公開するための環境を整えるのが大変だったりお金がかかったりで、なかなか踏み切れないところです。ところが、最近になっていろいろなことが無料でできるようになり、(スペックを度外視すると)なんと1円も使わずにSSL化(Https化)された自作Webサイトを公開できることが分かりました。
以下が作ったサイトです。本記事ではこのサイトを作るまでの手順と内容を整理していきます。
https://www.1prw00r6at.tk/

SSL自作Webサイト公開に必要な要素と入手方法

Webサーバの立ち上げには以下の5要素が必要です。従来はサーバー、ドメイン名、SSL証明書は少なからぬ費用が必要でしたが、今時は無料で使えるものが増えています。

  • サーバー本体
    リクエストを受け取りレスポンスを返すためのPCの本体。今回はGCP(Google Cloud Platform)の無料インスタンス(1Core、メモリ600MB)を使いました。OSは使い慣れているUbuntu16.04を採用しています。
  • Webサーバー(フロントエンド)
    Webサーバーは一般的なApache2.4を使いました。
  • Webサーバー(バックエンド)
    レスポンスを作成する本体としてはPythonのFlaskを使いました。
  • ドメイン
    ドメイン名はFreenomから無料で取得できました。
  • SSL証明書
    SSL証明書はLet’s Encryptから無料で取得できました。

SSL自作Webサイト公開までの手順

以下順を追って説明していきます。

Apacheを起動させるまで

GCPを使ってサーバ本体として使えるクラウドのインスタンスを作成(HTTP及びHTTPSが繋がるように設定しておきましょう)し、SSH接続等でコンソールが動くところまで行っているものとします。(そこまでがわからないという方は以下サイト様等を参考にしてみてください)
無料で使える個人用サーバが欲しかったらGCP(Google Cloud Platform)を使ってみようーgracetory’s blog
以下のコマンドでApacheをインストールします。

sudo apt install apache2 apache2-dev

Apacheの起動・停止・再起動はそれぞれ以下のコマンドで実行できます。

sudo apache2ctl start
sudo apache2ctl stop
sudo apache2ctl restart

起動できたらグローバルIPアドレスをブラウザで叩いて接続を試してみます。

Apacheが起動しており、外部から接続できていることを確認できました。

Flaskを起動させるまで

Anaconda等のPythonのディストリビュータをインストールし、Pythonへのパスが通っているものとします。(そこまでが分からないという方は、同様に以下サイト様等を参考にしてみてください。)
【随時更新】pyenv + Anaconda (Ubuntu 16.04 LTS) で機械学習のPython開発環境をオールインワンで整えるーALGO GEEKS
適当なフォルダ上で以下のファイルを作成します。

nano app.py

中身は以下のようにしましょう。接続を受けるとHello Flask!というレスポンスを返す設定になっています。

# coding: utf-8
from flask import Flask

app = Flask(__name__)

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

if __name__ == "__main__":
    app.run("0.0.0.0", port=80)

Flaskを起動してみます。まだApacheとは連携させていないので、Apacheが起動していると80番ポートが競合してエラーが出ます。なので、一旦Apacheを停止した上で、Flaskを起動してみましょう。

sudo apache2ctl stop
python app.py

起動できたら同様にグローバルIPアドレスをブラウザで叩いて接続を試してみます。

Flaskが起動しており、外部から接続できていることを確認できました。
もしかすると、Permissionがないと出るかもしれません。その場合はsudoでpythonを立ち上げる必要があるのですが、pythonのバージョンが違う(2.7)ために動かないことが予想されます。その場合は以下のように具体的にpythonの場所を指定してから起動しましょう。私の場合は以下のコマンドになります。

sudo /home/hoge/.pyenv/shims/python app.py

pythonの場所がわからないという場合は、以下のコマンドで検索しましょう。

which python

ApacheとFlaskをWSGIで連携させて起動させるまで

少しずつ高度になっていきます。上ではApache及びFlaskを単体で動作させてきましたが、ApacheだけではPythonアプリは公開できない、Flaskだけではサーバーとしての性能やセキュリティに心配がある、ということで、ApacheとFlask(Python)を連携させる設定が必要です。そのためのライブラリとしてWSGI(ウィズギー)をインストールします。インストールはpipで可能です。

pip install mod_wsgi

インストールしたら、ApacheにWSGIを使うことと、その実体のファイルの場所を設定する必要があるので、ファイルの場所を控えておきます。ファイル名は例えば「mod_wsgi-py36.cpython-36m-x86_64-linux-gnu.so」です。分からなければ以下等のコマンドで探してみてください。

sudo find / -name mod_wsgi

ファイルの場所が分かったらApacheの設定を進めます。まず設定ファイルがある場所に移動しましょう。

cd /etc/apache2/mods-available

ここに設定ファイルを追加します。

sudo nano mod_wsgi.load

中身は以下を書いておきましょう。/home以下に上記で控えたファイルの場所を記載します。私の場合は下記のようになりました。

LoadModule wsgi_module /home/hoge/.pyenv/versions/anaconda3-5.2.0/lib/python3.6/site-packages/mod_wsgi/server/mod_wsgi-py36.cpython-36m-x86_64-linux-gnu.so

WSGIを有効化します。

sudo a2enmod mod_wsgi
sudo apache2ctl restart

次に起動させるPythonのコードを作成します。デフォルトでApacheからアクセスできるようになっている/var/wwwのフォルダにflaskフォルダを追加し、先ほど作成したのと同様のapp.pyと、WSGIで呼び出すwsgi.pyを新しく作成します。

cd /var/www
mkdir flask
cd flask
sudo nano app.py
sudo nano wsgi.py

wsgi.pyの中身には以下の内容を与えておきます。

# coding: utf-8
import sys
import os
sys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))

from app import app as application

最後にApacheの設定ファイルにWSGIで読み出すファイルがwsgi.pyであることを設定する必要があります。まず設定ファイルが保存されているフォルダ(/etc/apache2/sites-available)に移動し、デフォルトの設定ファイルをコピーしてflask.confというファイルを作成します。

cd /etc/apache2/sites-available
sudo cp 000-default.conf flask.conf

設定ファイルの中に、WSGIスクリプトの場所を設定するため以下のコードを追加します。以下は、トップページにアクセスがあったら/var以下のwsgi.pyを読みだす、と言う意味になります。WSGIはwsgi.pyの中にあるapplicationをrunするような仕様になっており、これによりflaskの応答がapacheに返され、クライアントに渡される、ということになります。

WSGIScriptAlias / /var/www/flask/wsgi.py

追加できたら、今までの設定ファイルを無効化し、flask.confを有効化します。

sudo a2dissite 000-default.conf
sudo a2ensite flask.conf

最後にApacheを再起動すれば完成です。

sudo apache2ctl restart

起動できたら同様にグローバルIPアドレスをブラウザで叩いて接続を試してみます。

Flask単体の時と違いがわからないですが、Apacheを起動した状態でこの画面が見えていれば、WSGIを使って、Apache+Flaskで動かすことができているはずです。

自己証明でSSL化するまで

次に、サイトをSSL化し、Https対応することを進めていきます。まずはopenSSLを使って自己証明によりSSL化させます。まずApacheのSSLモジュールを有効化させるため、以下のコマンドを実行します。

sudo a2enmod ssl
sudo apache2ctl restart

次にflask.confファイルを編集し、SSL化することを設定します。具体的には以下を修正し、

-<VirtualHost *:80>
+<VirtualHost *:443>

以下を追加します。これらのコードはdefault-ssl.confの中に説明を含めて記載されています。

SSLEngine on
SSLCertificateFile	/etc/ssl/certs/ssl-cert-snakeoil.pem
SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key

起動できたら同様にグローバルIPアドレスをブラウザで叩いて接続を試してみます。今度は頭にhttpsをつけましょう。

自己証明なのでNot secureと出てしまっていますが、opensslによるhttps対応まで到達しました。
なお、もしかすると以下のようなエラー(Internal Server Error)が出るかもしれません。

Apacheのログを見ると以下のように出ています。

_ssl.cpython-36m-x86_64-linux-gnu.so: undefined symbol: SSLv2_method

これはanacondaも独自のopensslを持っていて、apacheが見ているopensslとバージョンが違うことが原因です。今回の構成ではflaskがSSL化を考える必要はない(Apacheで対応)なので、エラーを出している該当コードをコメントアウトしてしまいましょう。具体的には、anacondaのsite-package下のflaskの中にあるcli.pyの10行目辺りにある

import ssl

をコメントアウトすればOKです。

ドメイン名を対応付けるまで

ここまでは、URLはIPアドレスを直打ちしていましたが、ここからは具体的な***.comのようなURLになるように進めます。まず、ドメイン名を例えばFreenomから取得し(私の場合は1prw00r6at.tkを取得)、GCPの設定でDNSゾーン等を作成、FreenomのページでIPアドレスとドメイン名の対応付けを実施します。本手順については以下のサイト様が分かりやすかったので参考にしてみてください。
GCP上で独自ドメインを使う
次にApache側を設定します。flask.confを開き以下のコードを追加しましょう。以下は私が取得したドメインの例です。必ず前にwwwをつけるようにしましょう。

ServerName www.1prw00r6at.tk 

DNSの反映に数分かかるはずですが、上記が正しくできていればhttps:ドメイン名でアクセスできるようになるはずです。

SSL証明を反映させるまで

最後に、Not SecureとなっているSSL対応をSecureになるように正しい証明書を与えます。これも無料のものがあり、Let’s Encryptの証明書を使います。なお、下記内容は以下のサイト様の情報を参考にさせていただいています。
Let’s encryptでUbuntu 16.04のApacheをhttps化するにはーHRENDOH’S TECH MEMO
まず、Let’s Encryptの証明書設定機能をインストールします。

sudo apt install letsencrypt python-letsencrypt-apache -y

次に、Apacheを停止してから以下コマンドを実行してEncryptを立ち上げます。

sudo apache2ctl stop
sudo letsencrypt --authenticator standalone --installer apache

Apacheの設定ファイルを自動で見つけて進めてくれるため、メールアドレスを入れてSecureの選択肢を選べば自動的にApacheの設定ファイル(今回で言えばflask.conf)の修正まで自動でやってくれます(これはすごい)。うまく行けば以下のような画面が出るはずです。

ブラウザのページを更新してみましょう。

うまく行っていれば、Not Secureが消えた上で、https:ドメイン名でアクセスできるようになっているはずです。あとは必要に応じてApacheのセキュリティ設定をしたり、Pythonのコードを変えていけば、作りたいアプリケーションが作れるはずです。

まとめ

いろいろ苦闘(汗)はありましたが(主に自分の知識不足とWSGI周りが原因)、GCP(Ubuntu) + Apache + Python(Flask) + WSGI + Freenom + Let’s Encryptを活用し、無料でSSL化(Https化)された自作Webサイトを公開することができました。Google等の活躍で、常識が急速に変わっているのを感じます。活用できるものはどんどん活用して、稼ぐ力+技術力+知識力をアップしていきたいですね。

1+

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA