☆☆ 新着記事 ☆☆

2018年12月29日土曜日

[最終版] mod_wsgi と 複数ドメインを管理するvirtual host でLet's Encryptをインストールする(SSL対応)

mod_wsgi経由でDjangoやFlaskを使いつつ、Virtual Hostで複数のサブ・ドメインを1台のサーバで動かしたい。(勿論、wwwホスト名 あり・なしにも対応。) 

しかも、各ドメインは、SSLにも対応させる。
結構、難しくないですか? Virtual Hostの書き方を把握するまで、凄く時間がかかったので、まとめておきます。
--------------------------------------------------------------------------------

***** Important Notice *****
前半の記述は、失敗版だと判明しました。 この記述だと、一番最初に読み込んだ
    flask appが保持されて、別のflask appに切り替わりません。 
     この問題には、stackoverflowに、mod_wsgiの開発者であるGraham Dumpleton さん
           自身が回答されていましたので、そのガイドに基づいて、再度、設定を修正しています。
           このpostの後半に書きました。 最初の部分は、読み飛ばしてください。
 

mod_wsgiを利用した場合の基本的なVirtual Hostの書き方は、
【 複数のサブドメインを管理しているサーバで、wsgiを使う時のVirtual Hostの書き方  】
に、まとめました。

この書き方で、’wwwあり・なし’、’複数のサブドメイン’に対応することができます。
(あわせて、mod_wsgiのスクリプトがあるディレクトリ配下でも、staticなファイルは直接、ブラウザから呼び出せるようにしています。)

このポストでは、これをSSLに対応させる(Let's Encrypt) 時のVirtual Hostの書き方と注意点を書いておきます。

◆環境
CentOS 7 + Apache 2.4 + mod_wsgi 4.6.5 + Flask
で、挙動確認しています。

◆対象ドメイン
(Freenomで12か月、無料で取得したもの。DNSもすべてに同じIP Addressを指定しています。)
- mossymob.tk
- www.mossymob.tk
- taylor.mossymob.tk


***********(前半 失敗の部)***********

◆結論
Virtual Hostの記載:
conf.d ディレクトリの配下に 'vhosts_www.conf' を作り、記述しています。

[root@cnewgwb6 conf.d]# pwd
/etc/httpd/conf.d
[root@cnewgwb6 conf.d]# cat vhosts_www.conf


LoadModule wsgi_module /usr/lib64/httpd/modules/mod_wsgi.so

WSGIApplicationGroup %{GLOBAL}
WSGIDaemonProcess www user=apache group=apache maximum-requests=10000 <- ①
WSGIProcessGroup www

 <VirtualHost *:80>
   ServerName www.mossymob.tk
   DocumentRoot /var/www/html
   Alias /posts  /var/www/html/posts <- ②
   WSGIScriptAlias / /var/www/html/myapp.wsgi
   <Directory "/var/www/html/">
     Options Includes ExecCGI FollowSymLinks
   </Directory>
 </VirtualHost>
<VirtualHost *:80>
   ServerName mossymob.tk <- ③
   DocumentRoot /var/www/html
   Alias /posts  /var/www/html/posts
   WSGIScriptAlias / /var/www/html/myapp.wsgi
   <Directory "/var/www/html/">
     Options Includes ExecCGI FollowSymLinks
   </Directory>
 </VirtualHost>

<VirtualHost *:80>
   ServerName taylor.mossymob.tk
   DocumentRoot /var/taylor/html
   Alias /posts  /var/taylor/html/posts
   WSGIScriptAlias / /var/taylor/html/myapp.wsgi
   <Directory "/var/uslife/html/">
     Options Includes ExecCGI FollowSymLinks
     Require all granted <- ④
  </Directory>
 </VirtualHost>
 

注意点)

①デーモン・モードについて
明示的にdeamon modeを指定してあげないと"ValueError: Unable to set value to path!" とエラーになります。 そこで、個別の<VirtualHost></VirtualHost>の中に、それぞれ記述しましたが、 "Name duplicates previous WSGI daemon definition.” というエラーになりました。 

記述は、こんな感じ。
LoadModule wsgi_module /usr/lib64/httpd/modules/mod_wsgi.so
 <VirtualHost *:80>
   ServerName mossymob.tk
   WSGIDaemonProcess www user=apache group=apache maximum-requests=10000
   DocumentRoot /var/www/html
   WSGIScriptAlias / /var/www/html/myapp.wsgi process-group=www
   <Directory "/var/www/html/">
     Options Includes ExecCGI FollowSymLinks
   </Directory>
 </VirtualHost>


