2020/01/20(月)Debian10で Apache + php-fpm の正しい設定メモ

Apache + php-fpm 環境で Debian 9(jessie) から 10(buster) にアップデートしたら動かなくなったので、メモ。

概要

Debian付属のmod_phpはスレッドセーフではないため、Apacheを event_mpm や worker_mpm で運用している場合は使用できません(prefork専用)。

そもそも今どきmod_phpで動作させるのはナンセンスなので、FastCGIデーモンによるPHP環境 FPM/php を使用します。

Debian10での設定

  • Apache 2.4
  • PHP 7.3 (php7.3-fpm)
apt-get install php-fpm libapache2-mod-fcgid

php-fpmをインストールすることで自動的に「php-fpm7.3」サービスが起動します。

/etc/apache2/conf-available 以下に php7.3-fpm.conf が作られるので、これを有効にします。

cd /etc/apache2/conf-enabled
ln -s ../conf-available/php7.3-fpm.conf

proxy_fcgi_moduleが必要なのでこれも有効にします。

cd /etc/apache2/mods-enabled
ln -s ../mods-available/proxy_fcgi.load

この状態で、Apacheを再起動すれば有効になっているはずです。

php7.3-fpm.confの中身

# Redirect to local php-fpm if mod_php is not available
<IfModule !mod_php7.c>
<IfModule proxy_fcgi_module>
    # Enable http authorization headers
    <IfModule setenvif_module>
    SetEnvIfNoCase ^Authorization$ "(.+)" HTTP_AUTHORIZATION=$1
    </IfModule>

    <FilesMatch ".+\.php$">
        SetHandler "proxy:unix:/run/php/php7.3-fpm.sock|fcgi://localhost"
    </FilesMatch>
    <FilesMatch ".+\.phps$">
        Require all denied
    </FilesMatch>
    <FilesMatch "^\.ph(ar|p|ps|tml)$">
        Require all denied
    </FilesMatch>
</IfModule>
</IfModule>

以前使っていた古い設定

Debian 9(jessie)でも全く同じ設定で動作するのですが、以前は古い設定を使っていました。その設定を書いておきます。

  • php-fpm7.0
  • libapache2-mod-fastcgi (Debian9までしか提供されず)

Apache2の libapache2-mod-fastcgi(libapache2-mod-fcgidではダメ)を有効化してから、sites-available/000-default.conf 等に以下の設定を行います。

<IfModule mod_fastcgi.c>
        AddHandler      fastcgi-script  .fcgi
        AddHandler      php7.0-fcgi     .php
        Action          php7.0-fcgi     /usr/sbin/php-fpm7.0
        FastCgiExternalServer   /usr/sbin/php-fpm7.0 -socket /var/run/php/php7.0-fpm.sock -pass-header Authorization
        FastCgiConfig           -maxClassProcesses 100

        <Directory /usr/sbin>
                <Files php-fpm7.0>
                        Require all granted
                </Files>
        </Directory>
</IfModule>

何が変更になったのか

外部プログラムを呼び出して、そこから php-fpm サーバに接続するという形式が無効になったようです。上に書いた古い設定は多くの新しいLinuxディストリビューションで無効になっているようです

この古い設定を行った場合、エラーログ等はなく「404 Not Found」と言われ白紙のページが出るだけなので混乱します。

現在は Apache に直接組み込んだ FastCGIのProxyのモジュール(proxy_fcgi_module)から、直接php-fpmに接続するようになりました。このほうが遥かに効率的です。

メモ

  • php-fpmを利用する場合、SuEXECと併用できない。
  • php-fpmデーモン(設定ファイル)を権限(ユーザー)ごとに分ける必要がある。

2018/06/30(土)Certbotによるワイルドカード証明書と自動更新の設定

どこよりも簡単なワイルドカード証明書設定メモ。


2018年からLet's Encryptがワイルドカード証明書に対応しました。

しかし、これを利用するためにはdns-01という、DNSのTXTレコードを使った認証が必要で、有効期限3ヶ月を乗り越え他の証明書と同じように自動更新させるためにはこのDNS認証手順を自動化する必要があります

そもそもdns-01対応の自動設定が大変ですし、お名前.comやValue Domain等のレジストラサービスを使用していると色々と厄介です。

