さくらのレンタルサーバのクセ

さくらのレンタルサーバについて、いくつか独特のクセに遭遇したのでメモしておきます。

.html 拡張子で PHPスクリプト を実行したい

経緯

SEOやセキュリティの観点からか、拡張子は .html としてあたかも静的サイトであるように見せかけ、実際は内部で PHP が動いている……というケースですかね。

通常のサーバであれば .htaccess に次のような行(サーバによってパラメータは細かく調整する必要はあり)を追記すれば要求は満たせます。

AddHandler php5-script .php .html

しかし、さくらのレンタルサーバの場合は一筋縄では行かない、というお話。

さくらのレンタルサーバの PHP はモジュール版ではなくCGI版だからでしょうか。

対処

用意するファイルは php.cgi.htaccess の2つ。

php.cgi

#!/bin/sh
exec /usr/local/bin/php-cgi

.htaccess

Action myphp-script /php.cgi
AddHandler myphp-script .php .html

ちなみに両方とも文字コード「EUC-JP」、改行コード「LF」としておきます。 php.cgi はともかく、 .htaccess は大丈夫そうな気はするのですが。

参考記事の一つに指示があったのでアップロード時はバイナリモードとします。

また、仮にこの設定をサブディレクトリのみで適用したい場合は2つのファイルをサブディレクトリに置いて

Action myphp-script /SUBDIRECTORY/php.cgi
AddHandler myphp-script .php .html

という形にします。もしパスが間違えている場合は

AH02811: script not found or unable to stat: /home/USERNAME/www/php.cgi

というようなエラーログが記録されます。

仮にサブディレクトリに設置するならば、次のような配置イメージになります。

└ /home/USERNAME/                              # ユーザルート
              └ www/
                  └ www/                       # ドキュメントルート
                      └ SUBDIRECTORY/
                            ├ .htaccess        # .html拡張子でもPHPスクリプトを動作させるため。 php.cgi とセット
                            └ php.cgi          # .html拡張子でもPHPスクリプトを動作させるため。 .htaccess とセット

$_SERVER[‘DOCUMENT_ROOT’]

2つ目は PHP の $_SERVER['DOCUMENT_ROOT'] の値について。

現象

本体サイトとは別にサブドメインでもサイトを運用する等をするために、ドキュメントルートをコントロールパネルで変更している場合にこの事例に遭遇します。

└ /home/USERNAME/                             # ユーザルート
              └ www/                          # デフォルトのドキュメントルート
                  ├ www/                      # 変更したドキュメントルート
                  │   └ 本体サイト
                  │
                  └ SUBDOMAIN/                # サブドメインのドキュメントルート
                      └ サブドメインの別サイト

例えばこんなディレクトリとドキュメントルートの設定になっているとします。

ここで、 /home/USERNAME/www/www/ に PHP を設置して $_SERVER['DOCUMENT_ROOT'] に代入される値を見てみると……。

想定ではコントロールパネルで変更した /home/USERNAME/www/www/ になっていると思いがちですが、実際は /home/USERNAME/www/ 、つまり変更する前のデフォルトのドキュメントルートになります。

これを知らないで PHP で $_SERVER['DOCUMENT_ROOT'] を使って requireinclude をすると、階層がずれるため読み込みに失敗してしまいます。

対処

用意するファイルは path.php (任意の名前) と .user.ini の2つ。

path.php

<?php
$_SERVER['DOCUMENT_ROOT'] = $_SERVER['DOCUMENT_ROOT'] . '/www/';

.user.ini

auto_prepend_file = ${DOCUMENT_ROOT}/../php_path_replacer/path.php

文字コードや改行コードは UTF-8, LF で大丈夫です。

これを、 path.php/home/USERNAME/php_path_replacer/ (任意ですがユーザから実行されないようにドキュメントルートより上の階層にしておきます) に、 .user.ini$_SERVER['DOCUMENT_ROOT'] の値を置換したいPHPの階層にアップロードします。

すると、次のような配置イメージになります。

└ /home/USERNAME/                              # ユーザルート
              ├ php_path_replacer/
              │      └ path.php                # $_SERVER['DOCUMENT_ROOT'] が狂うのを防ぐため。 .user.ini とセット
              │
              └ www/
                  └ www/                       # ドキュメントルート
                      └ SUBDIRECTORY/
                            └ .user.ini        # $_SERVER['DOCUMENT_ROOT'] が狂うのを防ぐため。 path.php とセット