結局、個別の<VirtualHost>コンテナーの外に記述することで、このName duplicates errorを回避しました。

*maximm requests:
Use of maximum-requests is discouraged for production sites unless you really have a crippling memory leak you can't fix straight away. – Graham Dumpleton Jul 6 '11 at 5:18


②mod_wsgiとstatic file

必須ではないかもしれませんが、htmlなどの静的なファイルは、将来、mod_wsgiを介さないでブラウザに表示したいので、その為の設定です。 wsgiスクリプトが設置されたディレクトリにpostsというディレクトリを作り、その配下のファイルは、ブラウザから直接、アクセスできるようにしました。

③ wwwサブドメイン名なしのURLについて

Server Aliasを当初使っていましたが、この設定があるとLet's Encriptは上手く機能しないようです。 冗長ですが個別に<VirtualHost>の記述をすることにしました。

④Require all granted
   mossymob.tk や www.mossymob.tk の<VirtualHost>の<Directory>コンテナーの中には記述不要ですが、別サブ・ドメインの時には、この記述が必須になります。 wwwは、mod_wsgiの読み込みのデフォルト・ルートになっているからでしょうか? 理由は良く分かりません。

ここまできたら、Let's Encrypt で、certbotを実行します。
コマンドは、ルート・ディレクトリで以下の実行をしました。

# certbot --apache -d mossymob.tk

-d のオプションでドメイン名を指定しなければ、一括してSSL対応になるようですが、一つずつ対応させた方が、どのドメインに問題があるか把握するのが容易です。

certbotが実行される毎に、’vhosts_www-le-ssl.conf' (自分が作成したvirtual host記述ファイル名+le-ssl.conf)が作成されます。 (後から実行したドメインの記述は、このファイル内に追加されます。

地道に全てのドメインに対して実行した後の’vhosts_www-le-ssl.conf'の内容が以下になります。
[root@cnewgwb6 conf.d]# cat vhosts_www-le-ssl.conf


<IfModule mod_ssl.c>
<VirtualHost *:443>
   ServerName mossymob.tk
   DocumentRoot /var/www/html
   Alias /posts  /var/www/html/posts
   WSGIScriptAlias / /var/www/html/myapp.wsgi
   <Directory "/var/www/html/">
     Options Includes ExecCGI FollowSymLinks
   </Directory>
   SSLCertificateFile /etc/letsencrypt/live/mossymob.tk-0001/cert.pem
   SSLCertificateKeyFile /etc/letsencrypt/live/mossymob.tk-0001/privkey.pem
    Include /etc/letsencrypt/options-ssl-apache.conf
    SSLCertificateChainFile /etc/letsencrypt/live/mossymob.tk-0001/chain.pem
</VirtualHost>
</IfModule>

<IfModule mod_ssl.c>
 <VirtualHost *:443>
   ServerName www.mossymob.tk
   DocumentRoot /var/www/html
   Alias /posts  /var/www/html/posts
   WSGIScriptAlias / /var/www/html/myapp.wsgi
   <Directory "/var/www/html/">
     Options Includes ExecCGI FollowSymLinks
   </Directory>
  SSLCertificateFile /etc/letsencrypt/live/www.mossymob.tk/cert.pem
  SSLCertificateKeyFile /etc/letsencrypt/live/www.mossymob.tk/privkey.pem
  Include /etc/letsencrypt/options-ssl-apache.conf
  SSLCertificateChainFile /etc/letsencrypt/live/www.mossymob.tk/chain.pem
</VirtualHost>
</IfModule>

<IfModule mod_ssl.c>
<VirtualHost *:443>
   ServerName taylor.mossymob.tk
   DocumentRoot /var/taylor/html
   Alias /posts  /var/taylor/html/posts
   WSGIScriptAlias / /var/taylor/html/myapp.wsgi
   <Directory "/var/taylor/html/">
     AllowOverride None <- ②
     Options Includes ExecCGI FollowSymLinks
     Require all granted <- ①
   </Directory>
   Include /etc/letsencrypt/options-ssl-apache.conf
   SSLCertificateFile /etc/letsencrypt/live/uslife.mossymob.tk/cert.pem
   SSLCertificateKeyFile /etc/letsencrypt/live/uslife.mossymob.tk/privkey.pem
   SSLCertificateChainFile /etc/letsencrypt/live/uslife.mossymob.tk/chain.pem
   </VirtualHost>
</IfModule>


注意点)

① <Directory "/var/taylor/html/"> の記述