構成

  • Debian Stretch
  • Apache
  • BIND
  • 設定対象DNS : example.jp

DNSは外部サービスを使用しているものとします。外部サービスでも、CloudfireやAWS、Google Cloud DNSといった有名サービスを使っている場合、DNSサーバは不要です。検索すれば、それらの設定方法が出てきます。

続きを読む

2017/10/30(月)LAN内に外部公開サーバを置いて、内部からアクセスさせる

ルーティングテーブル書き換え(route)によるアクセス制御から、unboundによるDNSの一部書き換えに移行したメモ。

状況

LAN内のLinuxマシンを、家庭用ルータのポートマッピングを使って外部公開している状況を想定しています。小規模の会社とかでも、こういう設定をされていることがありますね。

home-LAN-newtork.png

この場合、内側のPCから外部公開時のホスト名である「global.my.ip」にアクセスするとグローバルIPを引いてしまいます。そして、PCからルーターの外側IPにアクセスすることになるのですが、NEC等のルータではこの際ポートマッピングが有効にならずアクセス不能となります。*1

ルータのルーティングテーブルを書き換えることができれば色々と解決策はあるのですが、そんな機能を持った機種はまずありません……。*2

*1 : Buffaloはたしかアクセスできたような気がする。

*2 : Atermとかでは外向きの静的ルーティングはできても、内向きは無効です……

力技で解決していた

どうにもならないので、PCを起動するたびに、外部IPを確認して、外部IPにアクセスするときはLinuxサーバ(192.168.1.8)にルーティングするような設定をしていました。

@echo off
' route-add.bat
for /f "usebackq tokens=2 skip=1" %%i in (`nslookup global.my.ip 192.168.1.1 ^| findstr "[0-9]\.[0-9]"`) do set IP=%%i
route add %IP% 192.168.1.8

これで、PCから外部IP向けのパケットがLinuxサーバに向かうので、Linuxサーバ側でNAT処理をします。

MY_LOCAL="192.168.1.2"
MY_GLOBAL=`dig +short global.my.ip`
#---------------------------------------------------------------------------
# Special forward for myself
#---------------------------------------------------------------------------
iptables -t nat -A OUTPUT      -d $MY_GLOBAL -s $MY_LOCAL \
         -j DNAT --to-destination $MY_LOCAL
#---------------------------------------------------------------------------
# Special forward for local network
#---------------------------------------------------------------------------
iptables -t nat -A PREROUTING  -d $MY_GLOBAL -s $MY_LOCAL/24 \
         -j DNAT --to-destination $MY_LOCAL

これで無事アクセスはできるのですが、スマホ等からのアクセスは断絶されたままでした。

unboundによるDNSの書き換え

unboundというDNSキャッシュサーバには、特定のホスト名やドメインだけ、DNSの結果を書き換える機能が付いています。

本当は外部IPでのアクセスがすべてLinuxサーバに転送されるのが理想なのですが、そうも言ってらもないので、この方法で解決を試みました。以下、Debianサーバでの設定例です。

sudo su
apt-get install unbound

/etc/unbound/unbound.conf を編集して以下を追加します。

server:
        interface: 0.0.0.0
        access-control: 127.0.0.1 allow
        access-control: 192.168.0.0/16 allow

続いて /etc/unbound/unbound.conf.d/global.my.ip.conf というファイルを新規作成します。

local-data: "global.my.ip A 192.168.1.8"

作成したら unbound にリロードさせます。

service unbound reload

確認

$ dig @localhost global.my.ip
;; ANSWER SECTION:
global.my.ip.           3600    IN      A       192.168.1.8

ルータの設定書き換え

ルータのDHCPの設定を書き換えて、DNSのプライマリサーバに 192.168.1.8 を指定します。セカンダリは 192.168.1.1 を指定しておくと良いでしょう。

まとめ

NECのルータは性能は悪くないけど、細かい設定ができないのでちょっと面倒ですね。

UPnPタイムアウトを設定できないし(高級機のみ可)。Buffaloのほうがいいのかもしれない。ポート転送が内側に対しても効いた気がするし。

その後 2020/4/15

IPv6化して解決したため、unboundを削除しました。