設置のディレクトリ階層のイメージはこのような形。

ディレクトリごとにFTPユーザの権限を設定する

自前の vsftpd ならば

/etc/vsftpd/vsftpd.conf

chroot_local_user=YES
chroot_list_enable=YES
chroot_list_file=/etc/vsftpd/chroot_list
userlist_deny=NO
user_config_dir=/etc/vsftpd/user_conf

/etc/vsftpd/chroot_list

## 空

/etc/vsftpd/user_conf/FTPUSER

local_root=/var/www/example/

とかしてユーザごとのルートディレクトリを決めてしまうのですが、さくらのレンタルサーバではそういったFTPユーザごとにディレクトリを指定することはできません (できるのはドメインごとのルートディレクトリまでで、「同じドメイン内で異なるディレクトリをルートとする」のようなことは不可)。

代わりに .ftpaccess を使用して一応の権限を設定します。

ルートディレクトリの .ftpaccess

<Limit ALL>
  AllowUser rootdir_user@example.com
  DenyUser subdir_user@example.com
</Limit>
<Limit CWD CDUP LIST>
  AllowUser subdir_user@example.com
</Limit>
  • Limit ALLセクション: ルートディレクトリ以下を編集できるユーザに権限を与えます
    • AllowUserディレクティブ で全てのコマンドを許可するユーザを指定
    • DenyUserディレクティブ コマンドを許可しないユーザを指定
  • Limit CWD CDUP LISTセクション: サブディレクトリ用のユーザはログイン時はどうしてもルートディレクトリに来てしまうので、ディレクトリ移動と一覧取得の権限がないとサブディレクトリに入れないため、そこだけ権限を付与します
    • CWD, CDUP, LIST の3つのコマンドのみ許可するユーザを AllowUserディレクティブ で指定

サブディレクトリの .ftpaccess

<Limit ALL>
  AllowUser OR rootdir_user@example.com,subdir_user@example.com
</Limit>

.ftpaccess.htaccess と同様、設置したディレクトリ下の全てのディレクトリに影響を及ぼすので、サブディレクトリ用ユーザが編集できるディレクトリには上述の設定を打ち消すように Limit ALLセクション に追加します。

以上を踏まえると、次のような配置イメージになります。

└ /home/USERNAME/                              # ユーザルート
              └ www/
                  └ www/                       # ドキュメントルート
                      ├ .ftpaccess             # ドキュメントルート用
                      └ SUBDIRECTORY/
                            └ .ftpaccess       # サブディレクトリ用

余談

仮に全てを組み合わせると次のような配置イメージになります。

└ /home/USERNAME/                             # ユーザルート
              ├ php_path_replacer/
              │      └ path.php               # $_SERVER['DOCUMENT_ROOT'] が狂うのを防ぐため。 .user.ini とセット
              │
              └ www/                          # デフォルトのドキュメントルート
                  ├ www/                      # 変更したドキュメントルート
                  │   ├ 本体サイト
                  │   │
                  │   ├ .ftpaccess            # ドキュメントルート用FTPユーザ権限設定
                  │   └ SUBDIRECTORY/
                  │         ├ .ftpaccess      # サブディレクトリ用FTPユーザ権限設定
                  │         ├ .user.ini       # $_SERVER['DOCUMENT_ROOT'] が狂うのを防ぐため。 path.php とセット
                  │         ├ .htaccess       # .html拡張子でもPHPスクリプトを動作させるため。 php.cgi とセット
                  │         └ php.cgi         # .html拡張子でもPHPスクリプトを動作させるため。 .htaccess とセット
                  │
                  └ subdomain/                # サブドメインのドキュメントルート
                      └ サブドメインの別サイト

流石にカオスですね……。

参考

拡張子 .html で PHP を動かす

$_SERVER[‘DOCUMENT_ROOT’]

.ftpaccess

概要

ディレクティブ一覧

AllowUserディレクティブ, DenyUserディレクティブ

Limitセクション

Directoryセクション

.ftpaccess では Directoryセクション は使用できないため、今回は各々のディレクトリに .ftpaccess を置くことにしました。

その他

この記事を書いた人

アルム=バンド

フロントエンド・バックエンド・サーバエンジニア。LAMPやNodeからWP、Gulpを使ってejs,Scss,JSのコーディングまで一通り。たまにRasPiで遊んだり、趣味で開発したり。