Зачем нужен Nginx?

Это веб-сервер, предназначенный в основном для отдачи статики (для того чтобы разгрузить бекенд) и использования в качестве фронтендов. Apache при этом можно использовать в качестве бэкенда для генерации динамического контента.

Так же Nginx можно использовать в режиме FastCGI, при этом Apache вам не понадобится. Однако при этом режиме у PHP наблюдается ряд проблем, поэтому на помощь приходит php-fpm!

Однако мы сегодня поговорим о совместной установке с Apache, а не в режиме FastCGI. Более того, по задаче у нас эти веб-сервера будут находится на одном сервере, поэтому выделим для Nginx — 80, а для Apache — 88 порт!

Apache (см. схему)

nginx

 

web_sch_11

Установка Apache и Nginx

Ставим Apache:

FreeBSD:

cd /usr/ports/www/apache2
make config
make install clean

 

Debian:

Установка Apache

apt-get install apache2
[+mod_rewrite]
a2enmod rewrite

При этом буду установлены так же пакеты:

    • openssl

 

  • openssl-blacklist

 

 

  • ssl-cert

 

 

Если этого не произошло, то необходимо установить их самостоятельно:

sudo apt-get install openssl openssl-blacklist ssl-cert

Создание сертификатов для SSL

Создание ключа

Первым делом необходимо создать приватный ключ (private key):

$ openssl genrsa -des3 -out adminunix.ru.key 2048
Generating RSA private key, 2048 bit long modulus
............................................+++
.....................................+++
e is 65537 (0x10001)
Enter pass phrase for adminunix.ru.key:
Verifying - Enter pass phrase for adminunix.ru.key:

При создании ключа необходимо указать ключевую фразу (и запомнить ее).

Создание подписанного сертификата

После того, как сгенерирован ключ, можно создавать самоподписанный сертификат (CSR — Certificate Signing Reques):

$ openssl req -new -key adminunix.ru.key -out adminunix.ru.csr
Enter pass phrase for adminunix.ru.key:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:RU
State or Province Name (full name) [Some-State]:Russia
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:adminunix.ru
Organizational Unit Name (eg, section) []:
Common Name (eg, YOUR name) []:lists.adminunix.rulists.adminunix.rulists.adminunix.ru
Email Address []:ssl@lists.adminunix.rulists.adminunix.rulists.adminunix.ru
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

Удаление пароля из ключа

Неприятной особенностью ключа с паролем является то, что Apache или nginx будет регулярно спрашивать пароль при старте. Очевидно, что это не очень удобно (если только кто-то не находится постоянно рядом на случай перезагрузки или аварийной остановки). Для удаления ключа из пароля необходимо выполнить следующее:

$ cp adminunix.ru.key adminunix.ru.key.orig
$ openssl rsa -in adminunix.ru.key.orig -out adminunix.ru.key
Enter pass phrase for adminunix.ru.key.orig: <пароль-который-указывался-при-создании-adminunix.ru.key>
writing RSA key

Генерация SSL сертификата

Далее, создаем сам SSL сертификат:

$ openssl x509 -req -days 365 -in adminunix.ru.csr -signkey adminunix.ru.key -out adminunix.ru.crt
Signature ok
subject=/C=RU/ST=Russia/O=adminunix.ru/CN=lists.adminunix.rulists.adminunix.rulists.adminunix.ru/emailAddress=ssl@lists.adminunix.rulists.adminunix.rulists.adminunix.ru
Getting Private key

Теперь есть все, что необходимо для создания SSL-соединений.

Правильное расположение SSL сертификатов

Заключительным шагом в создании SSL сертификата будет распределение полученных файлов в соответствующие директории. Во-первых, копируем сам сертификат:

$ sudo cp adminunix.ru.crt /etc/ssl/certs/

Во-вторых, копируем ключ:

$ sudo cp adminunix.ru.key /etc/ssl/private/

И в-третьих, удаляем, все то, что было создано в текущей директории:

$ rm adminunix.ru.crt adminunix.ru.key adminunix.ru.csr adminunix.ru.key.orig

 

Ставим Nginx:

FreeBSD:

cd /usr/ports/www/nginx
make config
make install clean

Debian:

 apt-get install nginx
 Конфиги -> /etc/nginx

Настройка Nginx

Отредактируем файл /usr/local/etc/nginx/nginx.conf

# пользователь и группа от которого запускается процесс
user  www-data;

# кол-во рабочих процессов. Обычно равно кол-ву ядер на машине
worker_processes  2;

# Лог для ошибок
error_log  logs/error.log;

events {

    # максимум рабочих соединений
    worker_connections  1024;

    # Метод обработки соединений
    # kqueue — эффективный метод, используемый во FreeBSD
    # Подробнее [urlspan]http://sysoev.ru/nginx/docs/events.html[/urlspan]
    use kqueue;
}

http {

    # Подключаем таблицу mime
    include       mime.types;

    # mime-тип по умолчанию
    default_type  application/octet-stream;

    # Формат лог файла
    #log_format  main  '$remote_addr - $remote_user [$time_local] $request '
    #                  '"$status" $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';

    # Лог доступа всего веб-сервера
    #access_log  logs/access.log  main;

    # Директива задаёт таймаут при чтении заголовка запроса клиента
    client_header_timeout  3m;

    # Директива задаёт таймаут при чтении тела запроса клиента
    client_body_timeout    3m;

    # Директива задаёт таймаут при передаче ответа клиенту
    send_timeout           3m;

    # Директива задаёт таймаут, в течение которого keep-alive соединение с клиентом не будет закрыто со стороны сервера
    keepalive_timeout      2m;

    # Директива разрешает или запрещает использовать sendfile()
    sendfile        on;

    # Директива разрешает или запрещает использовать опции TCP_NOPUSH во FreeBSD

    #tcp_nopush     on;

    # Директива задаёт размер буфера для чтения заголовка запроса клиента
    #client_header_buffer_size    1k;

    # Директива задаёт максимальное число и размер буферов для чтения большого заголовка запроса клиента
    #large_client_header_buffers  4 4k;
    # Настройки сжатия
       gzip on;
       gzip_disable "msie6";
       ssi on;
       gzip_comp_level 3;
       gzip_proxied any;
       gzip_types text/plain text/html text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript;
 # Модуль позволяет описывать группы серверов, которые могут использоваться
 # в директивах proxy_pass и fastcgi_pass. upstream backend {
# Директива задаёт имя и параметры сервера. Обратите внимание, мы будем
# использовать имя "backend" в директиве proxy_pass server 127.0.0.1:88; } server {
# Слушать 80 порт listen 80;
# Использовать следующие хосты server_name adminunix.ru www.adminunix.ru;
# Кодировка #
charset koi8-r;
# Лог доступа для конкретного виртуального хоста
#access_log logs/host.access.log main;
# Максимальный размер тела запроса клиента client_max_body_size 101M;
# Разруливаем статику и динамку, смотрите описание ниже в этой статье! location ~* .(jpg|jpeg|gif|png|ico|css|bmp|swf|js)$ { root /home/adminunix/adminunix.ru; } location ~ /.ht { deny all; } #Секция описывает параметры, по которым фронтенд обменивается с бекендом,
#такие, как адресабекенда, параметры прямого редиректа, парарметры передачи заголовков,
#максимальный размер принимаемых файлов и пр.
}
}

Создаем файл конфигурации proxy.conf:
$ sudo mcedit /etc/nginx/proxy.conf

Должен иметь следующий вид:

proxy_redirect              off;
proxy_set_header            Host $host;
proxy_set_header            X-Real-IP $remote_addr;
proxy_set_header            X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size        10m;
client_body_buffer_size     128k;
proxy_connect_timeout       90;
proxy_send_timeout          90;
proxy_read_timeout          90;
proxy_buffer_size           4k;
proxy_buffers               4 32k;
proxy_busy_buffers_size     64k;
proxy_temp_file_write_size  64k;

Настройка виртуального хоста в Nginx

Создаем файл виртуального хоста:

$ sudo mcedit /etc/nginx/sites-available/adminunix.ru.vhost

Файл следующего вида:

upstream backend {
  # Адрес back-end'a
  server 127.0.0.1:8080;
}

server {
    listen   80;
    server_name www.adminunix.ru adminunix.ru;

    access_log /home/site/adminunix.ru/logs/nginx_access.log;
    error_log /home/site/adminunix.ru/logs/nginx_error.log;

    # Перенаправление на back-end
    location / {
        proxy_pass  http://backend;
        include     /etc/nginx/proxy.conf;
    }

    # Статическиое наполнение отдает сам nginx
    # back-end этим заниматься не должен
    location ~* .(jpg|jpeg|gif|png|ico|css|bmp|swf|js)$ {
        root /home/site/adminunix.ru/static/;
    }
}

Создание виртуальных хостов в Nginx

Создаем описание двух виртуальных хостов:

$ sudo touch /etc/nginx/sites-available/adminunix.ru.vhost
$ sudo touch /etc/nginx/sites-available/lists.adminunix.ru-ssl.vhost

Создаем необходимые директории двух виртуальных хостов:

$ sudo mkdir -p /usr/local/hosting/www/adminunix.ru/logs
$ sudo mkdir -p /usr/local/hosting/www/adminunix.ru/apache
# создаем html файл, который будет отражаться при обращении к "http://adminunix.ru"
$ sudo touch /usr/local/hosting/www/adminunix.ru-1/index.html
$ sudo mkdir -p /usr/local/hosting/www/lists.adminunix.ru/logs
$ sudo mkdir -p /usr/local/hosting/www/lists.adminunix.ru/apache
# создаем html файл, который будет отражаться при обращении к "http(s)://lists.adminunix.ru"
$ sudo touch /usr/local/hosting/www/lists.adminunix.ru/index.html
$ sudo chown www-data:www-data -R /usr/local/hosting/www/

Настройка стандартного виртуального хоста в Nginx

Файл настройки должен иметь следующий вид:

#$ sudo cat /etc/nginx/sites-available/adminunix.ru.vhost
upstream backend {
  # Адрес back-end'a
  server 127.0.0.1:8080;
}

server {
    listen   80;
    server_name adminunix.ru;

    access_log /usr/local/hosting/www/adminunix.ru/logs/nginx_access.log;
    error_log /usr/local/hosting/www/adminunix.ru/logs/nginx_error.log;
    # Перенаправление на back-end
    location / {
        proxy_pass  http://backend;
        include     /etc/nginx/proxy.conf;
    }
    # ...
}

Настройка виртуального хоста в Nginx с поддержкой SSL

Файл настройки должен иметь следующий вид:

#$ sudo cat /etc/nginx/sites-available/listen.adminunix-ssl.vhost
upstream backend1 {
  # Адрес back-end'a
  server 127.0.0.1:8080;
}

