警告
以下の設定は、app.php, app_dev.php および config.phpを除く全てのPHPスクリプトを実行ではなくダウンロード可能にします。これは、同じバーチャルホスト内のphpMyAdminのようなツールを使いたい場合は望ましくないかも知れません。
Nginx下でアプリケーションを動作させるための最小限の設定:
server {
server_name domain.tld www.domain.tld;
root /var/www/project/web;
location / {
# try to serve file directly, fallback to app.php
try_files $uri /app.php$is_args$args;
}
# DEV
# This rule should only be placed on your development environment
# In production, don't include this and don't deploy app_dev.php or config.php
location ~ ^/(app_dev|config)\.php(/|$) {
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
# When you are using symlinks to link the document root to the
# current version of your application, you should pass the real
# application path instead of the path to the symlink to PHP
# FPM.
# Otherwise, PHP's OPcache may not properly detect changes to
# your PHP files (see https://github.com/zendtech/ZendOptimizerPlus/issues/126
# for more information).
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
}
# PROD
location ~ ^/app\.php(/|$) {
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
# When you are using symlinks to link the document root to the
# current version of your application, you should pass the real
# application path instead of the path to the symlink to PHP
# FPM.
# Otherwise, PHP's OPcache may not properly detect changes to
# your PHP files (see https://github.com/zendtech/ZendOptimizerPlus/issues/126
# for more information).
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
# Prevents URIs that include the front controller. This will 404:
# http://domain.tld/app.php/some-path
# Remove the internal directive to allow URIs like this
internal;
}
# return 404 for all other php files not matching the front controller
# this prevents access to other php files you don't want to be accessible.
location ~ \.php$ {
return 404;
}
error_log /var/log/nginx/project_error.log;
access_log /var/log/nginx/project_access.log;
}
PHP-FPM の設定に依存しますが、fastcgi_pass
は fastcgi_pass 127.0.0.1:9000
かも知れません。
これは、webディレクトリ内で、app.php
, app_dev.php
および config.php
だけを実行します。".php"
で終わる他の全てのファイルは拒否されるでしょう。
webディレクトリに実行する必要がある他のPHPファイルがある場合、上のlocationブロック内に必ずそれらを含めてください。
プロダクションに配備した後で、app_dev.php
あるいは config.php
スクリプト (つまり http://example.com/app_dev.php
および http://example.com/config.php
) にアクセスできないことを確かめてください。それらにアクセスできる場合、上の設定からDEVの部分を必ず削除してください。
upstream phpfcgi {
server 127.0.0.1:9000;
# server unix:/var/run/php5-fpm.sock; #for PHP-FPM running on UNIX socket
}
server {
listen 80;
server_name symfony2;
root /var/www/symfony2/web;
error_log /var/log/nginx/symfony2.error.log;
access_log /var/log/nginx/symfony2.access.log;
# strip app.php/ prefix if it is present
rewrite ^/app\.php/?(.*)$ /$1 permanent;
location / {
index app.php;
try_files $uri @rewriteapp;
}
location @rewriteapp {
rewrite ^(.*)$ /app.php/$1 last;
}
# pass the PHP scripts to FastCGI server from upstream phpfcgi
location ~ ^/(app|app_dev|config)\.php(/|$) {
fastcgi_pass phpfcgi;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTPS off;
}
}
server {
listen 443;
server_name symfony2;
root /var/www/symfony2/web;
ssl on;
ssl_certificate /etc/ssl/certs/symfony2.crt;
ssl_certificate_key /etc/ssl/private/symfony2.key;
error_log /var/log/nginx/symfony2.error.log;
access_log /var/log/nginx/symfony2.access.log;
# strip app.php/ prefix if it is present
rewrite ^/app\.php/?(.*)$ /$1 permanent;
location / {
index app.php;
try_files $uri @rewriteapp;
}
location @rewriteapp {
rewrite ^(.*)$ /app.php/$1 last;
}
# pass the PHP scripts to FastCGI server from upstream phpfcgi
location ~ ^/(app|app_dev|config)\.php(/|$) {
fastcgi_pass phpfcgi;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTPS on;
}
}
server {
listen 80;
server_name mysite.com;
root /var/www/mysite.com/web;
access_log /var/log/nginx/mysite.com.access.log;
error_log /var/log/nginx/mysite.com.error.log;
location ~ ^/(index|frontend|frontend_dev|backend|backend_dev)\.php$ {
include fastcgi_params;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
fastcgi_param HTTPS off;
fastcgi_pass 127.0.0.1:9000;
}
location / {
index index.php;
try_files $uri /index.php?$args;
}
}
server {
listen 443;
ssl on;
ssl_certificate /etc/ssl/certs/mysite.com.crt;
ssl_certificate_key /etc/ssl/private/mysite.com.key;
server_name mysite.com;
root /var/www/mysite.com/web;
access_log /var/log/nginx/mysite.com.access.log;
error_log /var/log/nginx/mysite.com.error.log;
location ~ ^/(index|frontend|frontend_dev|backend|backend_dev)\.php$ {
include fastcgi_params;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
fastcgi_param HTTPS on;
fastcgi_pass 127.0.0.1:9000;
}
location / {
index index.php;
try_files $uri /index.php?$args;
}
}
注意
この上の設定はPHPでのファイルアップロードアタックに対して脆弱性はありませんが、以下を使う設定は脆弱性があります:
location ~ \.php$ {
...
}
ファイルアップロードアタックへの一般的な回避策は、php.ini内でfix_pathinfo=0
を設定することです。これはpathinfo URLを壊し、symfonyはそれらに依存します。ここで使われている解決策は、phpとしてパースされるファイルを明示的に指定することです。
更に詳しい情報は、nginx+php-cgi security alertを見てください。
location / {
try_files $uri $uri/ /index.php$uri?$args;
}
location ^~ /sf/ {
alias /usr/share/php/data/symfony/web/sf/;
}
location ~ "^(.+\.php)($|/)" {
fastcgi_split_path_info ^(.+\.php)(.*)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_pass 127.0.0.1:9000;
include fastcgi_params;
}
symfonyのための開発サーバとしてNGINXを使っているので、これはディレクトリ内でNGINXを設定および起動するphp (cli)スクリプトで、その結果はdjango開発サーバと似ています。
#!/usr/bin/php
// by Jean-Bernard Addor 2011
if (1 != assert_options(ASSERT_ACTIVE) or 1 != assert_options(ASSERT_WARNING)):
trigger_error('Assertion ignored');
endif;
$return_var = 0;
echo passthru('mkdir --parents '.'/tmp'.getcwd(), $return_var);
assert ('0 == $return_var');
// assert : directory must be writable and executable
// $process = proc_open("env PHP_FCGI_CHILDREN=15 php-cgi -b /tmp".getcwd()."/php.socket", $descriptorspec, $pipes);
// env should be modified here, if this is really needed
$php_process = proc_open("php-cgi -b /tmp".getcwd()."/php.socket",
array(0 => STDIN, 1 => STDOUT, 2 => STDERR), $php_pipes);
assert('FALSE != $php_process');
file_put_contents("/tmp".getcwd()."/nginx.conf", '
worker_processes 1;
error_log /dev/stderr;
pid /tmp'.getcwd().'/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
client_max_body_size 10m;
sendfile on;
gzip on;
keepalive_timeout 65;
server {
listen 8080;
server_name 127.0.0.1;
server_tokens off;
root '.getcwd().'/web;
index index.php index.html index.htm;
access_log /dev/stdout;
location / {
try_files $uri /index.php;
}
location ^~ /frontend_dev.php/ {
try_files $uri /frontend_dev.php;
# try_files $uri /frontend_dev.php?q=$uri&$args /index.php?q=$uri&$args;
}
location ^~ /sf/ {
root '.getcwd().'/lib/vendor/symfony/data/web/;
}
location ~ \.php$ {
include /etc/nginx/fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/tmp'.getcwd().'/php.socket; # 127.0.0.1:9000;
}
location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
expires max;
log_not_found off;
}
}
}
');
// connections should only be accepted from localhost! (security issue)
echo passthru('nginx -c /tmp'.getcwd().'/nginx.conf -t', $return_var);
assert ('0 == $return_var');
usleep(200000); echo "Launching NGINX\n";
// echo passthru('nginx -c /tmp'.getcwd().'/nginx.conf', $return_var);
// assert ('0 == $return_var');
$nginx_process = proc_open('nginx -c /tmp'.getcwd().'/nginx.conf',
array(0 => STDIN, 1 => STDOUT, 2 => STDERR), $nginx_pipes);
assert('FALSE != $nginx_process'); // was blocking with passthru!! PHP 5.3.2-1ubuntu4.9
usleep(200000); // to be sure that stdout and stderr are printed
echo "Waiting for ctrl-c (", posix_getpid(), ")\n";
$oldset = array();
pcntl_sigprocmask(SIG_BLOCK, array(SIGHUP, SIGINT), $oldset);
pcntl_sigwaitinfo(array(SIGHUP, SIGINT, SIGUSR1));
pcntl_sigprocmask(SIG_SETMASK, $oldset);
echo "\nShutting doen NGINX\n";
echo passthru('nginx -c /tmp'.getcwd().'/nginx.conf -s stop', $return_var);
assert ('0 == $return_var');
echo "\nShutting down php-cgi (fcgi)\n";
$php_proc_terminate = proc_terminate($php_process);
$php_proc_close = proc_close($php_process);
assert(-1 != $php_proc_close);
// just for cleaness
$nginx_proc_terminate = proc_terminate($nginx_process);
$nginx_proc_close = proc_close($nginx_process);
assert(-1 != $nginx_proc_close);
?>