基本的に、Let's Encryptのcerbotが自動で作成するconfファイルは、自分で記述したvirtual hostの記述内容をコピーしてきて、その内容にsslの対応をさせる、というものだと思います。
でも、確実にコピーがされるか、というと疑問です。 自分の場合、赤字のRequire all grantedがコピーされていませんでした。 それが certbot の正しい挙動なのか分かりませんが、再度、自分で確認した方が良いでしょう。

 ② AllowOverride None 
この記述は、httpのオリジナルの<Virtual Host>内には記述していません。 しかし、SSLの時には、この記述がないと、うまくwsgi scriptが機能しません。 理由の把握までは出来ていません。


これが最終版。





***********(前半 失敗の部 終了 & 正答版開始)***********

Let's EncrytのcertbotでSSLを設定しようとすると、 "Name duplicates previous WSGI daemon definition.”というエラーが表示される件について、mod_wsgiの開発者 Graham Dumpleton さんは、

As the error says, you cannot use the same name for a WSGIDaemonProcess definition more than once. They have to be unique for the whole Apache instance.
If you have both 80 and 443 instances of the VirtualHost for same ServerName, you shouldn't create a separate WSGIDaemonProcess in the 443 instance. Define it in the 80 instance and reference by name from the 443 instance. That way you share the same daemon process group between 80 and 443 instances of the VirtualHost for the same ServerName.


要は、certbotを走らせると <VirtualHost *:80> をcopyする形で、<VirtualHost *:443>用の新しいファイルが作られますが、すると、その記述の中に、再び、DaemonProcessの同じ名前が使われてしまうので、こんな感じで書いて、

WSGIApplicationGroup %{GLOBAL}
WSGIRestrictEmbedded On

<VirtualHost *:80>
ServerName example.com
WSGIDaemonProcess myprocess threads=10 home=/home/ubuntu/myapp
WSGIProcessGroup myprocess
...
</VirtualHost>

<VirtualHost *:443>
ServerName example.com
WSGIProcessGroup myprocess
...               ← WSGIDaemonProcess は記述しない、
</VirtualHost>

と、回答しています。

なので、ホスト名ごとに<VirtualHost>を記述したconfファイルを以下のように作ることにします。

file名:mossymob.tk.conf

LoadModule wsgi_module /usr/lib64/httpd/modules/mod_wsgi.so

WSGIApplicationGroup %{GLOBAL}
WSGIRestrictEmbedded On

  <VirtualHost *:80>
    ServerName mossymob.tk
    WSGIDaemonProcess bear user=apache group=apache
    WSGIProcessGroup bear
    DocumentRoot /var/www/html
    Alias /posts  /var/www/html/posts
    WSGIScriptAlias / /var/www/html/myapp.wsgi
    <Directory "/var/www/html/">
      Options Includes ExecCGI FollowSymLinks
    </Directory>
  </VirtualHost>

  <VirtualHost *:443>
    ServerName mossymob.tk

    WSGIProcessGroup bear
    DocumentRoot /var/www/html
    Alias /posts  /var/www/html/posts
    WSGIScriptAlias / /var/www/html/myapp.wsgi
    <Directory "/var/www/html/">
      Options Includes ExecCGI FollowSymLinks
    </Directory>
</VirtualHost>

そして、
# certbot --apache -d mossymob.tk

を実行。

<VirtualHost *:443>
    ServerName mossymob.tk
    WSGIProcessGroup bear
    DocumentRoot /var/www/html
    Alias /posts  /var/www/html/posts
    WSGIScriptAlias / /var/www/html/myapp.wsgi
    <Directory "/var/www/html/">
      Options Includes ExecCGI FollowSymLinks
    </Directory>
  SSLCertificateFile /etc/letsencrypt/live/mossymob.tk-0001/cert.pem
  SSLCertificateKeyFile /etc/letsencrypt/live/mossymob.tk-0001/privkey.pem
  Include /etc/letsencrypt/options-ssl-apache.conf
  SSLCertificateChainFile /etc/letsencrypt/live/mossymob.tk-0001/chain.pem
  </VirtualHost>


* 赤字部分がLet's Encryptのcertbotにより自動で追加された部分。

この作業をSSL化したい全てのサブ・ドメインに対して実行します。

これで、本当に想定した通りの挙動になります。

confファイルを変更した後は、systemctl reload httpdの実行を忘れてはいけません。

以上です。

結構、時間がかかりましたが、これで思い通りの挙動をするようになりました。
皆様にも参考になれば。


0 件のコメント:

コメントを投稿