server {
    listen   80;
    server_name lists.adminunix.ru;

    access_log /usr/local/hosting/www/lists.adminunix.ru/logs/nginx_access.log;
    error_log /usr/local/hosting/www/lists.adminunix.ru/logs/nginx_error.log;

    # Перенаправление на back-end
    location / {
        proxy_pass  http://backend1;
        include     /etc/nginx/proxy.conf;
    }
    # ...
}

server {
    listen   443;
    server_name lists.adminunix.ru;

    ssl    on;
    ssl_certificate         /etc/ssl/certs/lists.adminunix.ru.crt;
    ssl_certificate_key     /etc/ssl/private/lists.adminunix.ru.key;

    access_log /usr/local/hosting/www/lists.adminunix.ru/logs/nginx_ssl_access.log;
    error_log /usr/local/hosting/www/lists.adminunix.ru/logs/nginx_ssl_error.log;
    # Перенаправление на back-end
    location / {
        proxy_pass  http://backend1;
        include     /etc/nginx/proxy.conf;
    }
    # ...
}

В отличие от конфигурации для adminunix.ru тут уже появляется описание для 443 порта. Идея проста — ssl-соединение создает nginx, а вот данные по этому соединению передает уже apache.

Включение хостов и перезапуск Nginx

После того, как настройки сделаны, необходимо сделать виртуальные хосты достпными и перезапустить nginx:

$ sudo ln -s /etc/nginx/sites-available/adminunix.ru.vhost /etc/nginx/sites-enabled/adminunix.ru
$ sudo ln -s /etc/nginx/sites-available/adminunix.ru-ssl.vhost /etc/nginx/sites-enabled/adminunix.ru-ssl.vhost
$ sudo /etc/init.d/nginx restart

Создание виртуальных хостов в Apache

Так как ssl-соединениями занимается nginx, то apache остается всего лишь работать на не стандартном порту (например, 8080) и обрабатывает входящие содинения. Создаем файлы виртуальных хостов Apache:

#$ sudo cat /etc/apache2/sites-available/adminunix.ru.vhost
<VirtualHost *:8080>
  # Осн. настройки домена
  ServerAdmin admin@adminunix.ru
  ServerName adminunix.ru

  DocumentRoot /usr/local/hosting/www/adminunix.ru/
  <Directory /usr/local/hosting/www/adminunix.r/>
      Order deny,allow
      Allow from all
  </Directory>

  ErrorLog  /usr/local/hosting/www/adminunix.ru/logs/apache_error.log
  CustomLog /usr/local/hosting/www/adminunix.ru/logs/apache_access.log combined
  # Остальные настройки
  # ...
</VirtualHost>

Второй хост:

#$ sudo cat /etc/apache2/sites-available/lists.adminunix.ru
<VirtualHost *:8080>
  # Осн. настройки домена
  ServerAdmin admin@lists.adminunix.ru
  ServerName lists.adminunix.ru

  DocumentRoot /usr/local/hosting/www/lists.adminunix.ru/
  <Directory /usr/local/hosting/www/lists.adminunix.ru/>
      Order deny,allow
      Allow from all
  </Directory>

  ErrorLog  /usr/local/hosting/www/lists.adminunix.ru/logs/apache_error.log
  CustomLog /usr/local/hosting/www/lists.adminunix.ru/logs/apache_access.log combined
  # Остальные настройки
  # ...
</VirtualHost>

Далее, необходимо включить хосты и перегрузить apache:

$ sudo a2ensite adminunix.ru
$ sudo a2ensite lists.adminunix.ru
$ sudo /etc/init.d/apache2 restart

Проверка SSL соединения

Чтобы проверить корректность настройки SSL достаточно открыть в браузере https://lists.adminunix.ru/. Так как используется самоподписанный сертификат, то браузер, вероятнее всего, выдаст предупреждение, что подлинность сервера не может быть проверена, и предоставит возможность просмотреть сертификат. В случае, если текущий домен не совпадает с тем, что указан «Common Name», может быть выдано еще одно предупреждение.

Самоподписанных сертификтов как правило хватает для административных зон на сайтах. При использовании коммерческих сертификатов никаких предупреждений выдаваться не будет.

Для более тонкой настройки SSL или для решения проблем в TLS/SSL-соединениях следует пользоваться набором утилит openssl. Например:

$ openssl s_client -connect lists.adminunix.rulists.adminunix.rulists.adminunix.ru:443

После конфигурации необходимо перезагрузить Nginx

/usr/local/etc/rc.d/nginx restart

Nginx: Отдаем статику

web_sch_2 С помощью этих правил разруливаем запросы на отдачу статику и динамического контента

# Следующие расширения файлов (jpg, jpeg, gif, png, ico, css, bmp, swf и js) отдаются напрямую, без участия Apache.
location ~* .(jpg|jpeg|gif|png|ico|css|bmp|swf|js)$ {
    root /home/adminunix/adminunix.ru;
}

# htaccess и htpasswd не отдаем
location ~ /.ht {
       deny  all;
}

# Все остальное разруливает бекенд (Apache)
location / {

        # Адрес бекенда. Параметры бекенда перечислили в директиве "upstream" (см. выше в статье)
        proxy_pass http://backend/;

        # Заголовок Host
        proxy_set_header Host $host;

        # Заголовок X-Real-IP
        proxy_set_header X-Real-IP $remote_addr;

        # Заголовок X-Forwarded-For
        proxy_set_header X-Forwarded-For $remote_addr;

        # Директива задаёт таймаут для соединения с проксированным сервером, сек
        proxy_connect_timeout 120;

        # Директива задаёт таймаут при передаче запроса проксированному серверу, сек
        proxy_send_timeout    120;
        # Директива задаёт таймаут при чтении ответа проксированного сервера, сек
        proxy_read_timeout    180;
}

Настройка Apache

Редактируем файл /usr/local/etc/apache2/httpd.conf

# Меняем порт с 80 на 88
Listen 88

Тоже самое делаем и в httpd-vhosts.conf для ваших хостов.

Если у вас появляется следующая ошибка:
> [warn] (2) No such file or directory:
> Failed to enable the ‘httpready’ Accept Filter

то вам следует подгрузить модуль
# kldload accf_http

Установка и настройка RPAF или даешь верный REMOTE_ADDR!

Так как у нас появился в цепи дополнительный элемент в виде фронтенд-сервера, то теперь в REMOTE_ADDR у нас не пользовательский IP, а IP-адрес фронтенд-сервера (на котором расположен Nginx). Поэтому на помощь приходит RPAF, он берет тело заголовка X-Forwarded-For, присланного от фронтенда и формирует на бекенде из него REMOTE_ADDR.

Таким образом заголовок REMOTE_ADDR снова имеет пользовательский IP!

Устанавливаем модуль RPAF
FreeBSD

cd /usr/ports/www/mod_rpaf2
make install clean

Debian

apt-get install libapache2-mod-rpaf
a2enmod rpaf
mod_rpaf2 - для apache2, а для первого индейца надо mod_rpaf

Настраиваем RPAF, редактируем httpd.conf, добавляем в конец файла:

# Включаем модуль
RPAFenable On
# Доводит до ума X-Host
RPAFsethostname On
# Адрес фронтенда (nginx)
RPAFproxy_ips 82.146.61.55 127.0.0.1
# Имя отправляемого заголовка
RPAFheader X-Forwarded-For
или
RPAFheader X-Real-IP

После конфигурации необходимо перезагрузить Apache

apachectl restart

Debian 

/etc/init.d/apache2 restart
/etc/init.d/nginx restart

Ну вот вроде и все, смотрите ниже дополнительную литературу и задавайте вопросы в камменты!

Полезные материалы по Nginx

[urlspan]Полезные ссылки[/urlspan]
[urlspan]Пример конфигурации nginx[/urlspan]
Настройка виртуальных серверов
Отличная статья с Хабра: [urlspan]Тюнинг nginx[/urlspan]

Устал я от того что мой блог долго грузится, но менять движок с WordPress на что-либо другое пока нет времени, а переезд на новый более мощный сервер всё время затягивается и решил прикрутить кеширование на стороне Nginx. Так как блог работает на fastcgi, то буду использовать fastcgi_cache, если вы используете связку Nginx+Apache, то вам следует использовать proxy_cache, как я понял там отличий особых нет.

Некоторые блоки мне всетаки надо оставить вне кеша, поэтому буду использовать ssi.

Настройка

У меня много хостов на одном сервере, но мне надо настроить кеш только для одного хоста. Определим кеш для моего блога в nginx.conf, секция http:

fastcgi_cache_path /var/cache/nginx/adw0rd
    levels=1:2
    keys_zone=adw0rd:16m
    max_size=256m
    inactive=1d;

Где,

fastcgi_cache_path  — путь до каталога кеша, создайте его заблаговременно.
levels= — разделять файлы кеша на сабкаталоги заданного уровня, то есть «1:2» — это так:

/0/ab/b7f54b2df7773722d382f4809d650ab0

либо так, если не указывать LEVEL, то есть levels оставить пустым (levels=):

/b7f54b2df7773722d382f4809d650ab0

max_size — максимальный размер кеша.
incative — время жизни кеша.

Настройка виртуального хоста

Я разделяю конфиги на основной (nginx.conf) и на хосты (adw0rd.conf, pyha.conf, etc). Сейчас мы разберемся с adw0rd.conf:

server {
    # Порт который слушаем
    listen 80;
    # Имя хоста
    server_name adw0rd.ru;
    # Путь до htdocs (document_root)
    root /path/to/www;

    # включаем использование ssi
    ssi on;

    location / {
        # Если такой файл не существует физически, то переходить на крайний аргумент, то есть @wordpress
        try_files $uri @wordpress;
    }

    # обработчик для wordpress
    location @wordpress {

        # Проксируем на php-fpm
        fastcgi_pass php-fpm;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root/index.php;
        fastcgi_param SCRIPT_NAME /index.php;

        # Настройки кеширования
        fastcgi_temp_path /tmp/nginx 1 2; # Каталог для хранение временных файлов
        fastcgi_cache adw0rd; # Имя зоны кеша
        fastcgi_cache_key "$request_method|$host|$request_uri"; # Из этих данных строится хеш
        fastcgi_hide_header "Set-Cookie"; # Не передавать клиенту заголовки кук
        fastcgi_cache_min_uses 1; # Кол-во запросов, после которых ответ будет закеширован
        fastcgi_cache_valid 10m; # Время жизни кеша
        fastcgi_cache_use_stale error timeout invalid_header http_500; # Случаи при которых будет использоватся старый кеш

    }

    # обработчик для динамических данных на странице, ниже я покажу как юзать это
    location ~ ^/ssi/ {
        fastcgi_pass php-fpm;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }

    # Обработчик *.php файлов, например "wp-comments-post.php"
    location ~ .php$ {

        # если файл физически не существует, то переходим в @wordpress
        try_files $uri @wordpress;
        # иначе обрабатываем запрос
        fastcgi_pass php-fpm;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

Обо всех директивах можете прочитать в оф. доке [urlspan]Директивы модуля ngx_http_fastcgi_module[/urlspan].

Тестирование

Перезагружаем Nginx:

nginx -s reload

Для тестирования кеша я встроил в шаблон html-комментарий, который формирую так:

<!-- cache: <?php echo time() ?> -->

И теперь вижу в сорце странице закешировалась страница или нет.

Вставка динамических блоков при помощи SSI

Отредактируйте шаблон своей страницы и вставьте нечто подобное:

<!-- uncached_data: <!--# include virtual="/ssi/uncached.php" wait="no" --> -->

Теперь приведите файл «/ssi/uncached.php» к следующему виду:

<?php
echo time();

Так как у нас есть обработчик действующий для /ssi/* и он не отдает кешированные данные, то у нас будет подгружатся динамика, все просто!

Дополнение

 

Директива fastcgi_ignore_headers для игнорирования инструкци от FastCGI-сервера

Директива fastcgi_ignore_headers запрещает обработку некоторых строк заголовка из ответа FastCGI-сервера. В директиве можно указать строки «X-Accel-Redirect», «X-Accel-Expires», «Expires» и «Cache-Control».

fastcgi_ignore_headers Expires Cache-Control;

То есть указываем Nginx кэшировать страницы в любом случае, независимо от заголовков кэширования выставленных FastCGI-сервером.

Директивы fastcgi_cache_bypass и fastcgi_no_cache

Директива задаёт условия, при которых ответ не будет браться из кэша. Если значение хотя бы одной из строк переменных не пустое и не равно «0», то ответ не берётся из кэша:

fastcgi_cache_bypass $cookie_session $cookie_nocache;

Директива задаёт условия, при которых ответ не будет сохраняться в кэш. Если значение хотя бы одной из строк переменных не пустое и не равно «0», то ответ не будет сохранён:

fastcgi_no_cache $cookie_session $cookie_nocache;

Управление кеширование через заголовок X-Accel-Expires

Будем управлять кеширование из PHP:

<?php
header("X-Accel-Expires: $seconds"); // ставим на $seconds секунд
header("X-Accel-Expires: 0"); // или отключаем кеширование для определенной страницы

Принудительное обновление кэша

Обновим наш bypass, добавим еще одну переменную для заголовка «X-Update»:

fastcgi_cache_bypass $cookie_session $http_x_update;

Ну а теперь обновим кеш:

curl -s -o /dev/null -H "X-Update: 1" example.com

Как и рекомендуют авторы статьи необходимо изменить «$http_x_update» и «X-Update» на что-то своё, чтобы скрипткидесы не баловались.

Полезные материалы

Вот небольшой список статей, который вам могут пригодится:

Note: I am talking about a component previously in Zend Server, but is now a standalone module and [urlspan]open-sourced[/urlspan], and will be bundle with [urlspan]PHP 5.5[/urlspan], it has performance/usability edge over the more widely used APC.

Now here is my problem, I cannot seem to get Zend Optimizer+ work properly with my codeigniter-powered (PHP framework) site, my debug config is as following:

zend_optimizerplus.enable=1
zend_optimizerplus.memory_consumption=128
zend_optimizerplus.interned_strings_buffer=8
zend_optimizerplus.max_accelerated_files=4000
zend_optimizerplus.revalidate_freq=10
zend_optimizerplus.fast_shutdown=1
zend_optimizerplus.enable_cli=1
zend_optimizerplus.optimization_level=0
zend_optimizerplus.error_log=/var/log/zendop.log

Once ZO+ is enabled, I started to see php-fpm logs such as these (but nothing else, no segfault error, no entries in ZO+ error log):

[13-Mar-2013 00:58:45] WARNING: [pool www] child 6734 exited with code 1 after 176.326628 seconds from start
[13-Mar-2013 00:58:45] NOTICE: [pool www] child 6761 started

Basically php worker process were stopped and restarted. And all page appear to be outputing only partially. I turned on php error display with error_reporting(E_ALL & ~E_NOTICE); but still don't see any error from PHP itself.

All I can find in Nginx log were entries like:

2013/03/13 00:22:47 [error] 1761#0: *14 readv() failed (104: Connection reset by peer) while reading response header from upstream, client: [my ip address], server: [my server name], request: "GET /leave HTTP/1.1", upstream: "fastcgi://127.0.0.1:9000", host: [my host name].
2013/03/13 00:22:47 [error] 1761#0: *17 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: [my ip address], server: [my server name], request: "GET /leave HTTP/1.1", upstream: "fastcgi://127.0.0.1:9000", host: [my host name].

I can't seem to find much insight regarding what were happening, and I can confirm the site works without ZO+ fine, and ZO+ source appear to compile and install correctly (make test also passed correctly, though there aren't many tests to run).

Anyone had experience with Zend Optimizer+? I am surprised to see no mention of soon-to-be PHP-bundled module anywhere on this site.

php -v

PHP 5.3.10-1ubuntu3.5 with Suhosin-Patch (cli) (built: Jan 18 2013 23:40:19)
Copyright (c) 1997-2012 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2012 Zend Technologies

nginx -v

nginx version: nginx/1.1.19

(If this post belongs to stackoverflow, please help to migrate, though I am not seeing a programming-related error here.)

Тут я привожу русский перевод конфигурационного файла httpd.conf сервера Apache. Помимо перевода обозначений директив, так же подробно описано пояснение к каждой из них.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
# Основан на конфигурационных файлах сервера NCSA,
# написанных Rob McCool.
#
# Это главный конфиг-файл сервера Apache,
# содержащий директивы, управляющие
# работой сервера. За более подробной информацией об этих директивах,
# обращайтесь по адресу <URL:http://httpd.apache.org/docs-2.0/>
#
# Не стоит читать приведенные здесь команды, не вникая в их суть. Здесь
# они служат лишь в качестве примера или шпаргалки. Если вы не
# уверены — обращайтесь к онлайновой документации. Вы предупреждены.
#
# Конфигурационные директивы сгруппированы в три основные разделы :
#
# 1. Директивы, управляющие серверным процессом Apache в целом
#   («глобальная среда»).
#
# 2. Директивы, определяющие параметры «главного»
# или дефолтного сервера,
# который отвечает на запросы, не обрабатываемые каким-либо
# виртуальным хостом. Эти директивы также задают дефолтные
# установки для всех виртуальных хостов.
#
# 3. Установки для виртуальных хостов, позволяющие единым серверным
#   процессом Apache обрабатывать веб-запросы, на самом деле
#  адресованные различным хостам (по имени хоста или по IP).
#
# Наименования конфиг- и лог-файлов : Если имя файла начинается с «/» (или c
# «диск:/» под Win32) — сервер использует явно указанный путь. Если же имя
# НЕ начинается с «/», то к нему префиксируется значение ServerRoot.
# Т.о., если ServerRoot="/usr/local/apache", то «logs/foo.log» сервер
# интерпретирует как «/usr/local/apache/logs/foo.log»
#
#
# ПРИМЕЧАНИЕ: При определении имен файлов необходимо использовать прямые
# слэши вместо обратных (т.е. «c:/apache» вместо «c:apache»).
# Если диск не указан, по умолчанию используется тот, на котором размещен
# Apache.exe. Для однозначности, все же, рекомендуется в абсолютных путях
# всегда четко указывать диск.
#
#
### Раздел 1: Глобальная среда
#
# Директивы в этом разделе задают общие параметры работы Apache, такие, как,
# например, максимальное число одновременных запросов или
# месторасположение конфиг файлов.
#
# ServerRoot: Вершина дерева директорий, в которых содержатся конфиг- , лог- и
# error-файлы.
#
# ПРИМЕЧАНИЕ : Если это дерево будет располагаться на томе монтируемой
# файловой системы NFS (или на другом сетевом ресурсе),
# просьба прочесть описание директивы LockFile
# (по адресу <URL:http://httpd.apache.org/docs-2.0/mod/core.html#lockfile>)
# — во избежание массы проблем.
#
# В конце строки добавлять слэш НЕ следует.
#
ServerRoot "E:/Apache2"
#
# ScoreBoardFile: Файл для хранения информации внутреннего процесса сервера.
# Если не указан (по дефолту не указан), то эта информация хранится в
# неименованном разделе общей памяти, и не доступна посторонним программам.
# Если же файл указан, то он должен быть уникальным для каждой отдельной
# инстанции Apache. Этот файл должен располагаться на МЕСТНОМ диске.
#
#ScoreBoardFile logs/apache_runtime_status
#
# Файл записи идентификационного номера процесса (PID) сервера при запуске.
#
PidFile logs/httpd.pid
#
# Timeout: Время ожидания в секундах, прежде чем попытки приема или отправления
# выдают сообщение о тайм-ауте.
#
Timeout 300
#
# KeepAlive: Допускаются ли персистентные соединения (см. примечания).
# Для запрета укажите «Off».
#
KeepAlive On
#
#
# MaxKeepAliveRequests: Максимальное количество запросов при одном
# персистентном соединении. Значение 0 снимает ограничения. Для максимального
# быстродействия рекомендуем высокое значение.
#
MaxKeepAliveRequests 100
#
# KeepAliveTimeout: Время ожидания (в секундах) следующего запроса от того же
# клиента в рамках одного персистентного соединения
#
KeepAliveTimeout 15
#
#
# Server-Pool Size Regulation (MPM specific)
#
# Установка размеров серверного пула. Параметры данного подраздела
# меняются в зависимости от конкретного модуля мультизадачного режима
# (MPM — Multi-Processing Module), который, в свою очередь, меняется в
# зависимости от конкретной базовой ОС.
#
# WinNT MPM
# ThreadsPerChild: constant number of worker threads in the server process
# MaxRequestsPerChild: maximum number of requests a server process serves
#
# WinNT MPM : Мультизадачный модуль для Win32
# ThreadsPerChild: Постоянное число рабочих нитей (тредов) в серверном(sic)
# процессе
# MaxRequestsPerChild: Максимальное количество запросов, обслуживаемых
# серверным(sic) процессом
#
# (В обоих случаях, речь, на самом деле, идет о дочерних процессах сервера,
# а не о самом серверном процессе. Дело в том, что в случае Win32, который
# как раз здесь рассматривается, запускается один лишь единственный дочерний
# процесс, поэтому для WinNT_MPM эти понятия, в некоторой степени,
# совпадают -пп)
#
<IfModule mpm_winnt.c>
ThreadsPerChild 250
MaxRequestsPerChild 0
</IfModule>
#
# Listen: Позволяет привязать Apache к конкретным адресам IP и/или портам,
# помимо(sic) дефолтных. См. также директиву <VirtualHost>.
#
# Следует поменять это на конкретные адреса IP (как показано ниже), чтобы
# Apache не «прилипал» ко всем привязанным адресам (0.0.0.0)
#
# (Автор здесь немного противоречит себе. Возможно, правильнее второй абзац,
# а первый просто остался по наследству от предыдущих версий. Следует
# отметить, что в отличии от предыдущих версий, директива Listen теперь
# является обязательной — без нее Apache стартовать не будет -пп).
#
#Listen 12.34.56.78:80
Listen 80
#
#
# Поддержка динамических, разделяемых объектов (DSO, Dynamic Shared Object)
#
# Для того, чтобы использовать модули, созданные как DSO, следует поместить
# здесь соответствующие строки с директивой «LoadModule», чтобы команды этого
# модуля были доступны ДО обращения к ним. Статически скомпилированные модули
# (выявляемые по команде «httpd -l») в этом не нуждаются.
#
# Пример:
# LoadModule foo_module modules/mod_foo.so
#
LoadModule access_module modules/mod_access.so
LoadModule actions_module modules/mod_actions.so
LoadModule alias_module modules/mod_alias.so
LoadModule asis_module modules/mod_asis.so
LoadModule auth_module modules/mod_auth.so
#LoadModule auth_anon_module modules/mod_auth_anon.so
#LoadModule auth_dbm_module modules/mod_auth_dbm.so
#LoadModule auth_digest_module modules/mod_auth_digest.so
LoadModule autoindex_module modules/mod_autoindex.so
#LoadModule cern_meta_module modules/mod_cern_meta.so
LoadModule cgi_module modules/mod_cgi.so
#LoadModule dav_module modules/mod_dav.so
#LoadModule dav_fs_module modules/mod_dav_fs.so
LoadModule dir_module modules/mod_dir.so
LoadModule env_module modules/mod_env.so
#LoadModule expires_module modules/mod_expires.so
#LoadModule file_cache_module modules/mod_file_cache.so
#LoadModule headers_module modules/mod_headers.so
LoadModule imap_module modules/mod_imap.so
LoadModule include_module modules/mod_include.so
#LoadModule info_module modules/mod_info.so
LoadModule isapi_module modules/mod_isapi.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule mime_module modules/mod_mime.so
#LoadModule mime_magic_module modules/mod_mime_magic.so
#LoadModule proxy_module modules/mod_proxy.so
#LoadModule proxy_connect_module modules/mod_proxy_connect.so
#LoadModule proxy_http_module modules/mod_proxy_http.so
#LoadModule proxy_ftp_module modules/mod_proxy_ftp.so
LoadModule negotiation_module modules/mod_negotiation.so
#LoadModule rewrite_module modules/mod_rewrite.so
LoadModule setenvif_module modules/mod_setenvif.so
#LoadModule speling_module modules/mod_speling.so
#LoadModule status_module modules/mod_status.so
#LoadModule unique_id_module modules/mod_unique_id.so
LoadModule userdir_module modules/mod_userdir.so
#LoadModule usertrack_module modules/mod_usertrack.so
#LoadModule vhost_alias_module modules/mod_vhost_alias.so
#LoadModule ssl_module modules/mod_ssl.so
#
# Директива ExtendedStatus определяет, будет ли Apache выдавать подробную
# информацию о состоянии (ExtendedStatus On), или только общую справку
# (ExtendedStatus Off), при обращении к функции «server-status». Значение по
# умолчанию — Off.
#
#ExtendedStatus On
#
#
### Раздел 2: Конфигурация «главного» (дефолтного) сервера
#
# Директивы этого раздела устанавливают значения, используемые «главным
# сервером», который отвечает на запросы, не обрабатываемые виртуальными
# хостами. Эти значения также задают дефолты для любых последующих
# контейнеров <VirtualHost> в этом файле.
#
# Любые из этих директив могут быть включены в контейнер <VirtualHost>; в таком
# случае дефолтные установки будут переопределены для этого виртуального хоста.
#
# ServerAdmin: Ваш адрес, по которому следует направлять сообщения о проблемах
# с сервером. Этот адрес появится на некоторых сгенерированных сервером
# страницах, таких, как сообщения об ошибках. Пример: admin@your-domain.com
#
ServerAdmin admin@admin.com
#
# Директива ServerName задает имя и порт, которыми сервер представляется.
# Это часто может быть определено автоматически, но рекомендуется явно задавать
# эти параметры, во избежание проблем при запуске.
#
# Если Servername не указывает на действительное DNS-имя вашего хоста,
# переадресация, сгенерированная сервером, не будет работать. См. также
# директиву UseCanonicalName
#
# Если ваш хост не имеет зарегистрированного DNS-имени, укажите здесь его IP.
# В любом случае вам придется обращаться к нему по адресу, при этом
# переадресация станет разумней.
#
ServerName server:80
#
# UseCanonicalName: Определяет как Apache строит внутренние URL-ссылки и
# значения переменных SERVER_NAME и SERVER_PORT. Когда задано «Off», Apache
# использует имя и порт, данные клиентом. Если же задано «On», то Apache
# использует значение директивы ServerName.
#
UseCanonicalName Off
#
# DocumentRoot: Директория, из которой будут выдаваться ваши документы.
# По умолчанию, все запросы обслуживаются из этой директории, но могут быть
# использованы символические линки (пересылки) и алиасы (псевдонимы) для
# указания других мест.
#
DocumentRoot "E:/Apache2/htdocs"
#
#
# Каждая доступная для Apache директория может быть сконфигурирована в
# отношении действий и сервисов, которые разрешены и/или запрещены в
# этой директории (и ее суб-директориях).
#
# Для начала, мы определяем «дефолт», как весьма ограниченный набор разрешений.
#
<Directory />
  Options FollowSymLinks
  AllowOverride None
</Directory>
#
# Заметьте, что в дальнейшем вы должны явно разрешать конкретные действия так
# что, если что-то не работает так, как вы ожидаете, убедитесь, что вы явно
# разрешили это ниже.
#
# Здесь должна быть указана директория, которую вы установили как DocumentRoot.
#
<Directory "E:/Apache2/htdocs">
#
# Опции могут иметь значения «None», «All» или любую комбинацию из :
# «Indexes», «Includes», «FollowSymLinks», «SymLinksifOwnerMatch», «ExecCGI»,
# и «Multiviews».
#
# Заметьте, что опция «MultiViews» должна быть ЯВНО указана — т.к.
# «Options All» ее НЕ включает.
#
# Директива Options является и сложной и важной. Для дополнительной информации
# см. «http://httpd.apache.org/docs-2.0/mod/core.html#options»
#
    Options Indexes FollowSymLinks
#
# AllowOverride определяет какие директивы могут быть использованы в файлах
# .htaccess. Она может принимать значения «All», «None», или любую
# комбинацию из : «Options», «FileInfo», «AuthConfig», и «Limit»
#
    AllowOverride None
#
# Эти директивы определяют, кто может получать материал с этого сервера.
#
  Order allow,deny
  Allow from all
</Directory>
#
#
# UserDir: Имя директории, которое постфиксируется к имени домашней директории
# пользователя при получении запроса ~user. Будьте особенно внимательны — здесь
# используются прямые слеши.
#
UserDir "My Documents/My Website"
#
# Управляет доступом к директориям UserDir. Приведен пример сайта, где эти
# директории имеют ограничение «read-only» (только чтение).
#
# Исправьте (в следующем) корневой путь, чтобы он соответствовал
# местонахождению директории пользователя в вашей системе, например,
# «C:/WinNT/profiles/*/My Documents/My Website».
#
#<Directory «C:/Documents and Settings/*/My Documents/My Website»>
#  AllowOverride FileInfo AuthConfig Limit
#  Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec
#  <Limit GET POST OPTIONS PROPFIND>
#    Order allow,deny
#    Allow from all
#  </Limit>
#  <LimitExcept GET POST OPTIONS PROPFIND>
#    Order deny,allow
#    Deny from all
#  </LimitExcept>
#</Directory>
#
#
# DirectoryIndex: Имя файла, выдаваемого Apache в ответ на запрос директории.
#
# Файл «index.html.var» (типа type-map или application/x-type-map) используется
# для выдачи конкретной разновидности многовариантного документа в зависимости
# от параметров запроса (content-negotiated). Опция MultiViews может служить
# той же цели, но она намного медленее.
#
DirectoryIndex index.html index.html.var
#
# AccessFileName: Имя файла в каждой директории, задающего правила доступа (к
# этой директории). См. также директиву AllowOverride.
#
AccessFileName .htaccess
#
# Следующие строки запрещают просмотр файлов «.htaccess» и «.htpasswd»
# со стороны Web-клиентов.
#
<Files ~ "^.ht">
  Order allow,deny
  Deny from all
</Files>
#
# TypesConfig опеределяет местонахождение файла «mime.type» (или ему
# эквивалентного).
#
TypesConfig conf/mime.types
#
#
# Директива DefaultType — это дефолтный MIME-тип, используемый сервером для
# документов, тип которых не определяем по иным признакам, таким, как
# расширение имени файла. Если ваш сервер содержит в основном текстовые или
# HTML-документы, «text/plain» является подходящим значением. Если большая
# часть представляет собой бинарные файлы, такие, как программы или
# изображения, возможно использование «application/octet-stream», чтобы
# предотвратить попытки браузеров показывать содержимое двоичных файлов как
# текст.
#
DefaultType text/plain
#
#
# Модуль «mod_mime_magic» позволяет серверу использовать различные приемы для
# определения типа файла по его содержанию. Директива MIMEMagicFile указывает
# этому модулю месторасположение (файла с описаниями) этих приемов.
#
<IfModule mod_mime_magic.c>
  MIMEMagicFile conf/magic
</IfModule>
#
#
# HostnameLookups определяет, записывать ли имена клиентов, или только их
# IP-адреса, например, «www.apache.org» («On») или «204.62.129.132»(«Off»).
# По дефолту «Off», поскольку в целом для Интернета было бы лучше, если бы
# эта опция включалась сознательно, т.к. ее включение означает, что каждый
# клиентский запрос влечет за собой КАК МИНИМУМ еще один обратный запрос к
# серверу имен.
#
HostnameLookups Off
#
# ErrorLog: Расположение error-файла. Если вы не задаете директиву ErrorLog
# внутри контейнера какого-либо <VirtualHost>, его сообщения об ошибках
# будут записаны здесь. Если же вы определите error-файл для какого-либо
# <VirtualHost>, то его сообщения об ошибках будут записываться там, а не здесь.
#
ErrorLog logs/error.log
#
#
# LogLevel: Control the number of messages logged to the error.log.
# Possible values include: debug, info, notice, warn, error, crit,
# alert, emerg.
#
# LogLevel: Определение количества(sic) ошибок, которые записываются в
# error.log. Возможные значения :
# «debug», «info», «notice», «warn», «error», «crit», «alert», и «emerg».
#
LogLevel warn
#
# Следующие директивы присваивают имена некоторым определениям
# форматов записей, для использования в директиве
# CustomLog (см. ниже).
#
LogFormat "%h %l %u %t "%r" %>s %b "%{Referer}i" "%{User-Agent}i"" combined
LogFormat "%h %l %u %t "%r" %>s %b" common
LogFormat "%{Referer}i -> %U" referer
LogFormat "%{User-agent}i" agent
# (слово access — здесь как запрос о доступе, а не как доступ — пп)
#
# Расположение и формат лог-файла запросов (в общем формате лог-файлов —
# Common Logfile Format). Если вы не определяете никаких лог-файлов запросов
# внутри контейнера какого-либо <VirtualHost>, сведения будут записываться
# здесь. Если же вы определяете отдельные лог-файлы запросов для каждого(sic)
# <VirtualHost>, то транзакции будут отслеживаться там, а не здесь.
#
# (Наверное, здесь имеется в виду «для отдельных» <VirtualHost>, а не
# «для каждого» -пп)
#
CustomLog logs/access.log common
#
#
# Если вы хотите иметь лог-файлы для отслеживания значений agent и referrer
# (из соответствующих полей поступающих запросов -пп), раскомментируйте
# следующие директивы.
#
#CustomLog logs/referer.log referer
#CustomLog logs/agent.log agent
#
# Если вы предпочитаете единый лог-файл с информацией о запросе, агенте и
# referrer (комбинированный формат лог-файла — Combined Logfile Format),
# вы можете использовать следующую директиву.
#
#CustomLog logs/access.log combined
#
#
# Добавить дополнительную строчку, содержащую версию сервера и имя виртуального
# хоста на страницах, сгенерированных сервером (таких, как сообщения об
# ошибках, FTP листинги директорий, выдачи модулей «mod_status» и «mod_info»
# и т.п.; документы, сгенерированные скриптами CGI, к ним не относятся).
# Установите «EMail», чтобы включить еще и линк «mailto:», направленный
# на ServerAdmin.
# Допустимые значения: On | Off | Email
#
ServerSignature On
#
#
# Алиасы (Псевдонимы): Можно добавлять любое количество алиасов (без
# ограничений). Формат: Alias псевдоним действительное_имя
#
# Обратите внимание, что если вы включаете завершающий слэш в псевдониме, то
# сервер потребует его наличия и в URL. Так, псевдоним «/icons» не определен в
# данном примере, только «/icons/». Если псевдоним закначивается на слеш,
# действительное_имя также должно заканчиваться на слеш, а если псевдоним его
# опускает, то и действительное_имя его должно опустить.
#
# Мы используем алиас «/icons/» для листингов директорий типа FancyIndexed.
# Можно закомментировать эту часть, если вы не используете FancyIndexing.
#
Alias /icons/ "E:/Apache2/icons/"
<Directory "E:/Apache2/icons">
  Options Indexes MultiViews
  AllowOverride None
  Order allow,deny
  Allow from all
</Directory>
#
# Следует поменять это значение на (ваш) ServerRoot/manual/. Данный алиас
# обеспечивает доступ к документации, даже если вы передвините свой
# DocumentRoot. Можно эту часть закомментировать, если документация не нужна.
#
Alias /manual "E:/Apache2/manual"
#
<Directory "E:/Apache2/manual">
  Options Indexes FollowSymLinks MultiViews
  AllowOverride None
  Order allow,deny
  Allow from all
</Directory>
#
#
# ScriptAlias: Указывает директории, которые содержат серверные скрипты.
# Свойства ScriptAlias-ов в основном такие же, как и у простых Alias-ов,
# кроме того, что при запросе, документы в каталоге «действительное_имя»
# считаются приложениями и выполняются на сервере, а не отправляются
# клиенту. К директиве ScriptAlias применяются те же правила в отношении
# завершающего «/», что и к Alias.
#
ScriptAlias /cgi-bin/ "E:/Apache2/cgi-bin/"
#
# Значение «E:/Apache2/cgi-bin» следует поменять на существующую директорию
# CGI, указанную в ScriptAlias.
#
<Directory "E:/Apache2/cgi-bin">
  AllowOverride None
  Options None
  Order allow,deny
  Allow from all
</Directory>
#
# Директива Redirect позволяет сообщить клиенту о документах, ранее
# существовавших в именном пространстве сервера, но теперь не существующих.
# Она позволяет сообщить клиенту новый адрес перемещенного документа.
# Пример:
# «Redirect permanent /foo http://www.example.com/bar»
#
#
# Директивы, управляющие внешним видом листингов директории,
# генерируемых сервером.
#
#
# FancyIndexing задает, хотите ли вы стилизованные листинги директорий или
# же стандартные. VersionSort определяет, будут ли файлы с номерами версий
# сравниваться «естественно», т.е. так, чтобы в листинге файл
# «apache-1.3.9.tar» предшествовал файлу «apache-1.3.12.tar».
#
IndexOptions FancyIndexing VersionSort
#
#
# Директивы AddIcon* указывают серверу, какие иконы показывать для
# различных файлов, или расширений имен файлов. Они показываются только
# для директорий с FancyIndexing.
#
AddIconByEncoding (CMP,/icons/compressed.gif) x-compress x-gzip
AddIconByType (TXT,/icons/text.gif) text/*
AddIconByType (IMG,/icons/image2.gif) image/*
AddIconByType (SND,/icons/sound2.gif) audio/*
AddIconByType (VID,/icons/movie.gif) video/*
AddIcon /icons/binary.gif .bin .exe
AddIcon /icons/binhex.gif .hqx
AddIcon /icons/tar.gif .tar
AddIcon /icons/world2.gif .wrl .wrl.gz .vrml .vrm .iv
AddIcon /icons/compressed.gif .Z .z .tgz .gz .zip
AddIcon /icons/a.gif .ps .ai .eps
AddIcon /icons/layout.gif .html .shtml .htm .pdf
AddIcon /icons/text.gif .txt
AddIcon /icons/c.gif .c
AddIcon /icons/p.gif .pl .py
AddIcon /icons/f.gif .for
AddIcon /icons/dvi.gif .dvi
AddIcon /icons/uuencoded.gif .uu
AddIcon /icons/script.gif .conf .sh .shar .csh .ksh .tcl
AddIcon /icons/tex.gif .tex
AddIcon /icons/bomb.gif core
AddIcon /icons/back.gif ...
AddIcon /icons/hand.right.gif README
AddIcon /icons/folder.gif ^^DIRECTORY^^
AddIcon /icons/blank.gif ^^BLANKICON^^
#
# DefaultIcon показывает какую икону показывать для файлов, не имеющих
# явно определенных икон.
#
DefaultIcon /icons/unknown.gif
#
#
# Директива AddDescription позволяет поместить краткое описание после имени
# файла в листингах, сгенерированных сервером. Они показываются только для
# директорий с FancyIndexing.
#
# Формат: AddDescription «описание» имя_файла
#
#AddDescription «GZIP compressed document» .gz
#AddDescription «tar archive» .tar
#AddDescription «GZIP compressed tar archive» .tgz
#
#
# ReadmeName — это дефолтное имя README-файла, который сервер будет искать по
# умолчанию и добавит в конце листингов директорий.
#
# HeaderName — имя файла, который будет добавлен в начале листингов директорий.
#
ReadmeName README.html
HeaderName HEADER.html
#
#
# IndexIgnore — это список файлов, которые должны быть исключены из
# листингов. В именах файлов допускается использование метасимволов замены в
# стиле shell.
#
IndexIgnore .??* *~ *# HEADER* README* RCS CVS *,v *,t
#
#
# AddEncoding позволяет некоторым браузерам (Mosaic/X 2.1+) на ходу
# распаковывать информацию. Замечание: не все браузеры поддерживают это.
# Несмотря на сходство имен, следующие директивы Add* не имеют ничего общего
# с директивами форматирования FancyIndexing, указанными выше.
#
AddEncoding x-compress Z
AddEncoding x-gzip gz tgz
#
#
# DefaultLanguage и AddLanguage позволяют указать языки документов. Вы можете
# в последствие использовать динамическое определение содержимого (content
# negotiation) для выдачи браузеру файла на языке понятном пользователю.
#
#
# Установка языка default. Это означает, что вся информация, идущая без
# конкретного языкового тэга (см. ниже), будет идти на дефолтном языке.
# Вероятно, не стоит задавать эту директиву, не будучи твердо уверенным в том,
# что она подходит для всех случаев.
#
#
# * В общем, лучше не указывать определенный язык
# * для страницы, чем задать неправильный язык.
#
# DefaultLanguage nl
#
# Примечание 1: Суффикс не обязательно должен совпадать с
# кодом-идентификатором языка. Те, у кого есть документы
# на польском языке (стандартный буквенный
# код Интернета pl), могут воспользоваться директивой
# «AddLanguage pl .po» во избежание конфликта с распространенным
# суффиксом скриптов на языке Perl.
#
# Примечание 2: Нижеследующие примеры показывают, что в некоторых
# случаях двухбуквенный код языка не совпадает с двухбуквенным
# кодом соответствующей страны.
# Например, Датский (da) и Дания (dk).
#
# Примечание 3: В случае «ltz» мы нарушаем требования RFC, используя
# трехбуквенный код. Ведется работа по устранению несоответствий и
# усовершенствованию «rfc1766».
#
# Danish, датский (da)
# Dutch, голландский, (nl)
# English, английский (en)
# Estonian, эстонский (et)
# French, французский (fr)
# German, немецкий (de)
# Greek-Modern, новогреческий (el)
# Italian, итальянский (it)
# Norwegian, норвежский (no)
# Norwegian Nynorsk (nn)
# Korean, корейский (kr)
# Portugese, португальский (pt)
# Luxembourgeois*, люксембургский (ltz)
# Spanish, испанский (es)
# Swedish, шведский (sv)
# Catalan, каталанский (ca)
# Czech, чешский(cz)
# Polish, польский (pl)
# Brazilian Portuguese, бразильско-португальский (pt-br)
# Japanese, японскский (ja)
# Russian, русский (ru)
# Croatian, хорватский (hr)
#
AddLanguage da .dk
AddLanguage nl .<code class="bash functions">nl
AddLanguage en .en
AddLanguage et .et
AddLanguage fr .fr
AddLanguage de .de
AddLanguage he .he
AddLanguage el .el
AddLanguage it .it
AddLanguage ja .ja
AddLanguage pl .po
AddLanguage kr .kr
AddLanguage pt .pt
AddLanguage nn .nn
AddLanguage no .no
AddLanguage pt-br .pt-br
AddLanguage ltz .ltz
AddLanguage ca .ca
AddLanguage es .es
AddLanguage sv .se
AddLanguage cz .cz
AddLanguage ru .ru
AddLanguage tw .tw
AddLanguage zh-tw .tw
AddLanguage hr .hr
#
# LanguagePriority позволяет задать порядок выбора некоторых языков (в случае
# неоднозначности) при динамическом определении содержания (content
# negotiation).
#
# Просто перечислите языки в порядке убывания приоритета. Здесь они даны в
# более-менее алфавитном порядке. Вероятно, вы захотите изменить этот порядок.
#
LanguagePriority en da nl et fr de el it ja kr no pl pt pt-br ltz ca es sv tw
#
# ForceLanguagePriority позволяет вам (серверу) выдать конкретную страницу,
# вместо сообщения MULTIPLE CHOICES (задается Prefer), [в случае неоднозначного
# выбора], или сообщения NOT ACCEPTABLE (задается Fallback)[в случае, если
# не один язык не подошел]
#
ForceLanguagePriority Prefer Fallback
#
#
# AddDefaultCharset задает дефолтную таблицу символов (кодировку) для всех
# выдаваемых страниц. Это всегда полезно, и открывает возможность будущей
# мультилингвизации вашего веб сайта. Ее обозначение как дефолтной не
# наносит вреда, т.к. стандарт, в любом случае, определяет, что страница
# использует кодировку iso-8859-1 (latin1), если не указано иначе, т.е. вы
# просто подтверждаете очевидное. Существуют так же соображения о безопасности
# для браузеров, относящиеся к обработке javascript и URL, по которым всегда
# стоит указывать дефолтную кодировку.
#
AddDefaultCharset WINDOWS-1251
#
#
# Часто используемые расширения для обозначения кодировок. Вы, вероятно,
# захотите избежать столкновений с языковыми расширениями, если вы не
# специалист по тщательному тестированию установок после каждого изменения.
# См. «ftp://ftp.isi.edu/in-notes/iana/assignments/character-sets» для
# официального списка кодировок и соответствующих им документов RFC.
#
AddCharset ISO-8859-1 .iso8859-1 .latin1
AddCharset ISO-8859-2 .iso8859-2 .latin2 .cen
AddCharset ISO-8859-3 .iso8859-3 .latin3
AddCharset ISO-8859-4 .iso8859-4 .latin4
AddCharset ISO-8859-5 .iso8859-5 .latin5 .cyr .iso-ru
AddCharset ISO-8859-6 .iso8859-6 .latin6 .arb
AddCharset ISO-8859-7 .iso8859-7 .latin7 .grk
AddCharset ISO-8859-8 .iso8859-8 .latin8 .heb
AddCharset ISO-8859-9 .iso8859-9 .latin9 .trk
AddCharset ISO-2022-JP .iso2022-jp .jis
AddCharset ISO-2022-KR .iso2022-kr .kis
AddCharset ISO-2022-CN .iso2022-cn .cis
AddCharset Big5    .Big5    .big5
#
#
# Для русского языка используется более, чем одна кодировка (в основном,
# зависит от клиента):
#
AddCharset WINDOWS-1251 .cp-1251  .win-1251
AddCharset CP866    .cp866
AddCharset KOI8-r   .koi8-r .koi8-ru
AddCharset KOI8-ru   .koi8-uk .ua
AddCharset ISO-10646-UCS-2 .ucs2
AddCharset ISO-10646-UCS-4 .ucs4
AddCharset UTF-8    .utf8
#
#
# Ниже приведенный список не соответствует конкретному (iso) стандарту, но
# работает с довольно широким списком браузеров. Заметьте, что верхний регистр,
# на самом деле, имеет значение (этого не должно происходить, но с некоторыми
# браузерами, тем не менее, происходит).
#
# См. «ftp://ftp.isi.edu/in-notes/iana/assignments/character-sets» для своего
# рода списка (кодировок). Но браузеры поддерживают только некоторые из них.
#
AddCharset GB2312   .gb2312 .gb
AddCharset utf-7    .utf7
AddCharset utf-8    .utf8
AddCharset big5    .big5 .b5
AddCharset EUC-TW   .euc-tw
AddCharset EUC-JP   .euc-jp
AddCharset EUC-KR   .euc-kr
AddCharset shift_jis  .sjis
#
# AddType позволяет добавить новые MIME-типы (или переопределить старые из
# конфигурационного файла «mime.types») для определенных типов файлов.
#
AddType application/x-tar .tgz
#
# AddHandler позволяет связать определенные расширения имен файлов с
# обработчиками (handlers), вне зависимости от типа файла.
# Обработчики могут быть либо встроены в сервер, либо добавлены директивой
# Action (см. ниже).
#
# Для использования скриптов CGI вне директорий типа ScriptAliased :
# (Кроме того, вам придется добавить «ExecCGI» к директиве «Options»)
#
#AddHandler cgi-script .cgi
#
# Для файлов, которые включают свои HTTP заголовки:
#
#AddHandler send-as-is asis
#
# Для imagemap файлов, обрабатываемых сервером:
#
#AddHandler imap-file map
#
# Для type-maps (динамически определяемых ресурсов):
# Включено по умолчанию, чтобы допустить распространение страницы
# Apache «It Worked» («Сработало!») на различных языках.
#
AddHandler type-map var
#
#
# Фильтры позволяют обработать содержание до отправки клиенту.
#
# Для обработки .shtml файлов на предмет вставок, производимых сервером
# (server-side includes — SSI):
# (Кроме того, вам придется добавить «Includes» к директиве «Options»)
#
#AddOutputFilter INCLUDES .shtml
#
#
# Action позволяет определить MIME или другие типы (для которых задан
# какой-нибудь handler), при запросе которых выполняется соответствующий
# скрипт. Это устраняет необходимость многократного упоминания URL путей
# часто используемых скриптов CGI.
#
# Format: Action media/type /cgi-script/location
# Format: Action handler-name /cgi-script/location
#
# Формат: Action  название_MIME_типа            путь/скрипт
#     Action  назавние_типа_или_обработчика(handler)  путь/скрипт
#
#
# Существует три типа настроек для конфигурируемых сообщений об ошибках:
# 1) простой текст 2) местные ссылки 3) внешние пересылки
#
# Некоторые примеры:
#
#ErrorDocument 500 «The server made a boo boo.»
#ErrorDocument 404 /missing.html
#ErrorDocument 404 «/cgi-bin/missing_handler.pl»
#ErrorDocument 402 http://www.example.com/subscription_info.html
#
# Собрав все это воедино, мы можем мультилингвизировать сообщения об ошибках.
#
# Мы используем Alias чтобы перенаправлять сообщения
# «/error/HTTP_<error>.html.var» на наборы сообщений на разных языках
# (собранных по типу ошибки). Мы используем «includes» для вставления
# необходимого текста.
#
#  Alias /error/include/ «/your/include/path/»
#
#
# Можно изменить вид сообщения, не меняя никаких дефолтных
# «HTTP_<error>.html.var» файлов, добавив строку;
#
#  Alias /error/include/ «/your/include/path/»
#
# которая позволяет вам создать свой набор файлов, начав с файлов
# «E:/Apache2/error/include/» и копируя их в «/your/include/path/»,
# в том числе и для отдельных VirtualHost.
#
#
<IfModule mod_negotiation.c>
<IfModule mod_include.c>
  Alias /error/ "E:/Apache2/error/"
  <Directory "E:/Apache2/error">
    AllowOverride None
    Options IncludesNoExec
    AddOutputFilter Includes html
    AddHandler type-map var
    Order allow,deny
    Allow from all
    LanguagePriority en es de fr
    ForceLanguagePriority Prefer Fallback
  </Directory>
  ErrorDocument 400 /error/HTTP_BAD_REQUEST.html.var
  ErrorDocument 401 /error/HTTP_UNAUTHORIZED.html.var
  ErrorDocument 403 /error/HTTP_FORBIDDEN.html.var
  ErrorDocument 404 /error/HTTP_NOT_FOUND.html.var
  ErrorDocument 405 /error/HTTP_METHOD_NOT_ALLOWED.html.var
  ErrorDocument 408 /error/HTTP_REQUEST_TIME_OUT.html.var
  ErrorDocument 410 /error/HTTP_GONE.html.var
  ErrorDocument 411 /error/HTTP_LENGTH_REQUIRED.html.var
  ErrorDocument 412 /error/HTTP_PRECONDITION_FAILED.html.var
  ErrorDocument 413 /error/HTTP_REQUEST_ENTITY_TOO_LARGE.html.var
  ErrorDocument 414 /error/HTTP_REQUEST_URI_TOO_LARGE.html.var
  ErrorDocument 415 /error/HTTP_SERVICE_UNAVAILABLE.html.var
  ErrorDocument 500 /error/HTTP_INTERNAL_SERVER_ERROR.html.var
  ErrorDocument 501 /error/HTTP_NOT_IMPLEMENTED.html.var
  ErrorDocument 502 /error/HTTP_BAD_GATEWAY.html.var
  ErrorDocument 503 /error/HTTP_SERVICE_UNAVAILABLE.html.var
  ErrorDocument 506 /error/HTTP_VARIANT_ALSO_VARIES.html.var
</IfModule>
</IfModule>
#
# Следующие директивы модифицируют обычное (в ответ на запросы HTTP)
# поведение сервера, с целью предотвращения некоторых известных проблем
# с конкретными браузерами.
#
BrowserMatch "Mozilla/2" nokeepalive
BrowserMatch "MSIE 4.0b2;" nokeepalive downgrade-1.0 force-response-1.0
BrowserMatch "RealPlayer 4.0" force-response-1.0
BrowserMatch "Java/1.0" force-response-1.0
BrowserMatch "JDK/1.0" force-response-1.0
#
#
# Следующая директива блокирует переадресацию по запросу
# (не использующую метод GET) для директории, не заканчивающейся
# на слэш. Это решает проблему с пакетом «Microsoft WebFolders»,
# который неправильно обрабатывает пересылки для папок методами
# DAV (коллективная система удаленного создания и контроля
# версий документов).
#
BrowserMatch "Microsoft Data Access Internet Publishing Provider" redirect-carefully
BrowserMatch "^WebDrive" redirect-carefully
#
# Разрешить выдачу сообщений-отчетов о состоянии сервера по запросу на URL
# «http://servername/server-status» . Замените «.admin.admin.com» на имя
# своего домена для включения.
#
#<Location /server-status>
#  SetHandler server-status
#  Order deny,allow
#  Deny from all
#  Allow from .admin.admin.com
#</Location>
#
#
# Разрешить выдачу сообщений-отчетов о конфигурации удаленного сервера по
# запросу на URL «http://servername/server-info» . Замените «.your-domain.com»
# на имя своего домена для включения.
#
#<Location /server-info>
#  SetHandler server-info
#  Order deny,allow
#  Deny from all
#  Allow from .admin.admin.com
#</Location>
#
# Директивы прокси-сервера. Раскомментируйте следующие строки, чтобы включить
# прокси-сервер.
#
#<IfModule mod_proxy.c>
#ProxyRequests On
#
#<Proxy *>
#  Order deny,allow
#  Deny from all
#  Allow from .your-domain.com
#</Proxy>
#
#
# Включить/выключить обработку заголовков «HTTP/1.1» типа «Via:» (через)
# (Опция «Full» добавляет номер версии сервера, «Block» отменяет все исходящие
# заголовки типа «Via:».
# Возможные варианты: Off | On | Full | Block
#
#ProxyVia On
#
# Чтобы включить еще и кэширование, откорректируйте и раскомментируйте
# следующие строки
#
#CacheRoot «E:/Apache2/proxy»
#CacheSize 5
#CacheGcInterval 4
#CacheMaxExpire 24
#CacheLastModifiedFactor 0.1
#CacheDefaultExpire 1
#NoCache a-domain.com another-domain.edu joes.garage-sale.com
#</IfModule>
#
# Конец директив прокси сервера.
#
#
# Включить дополнительные конфиг-файлы для отдельных модулей
#
<IfModule mod_ssl.c>
  Include conf/ssl.conf
</IfModule>
#
#
#
###Раздел 3: Виртуальные хосты
#
#
# VirtualHost: Если вы хотите держать множество доменов/хостов на своей машине,
# то задайте для них контейнеры VirtualHost. Большинство конфигураций задает
# только имена виртуальных хостов, с тем, чтобы серверу не требовались
# IP адреса. Данное обстоятельство обозначено звездочками (*) в следующих
# директивах.
#
# См. документацию по адресу <URL:http://httpd.apache.org/docs-2.0/vhosts/>
# для дополнительной информации, прежде чем создавать виртуальные хосты.
#
# Вы можете воспользоваться ключом «-S» для командной строки, чтобы выявить
# конфигурацию ваших виртуальных хостов.
#
#
#
# Использовать виртуальные хосты по их именам.
#
#NameVirtualHost *
#
#
# Пример виртуального хоста.
# Почти любые директивы Apache могут входить в контейнер VirtualHost.
# Первый VirtualHost используется для запросов, направленных на
# неизвестное имя сервера
#<VirtualHost *>
#  ServerAdmin webmaster@dummy-host.example.com
#  DocumentRoot /www/docs/dummy-host.example.com
#  ServerName dummy-host.example.com
#  ErrorLog logs/dummy-host.example.com-error_log
#  CustomLog logs/dummy-host.example.com-access_log common
#</VirtualHost>

РНР не ограничивается созданием только HTML вывода. Вы можете создавать файлы изображений с помощью PHP.

Для этого просто необходимо установить GD library и вы можете создавать различные форматы изображения, такие как GIF, PNG, JPEG, WBMP, и XPM.

Вывод PHP потока возможен и непосредственно в браузер. Вам нужно будет собрать PHP с библиотекой GD функций, для работы с изображениями. GD и PHP могут также потребовать другие библиотеки, в зависимости от форматов с которыми вы хотите работать.

В этом посте вы узнаете , как установить PHP GD модуль на Ubuntu.

Введите следующую команду для установки этого модуля:

1
$sudo apt-getinstall php5-gd

Теперь перезагрузите сервер Apache:

1
# /etc/init.d/apache2 restart

Проверьте, работают ли установлен библиотека php5-GD или нет?

Введите следующую команду:

1
$ php5 -m |grep -i gd

Команда вернется «gd», если Graphics library установлен.

ИЛИ

Вы можете проверить статус установки GD library, запустив ниже показанный PHP код:

1
2
3
<?php
echo phpinfo();
?>

В web-сервер и reverse-proxy nginx встроены очень мощные возможности по кэшированию HTTP-ответов. Однако в ряде случаев документации и примеров не хватает, в результате не все получается так легко и просто, как хотелось бы. Например, мои конфиги nginx-а местами написаны кровью. Этой статьей я попробую немного улучшить ситуацию.

В этой статье: а) подводные камни при полностраничном кэшировании; б) кэширование с ротацией; в) создание динамического «окна» в закэшированной странице.

Я буду предполагать, что вы используете связку nginx+fastcgi_php. Если вы применяете nginx+apache+mod_php, просто замените имена директив с fastcgi_cache* на proxy_cache*

Если выбирать, кэшировать ли страницу на стороне PHP или на стороне nginx, я выбираю nginx. Во-первых, это позволяет отдавать 5-10 тыс. запросов в секунду без каких-либо сложностей и без умных разговоров о «высокой нагрузке». Во-вторых, nginx самостоятельно следит за размером кэша и чистит его как при устаревании, так и при вытеснении нечасто используемых данных.

Кэширование всей страницы целиком

Если на вашем сайте главная страница хоть и генерируется динамически, но меняется достаточно редко, можно сильно снизить нагрузку на сервер, закэшировав ее в nginx. При высокой посещаемости даже кэширование на короткий срок (5 минут и меньше) уже дает огромный прирост в производительности, ведь кэш работает очень быстро. Даже закэшировав страницу всего на 30 секунд, вы все равно добьетесь значительной разгрузки сервера, сохранив при этом динамичность обновления данных (во многих случаях обновления раз в 30 секунд вполне достаточно).

Например, закэшировать главную страницу можно так:

fastcgi_cache_path /var/cache/nginx levels= keys_zone=wholepage:50m;
...
server {
  ...
  location / {
    ...
    fastcgi_pass 127.0.0.1:9000;
    ...
    # Включаем кэширование и тщательно выбираем ключ кэша.
    fastcgi_cache wholepage;
    fastcgi_cache_valid 200 301 302 304 5m;
    fastcgi_cache_key "$request_method|$http_if_modified_since|$http_if_none_match|$host|$request_uri";
    # Гарантируем, что разные пользователи не получат одну и ту же сессионную Cookie.
    fastcgi_hide_header "Set-Cookie";
    # Заставляем nginx кэшировать страницу в любом случае, независимо от
    # заголовков кэширования, выставляемых в PHP.
    fastcgi_ignore_headers "Cache-Control" "Expires";
  }
}

Я не сильно преувеличу, если скажу, что каждая строчка в этом конфиге написана кровью. Здесь много подводных камней, давайте их все рассмотрим.

fastcgi_cache_path: простота отладки тоже важна

fastcgi_cache_path /var/cache/nginx levels= keys_zone=wholepage:50m;

В директиве fastcgi_cache_path я выставляю «пустое» значение для levels. Хотя это немного снижает производительность (файлы будут напрямую создаваться в /var/cache/nginx, без разбиения по директориям), но зато на порядок облегчает отладку и диагностику проблем с кэшем. Поверьте, вам еще не раз придется руками залезать в /var/cache/nginx и смотреть, что там хранится.

fastcgi_cache_valid: кэшируем код ответа 304 тоже

fastcgi_cache_valid 200 301 302 304 5m;

В директиве fastcgi_cache_valid мы заставляем кэшировать не только стандартные коды 200 ОК, 301 Moved Permanently и 302 Found, но также и 304 Not Modified. Почему? Давайте вспомним, что означает 304. Он выдается с пустым телом ответа в двух случаях:

  • Если браузер послал заголовок «If-Modified-Since: date», в котором date больше либо равна значению заголовка ответа «Last-Modified: date». Т.е. клиент спрашивает: «Есть ли новая версия с момента date? Если нет, верни мне 304 и сэкономь трафик. Если есть, отдай мне тело страницы».
  • Если браузер послал заголовок «If-None-Match: hash», где hash совапдает со значением заголовка ответа «ETag: hash». Т.е. клиент спрашивает: «Отличается ли текущая версия страницы от той, что я запросил в прошлый раз? Если нет, верни мне 304 и сэкономь трафик. Если да, отдай тело страницы».

В обоих случаях Last-Modified или ETag будут взяты, скорее всего, из кэша nginx, и проверка пройдет очень быстро. Нам незачем «дергать» PHP только для того, чтобы скрипт выдал эти заголовки, особенно в свете того, что клиентам, которым уйдет ответ 200, он будет отдан из кэша.

fastcgi_cache_key: внимательно работаем с зависимостями

fastcgi_cache_key «$request_method|$http_if_modified_since|$http_if_none_match|$host|$request_uri»;

Особого внимания заслуживает значение в директиве fastcgi_cache_key. Я привел минимальное рабочее значение этой директивы. Шаг вправо, шаг влево, и вы начнете в ряде случаев получать «неправильные» данные из кэша. Итак:

  • Зависимость от $request_method нам нужна, т.к. HEAD-запросы в Интернете довольно часты. Ответ на HEAD-запрос никогда не содержит тела. Если убрать зависимость от $request_method, то может так совпасть, что кто-то до вас запросил главную страницу HEAD-методом, а вам потом по GET отдастся пустой контент.
  • Зависимость от $http_if_modified_since нужна для того, чтобы кэш с ответом 304 Not Modified не был случайно отдан клиенту, делающему обычный GET-запрос. Иначе клиент может получить пустой ответ из кэша.
  • То же самое и с $http_if_none_match. Мы должны быть застрахованы от выдачи пустых страниц клиентам!
  • Наконец, зависимость от $host и $request_uri не требует комментариев.
fastcgi_hide_header: решаем проблемы с безопасностью

fastcgi_hide_header «Set-Cookie»;

Директива fastcgi_hide_header очень важна. Без нее вы серьезно рискуете безопасностью: пользователи могут получить чужие сессии через сессионную Cookie в кэше. (Правда, в последних версиях nginx что-то было сделано в сторону автоматического учета данного фактора.) Понимаете, как это происходит? На сайт зашел Вася Пупкин, ему выдалась сессия и сессионная Cookie. Пусть кэш на тот момент оказался пустым, и в него записалась Васина Cookie. Затем пришел другой пользователь, получил ответ из кэша, а в нем — и Cookie Васи. А значит, и его сессию тоже.

Можно, конечно, сказать: давайте не будем вызывать session_start () на главной странице, тогда и с Cookies проблем не будет. В теории это так, но на практике данный способ очень неустойчив. Сессии часто стартуют «отложено», и достаточно какой-либо части кода «случайно» вызвать функцию, требующую доступа к сессии, как мы получим дыру в безопасности. А безопасность — такая штука, что если в той или иной методике может возникнуть дыра по неосторожности, то эта методика считается «дырявой» по определению. К тому же есть и другие Cookies, кроме сессионной; их тоже не надо записывать в кэш.

fastcgi_ignore_headers: не даем сайту «лечь» от нагрузки при опечатке

fastcgi_ignore_headers «Cache-Control» «Expires»;

Сервер nginx обращает внимание на заголовки Cache-Control, Expires и Pragma, которые выдает PHP. Если в них сказано, что страницу не нужно кэшировать (либо что она уже устарела), то nginx не записывает ее в кэш-файл. Это поведение, хотя и кажется логичным, на практике порождает массу сложностей. Поэтому мы его блокируем: благодаря fastcgi_ignore_headers в кэш-файлы попадет содержимое любой страницы, независимо от ее заголовков.

Что же это за сложности? Они опять связаны с сессиями и функцией session_start (), которая в PHP по умолчанию выставляет заголовки «Cache-Control: no-cache» и «Pragma: no-cache». Здесь существует три решения проблемы:

  • Не пользоваться session_start () на странице, где предполагается кэширование. Один из минусов этого способа мы уже рассмотрели выше: достаточно одного неосторожного движения, и ваш сайт, принимающий тысячи запросов в секунду на закэшированную главную страницу, моментально «ляжет», когда кэш отключится. Второй минус — нам придется управлять логикой кэширования в двух местах: в конфиге nginx и в PHP-коде. Т.е. эта логика окажется «размазанной» по совершенно разным частям системы.
  • Выставить ini_set ('session.cache_limiter', ''). Это заставит PHP запретить вывод каких-либо заголовков, ограничивающих кэширование при работе с сессиями. Проблема здесь та же: «размазанность» логики кэширования, ведь в идеале мы бы хотели, чтобы все кэширование управлялось из единого места.
  • Игнорировать заголовки запрета кэширования при записи в кэш-файлы при помощи fastcgi_ignore_headers. Кажется, это беспроигрышное решение, поэтому я его и советую.

 

Кэширование с ротацией

Статическая главная страница — это не так уж и интересно. Что делать, если на сайте много материалов, а Главная выступает в роли своеобразной «витрины» для них? На такой «витрине» удобно отображать «случайные» материалы, чтобы разные пользователи видели разное (и даже один пользователь получал новый контент, перезагрузив страницу в браузере).

Решение задачи — кэширование с ротацией:

  1. Мы заставляем скрипт честно выдавать элементы главной странице в случайном порядке, выполняя необходимые запросы в базу данных (пусть это и медленно).
  2. Затем мы сохраняем в кэше не одну, а, скажем, 10 вариантов страницы.
  3. Когда пользователь заходит на сайт, мы показываем ему один из этих вариантов. При этом, если кэш пуст, то запускается скрипт, а если нет, то результат возвращается из кэша.
  4. Устанавливаем время устаревания кэша малым (например, 1 минута), чтобы за день разные пользователи «отсмотрели» все материалы сайта.

В итоге первые 10 запросов к скрипту-генератору выполнятся «честно» и «нагрузят» сервер. Зато потом они «осядут» в кэше и в течение минуты будут выдаваться уже быстро. Прирост производительности тем больше, чем больше посетителей на сайте.

Вот кусочек конфига nginx, реализующий кэширование с ротацией:

fastcgi_cache_path /var/cache/nginx levels= keys_zone=wholepage:50m;
perl_set $rand 'sub { return int rand 10 }';
...
server {
  ...
  location / {
    ...
    fastcgi_pass 127.0.0.1:9000;
    ...
    # Включаем кэширование и тщательно выбираем ключ кэша.
    fastcgi_cache wholepage;
    fastcgi_cache_valid 200 301 302 304 1m;
    fastcgi_cache_key "$rand|$request_method|$http_if_modified_since|$http_if_none_match|$host|$request_uri";
    # Гарантируем, что разные пользователи не получат одну и ту же сессионную Cookie.
    fastcgi_hide_header "Set-Cookie";
    # Заставляем nginx кэшировать страницу в любом случае, независимо от
    # заголовков кэширования, выставляемых в PHP.
    fastcgi_ignore_headers "Cache-Control" "Expires";

    # Заставляем браузер каждый раз перезагружать страницу (для ротации).
    fastcgi_hide_header "Cache-Control";
    add_header Cache-Control "no-store, no-cache, must-revalidate, post-check=0, pre-check=0";
    fastcgi_hide_header "Pragma";
    add_header Pragma "no-cache";
    # Выдаем всегда свежий Last-Modified.
    expires -1; # Внимание!!! Эта строка expires необходима!
    add_header Last-Modified $sent_http_Expires;
  }
}

Вы можете заметить, что по сравнению с предыдущим примером мне пришлось добавить еще 6 директив в location. Они все очень важные! Но не будем забегать вперед, рассмотрим все по порядку.

perl_set: зависимость-рандомизатор

perl_set $rand 'sub { return int rand 10 }';

С директивой perl_set все просто. Мы создаем переменную, при использовании которой nginx будет вызывать функцию встроенного в него Perl-интерпретатора. По словам автора nginx, это достаточно быстрая операция, так что мы не будем «экономить на спичках». Переменная принимает случайное значение от 0 до 9 в каждом из HTTP-запросов.

fastcgi_cache_key: зависимость от рандомизатора

fastcgi_cache_key «$rand|$request_method|...»;

Теперь мы замешиваем переменную-рандомизатор в ключ кэша. В итоге получается 10 разных кэшей на один и тот же URL, что нам и требовалось. Благодаря тому, что скрипт, вызываемый при кэш-промахе, выдает элементы главной страницы в случайном порядке, мы получаем 10 разновидностей главной страницы, каждая из которой «живет» 1 минуту (см. fastcgi_cache_valid).

add_header: принудительно выключаем браузерный кэш

 

fastcgi_hide_header "Cache-Control";
add_header Cache-Control "no-store, no-cache, must-revalidate, post-check=0, pre-check=0";
fastcgi_hide_header "Pragma";
add_header Pragma "no-cache";

Выше мы говорили, что nginx чувствителен к кэш-заголовкам, выдаваемым PHP-скриптом. Если PHP-скрипт возвращает заголовки «Pragma: no-cache» или «Cache-Control: no-store» (а также еще некоторые, например, «Cache-Control: не-сохранять, не-выдавать, меня-тут-не-было, я-этого-не-говорил, чья-это-шляпа»), то nginx не будет сохранять результат в кэш-файлах. Специально чтобы подавить такое его поведение, мы используем fastcgi_ignore_headers (см. выше).

Чем отличается «Pragma: no-cache» от «Cache-Control: no-cache»? Только тем, что Pragma — наследие HTTP/1.0 и сейчас поддерживается для совместимости со старыми браузерами. В HTTP/1.1 используется Cache-Control.

Однако есть еще кэш в браузере. И в некоторых случаях браузер может даже не пытаться делать запрос на сервер, чтобы отобразить страницу; вместо этого он достанет ее из собственного кэша. Т.к. у нас ротация, нам такое поведение неудобно: ведь каждый раз, заходя на страницу, пользователь должен видеть новые данные. (На самом деле, если вы все же хотите закэшировать какой-нибудь один вариант, то можно поэкспериментировать с заголовком Cache-Control.)

Директива add_header как раз и передает в браузер заголовок запрета кэширования. Ну а чтобы этот заголовок случайно не размножился, мы вначале убираем из HTTP-ответа то, что записал туда PHP-скрипт (и то, что записалось в nginx-кэш): директива fastcgi_hide_header. Ведь вы, когда пишете конфиг nginx-а, не знаете, что там надумает выводить PHP (а если используется session_start (), то он точно надумает). Вдруг он выставит свой собственный заголовок Cache-Control? Тогда их будет два: PHP-шный и добавленный нами через add_header.

expires и Last-Modified: гарантируем перезагрузку страницы

 

expires -1; # Внимание!!! Эта строка expires необходима!
add_header Last-Modified $sent_http_Expires;

Еще один трюк: мы должны выставить Last-Modified равным текущему времени. К сожалению, в nginx нет переменной, хранящей текущее время, однако она магическим образом появляется, если указать директиву expires -1.

Хотя это сейчас (октябрь 2009 г.) не задокументировано, nginx создает переменные вида $sent_http_XXX для каждого заголовка ответа XXX, отданного клиенту. Одной из них мы и пользуемся.

Почему же так важно выставлять текущим временем этот заголовок? Все довольно просто.

  1. Давайте представим, что PHP выдал заголовок «Last-Modified: некоторая_дата».
  2. Данный заголовок будет записан в кэш-файл nginx (можете проверить: в нашем примере файлы хранятся в /var/cache/nginx), а потом отдан в браузер клиенту.
  3. Браузер запомнит страницу и дату ее модификации...
  4. … поэтому при следующем заходе пользователя на сайт в HTTP-запросе будет заголовок-вопрос «If-Modified-Since: некоторая_дата».
  5. Что же сделает nginx? Он достанет страницу из своего кэша, разберет ее заголовки и сравнит Last-Modified с If-Modified-Since. Если значения совпадут (или первое окажется меньше второго), то nginx вернет ответ «304 Not Modified» с пустым телом. И пользователь не увидит никакой ротации: он получит то, что уже видел раньше.

На самом деле, большой вопрос, как поведет себя браузер при наличии одновременно Last-Modified и Cache-Control no-cache. Будет ли он делать запрос If-Modified-Since? Кажется, что разные браузеры ведут тут себя по-разному. Экспериментируйте.

Есть и еще один повод выставлять Last-Modified вручную. Дело в том, что PHP-функция session_start () принудительно выдает заголовок Last-Modified, но указывает в нем… время изменения PHP-файла, который первый получил управление. Следовательно, если у вас на сайте все запросы идут на один и тот же скрипт (Front Controller), то ваша Last-Modified будет почти всегда равна времени изменения этого единственного скрипта, что совершенно не верно.

Динамическое «окно» в закэшированной странице

Ну и напоследок упомяну одну технику, которая может быть полезна в свете кэширования. Если вам хочется закэшировать главную (или любую другую) страницу сайта, однако мешает один маленький блок, который обязательно должен быть динамическим, воспользуйтесь модулем для работы с SSI.

В ту часть страницы, которая должна быть динамической, вставьте вот такой «HTML-комментарий»:

<!--# include virtual="/get_user_info/" -->

С точки зрения кэша nginx данный комментарий — обычный текст. Он будет сохранен в кэш-файле именно в виде комментария. Однако позже, при прочтения кэша, сработает модуль SSI nginx, который обратится к динамическому URL. Конечно, по адресу /get_user_info/ должен быть PHP-обработчик, который выдает содержимое данного блока. Более подробно данный способ описан в этой статье с Хабра.

Ну и, естественно, не забудьте включить SSI для этой страницы или даже для всего сервера:

ssi on;

Директива SSI include имеет еще одно, крайне важное свойство. Когда на странице встречаются несколько таких директив, то все они начинают обрабатываться одновременно, в параллельном режиме. Так что, если у вас на странице 4 блока, каждый из которых загружается 200мс, в сумме страница будет получена пользователем через 200мс, а не через 800.

Исходный текст данной статьи можно прочитать тут: http://dklab.ru/chicken/nablas/56.html