Настройка Nginx на Debian Squeeze как front-end к Apache

Статья про оптимизацию Drupal. В статье описано как можно настроить веб-сервер Nginx фронтэндом к Apache. В данном случае Nginx принимает все пользовательские запросы и сам отдает всю статику, а динамические запросы отправляет на Apache.

Продолжаем серию статей по обучению системных администраторов для Drupal проектов.
В предыдущей статье Настройка веб-сервера на Debian и установка Drupal мы сделали базовую настройку веб-сервера и установили Drupal.
У этого решения есть некоторые недостатки:

  1. При работе с клиентами, у которых медленные каналы связи, оперативная память сервера будет занята процессом Apache до тех пор пока он полностью не отдаст запрошенный контент.
  2. Каждый раз когда клиент запрашивает статический контент будет запущен процесс Apache для выдачи этого контента, что тоже будет "отъедать" драгоценную оперативную память сервера.

Отличным способом устранения недостатков нашего решения является использования веб-сервера Nginx в качестве front-end к Apache. Все запросы к статике будет обслуживать Nginx, а запросы к динамических страницам Nginx будет проксировать на Apache. В этой статье мы рассмотрим подробную настройку этого решения.

Почему Nginx?

Nginx — это быстрый HTTP сервер и обратный прокси-сервер (reverse proxy), разработанный Игорем Сысоевым. Основным функционалом Nginx является обслуживание статических запросов, обратное проксирование (reverse proxy) и балансировка нагрузки. С этими задачами веб-сервер Nginx справляется значительно лучше, чем Apache, за счет своей архитектуры. Поэтому в нашей задаче мы вынесем обработку статических запросов из Apache в Nginx и настроим Nginx как обратный прокси-сервер (reverse proxy) для остальных запросов.

Схема работы Nginx в качество front-end к Apache

В результате внедрения в работу Nginx схема работы нашего веб-сервера изменится:  

nginx_apache

  Из схемы видно, что все запросы принимает Nginx, после чего динамические запросы Nginx отправляет на Apache, а все статические запросы Nginx обрабатывает самостоятельно.

Конфигурация Apache

Настраиваем в Apache возможность прослушивания порта 8080 В файле /etc/apache2/ports.conf изменяем строки NameVirtualHost и Listen на следующие:

NameVirtualHost 127.0.0.1:8080
Listen 8080

Вносим изменения в конфигурацию Apache в файле /etc/apache2/sites-enabled/drupaladmin-example.com . Настраиваем Apache на порт 8080, т.к. на порту 80 будет слушать запросы Nginx

<VirtualHost 127.0.0.1:8080>
        ServerAdmin info@drupaladmin-example.com
        ServerName www.drupaladmin-example.com
        ServerAlias drupaladmin-example.com
        DocumentRoot /home/webmaster/domains/drupaladmin-example.com/html
        <Directory /home/webmaster/domains/drupaladmin-example.com/html>
          AllowOverride All
          Options -Indexes +FollowSymLinks
          Require all granted        
        </Directory>
        ErrorLog /home/webmaster/domains/drupaladmin-example.com/logs/apache_errors.log
        # Possible values include: debug, info, notice, warn, error, crit,
        # alert, emerg.
        # LogLevel warn
        CustomLog /home/webmaster/domains/drupaladmin-example.com/logs/apache_access.log combined

        php_admin_value upload_tmp_dir "/home/webmaster/domains/tmp"
        php_admin_value session.save_path "/home/webmaster/domains/tmp"
        AddType application/x-httpd-php .php .php3 .php4 .php5 .phtml
        AddType application/x-httpd-php-source .phps
</VirtualHost>

Перезапускаем Apache

/etc/init.d/apache2 restart

Установка и настройка Nginx

Устанавливаем Nginx из пакетов Debian:

apt-get install nginx

Создаем виртуальный хост Nginx для сайта drupal-admin.ru в файле /etc/nginx/sites-available/drupaladmin-example.com

server {
   listen 80; 
   server_name drupaladmin-example.com www.drupaladmin-example.com;
   root /home/webmaster/domains/drupaladmin-example.com/html;
   index index.php;
   access_log /home/webmaster/domains/drupaladmin-example.com/logs/nginx_access.log;
   error_log /home/webmaster/domains/drupaladmin-example.com/logs/nginx_error.log;
   
   proxy_set_header X-Real-IP $remote_addr;
   proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
   proxy_set_header Host $http_host;
   proxy_hide_header 'X-Drupal-Cache';
   proxy_hide_header 'X-Generator';

   if ($bad_bot) {
      return 444;
   }
   if ($bad_referer) {  
      return 444;  
   }
   if ($not_allowed_method) {
      return 405;
   }
   proxy_http_version 1.1;
   add_header X-XSS-Protection '1; mode=block';
   add_header X-Frame-Options deny;
   add_header X-Content-Options nosniff;
   
   location ~* ^/.well-known/ { 
      allow all;  
   }
   location / {
      location ~* /system/files/ {
         proxy_pass http://127.0.0.1:8080/index.php?q=$uri;
         proxy_set_header Connection '';
         log_not_found off; 
      }
      location ~*  /sites/default/files/private/ { 
         internal;  
      }
      location ~* /imagecache/ {
         expires 30d;
         try_files $uri @drupal; 
      }
      location ~*  /sites/default/files/styles/ {
         expires 30d;
         try_files $uri @drupal;
      }
      location ~* /sites/.+/files/.+\.txt {
         expires 30d;
         tcp_nodelay off;
         open_file_cache max=3000 inactive=120s;
         open_file_cache_valid 45s;
         open_file_cache_min_uses 2;
         open_file_cache_errors off;        
      }
      location ~* /sites/.+/files/advagg_css/ {
         expires max;
         add_header X-XSS-Protection '1; mode=block';
         add_header X-Frame-Options deny;
         add_header X-Content-Options nosniff;
         add_header ETag '';
         add_header Last-Modified 'Wed, 20 Jan 1988 04:20:42 GMT';
         add_header Accept-Ranges '';
         location ~* /sites/.*/files/advagg_css/css[_[:alnum:]]+\.css$ { 
            try_files $uri @drupal;          
         } 
      }
      location ~* /sites/.+/files/advagg_js/ {
         expires max;
         add_header X-XSS-Protection '1; mode=block';
         add_header X-Frame-Options deny;
         add_header X-Content-Options nosniff;         
         add_header ETag '';
         add_header Last-Modified 'Wed, 20 Jan 1988 04:20:42 GMT';
         add_header Accept-Ranges '';
         location ~* /sites/.*/files/advagg_js/js[_[:alnum:]]+\.js$ { 
            try_files $uri @drupal;  
         } 
      }
      location ~* /admin/reports/hacked/.+/diff/ { 
         try_files $uri @drupal;  
      }
      location ~* ^.+\.xml {  
         try_files $uri @drupal;  
      }
      location ~* ^.+\.(?:css|ico|cur|js|jpe?g|gif|htc|ico|png|html|xml|otf|ttf|eot|woff2?|svg|mp3|ogg|mpe?g|avi|zip|gz|bz2?|rar|swf|woff|ogg|mp4|wav|aac|skin)$ {
         expires 30d;
         tcp_nodelay off;
         open_file_cache max=3000 inactive=120s;
         open_file_cache_valid 45s;
         open_file_cache_min_uses 2;
         open_file_cache_errors off;
         location ~* ^.+\.svgz$ {
            gzip off;
            add_header X-XSS-Protection '1; mode=block'; 
            add_header X-Frame-Options deny;    
            add_header X-Content-Options nosniff;             
            add_header Content-Encoding gzip;  
         } 
      }
      location ~* ^.+\.(?:pdf|pptx?)$ {
         expires 30d;
         tcp_nodelay off; 
      }
      location ~* ^(?:.+\.(?:htaccess|make|txt|yml|twig|engine|inc|info|install|module|profile|po|pot|sh|.*sql|test|theme|tpl(?:\.php)?|xtmpl)|code-style\.pl|/Entries.*|/Repository|/Root|/Tag|/Template|composer\.(json|lock))$|^#.*#$|\.php(~|\.sw[op]|\.bak|\.orig|\.save)$ {  
         deny all;   
      }
      try_files $uri @drupal;
   }
   location @drupal {
        proxy_pass http://127.0.0.1:8080/index.php?q=$uri;
        proxy_set_header Connection '';
   }
   location = /authorize.php {
      proxy_pass http://127.0.0.1:8080; 
   }
   location = /cron.php {
      proxy_pass http://127.0.0.1:8080;
   }
   location = /index.php {
      proxy_pass http://127.0.0.1:8080;
   }
   location = /install.php {
      proxy_pass http://127.0.0.1:8080;
   }
   location = /update.php { 
      proxy_pass http://127.0.0.1:8080;
   }
   location = /xmlrpc.php {
      proxy_pass http://127.0.0.1:8080;
   }
   location ^~ /.bzr { 
      return 404; 
   }
   location ^~ /.git { 
      return 404; 
   }
   location ^~ /.hg { 
      return 404; 
   }
   location ^~ /.svn {
      return 404;
   }
   location ^~ /.cvs { 
      return 404;
   }
   location ^~ /patches { 
      return 404; 
   }
   location ^~ /config {   
      return 404; 
   }
   location ^~ /backup { 
      return 404;
   }
   location = /robots.txt { 
      try_files $uri @drupal;  
    }
   location = /favicon.ico {
      expires 30d;
      try_files /favicon.ico @empty; 
   }
   location @empty {
      expires 30d;
      empty_gif; 
   }
   location ~* ^.+\.php$ { 
      return 404; 
   }
}

Активируем виртуальный хост Nginx путем установки ссылки

ln -s /etc/nginx/sites-available/drupaladmin-example.com /etc/nginx/sites-enabled/drupaladmin-example.com

Создаем файл конфигурации Nginx  /etc/nginx/conf.d/nginx_additional.conf с дополнительными настройками для определения переменных:

map $http_user_agent $bad_bot {
    default 0;
    ~*^Lynx 0; # Let Lynx go through
    libwww-perl                      1;
    ~(?i)(httrack|htmlparser|libwww) 1;
}

map $http_referer $bad_referer {
    default 0;
    ~(?i)(adult|babes|click|diamond|forsale|girl|jewelry|love|nudit|organic|poker|porn|poweroversoftware|sex|teen|webcam|zippo|casino|replica) 1;
}

map $request_method $not_allowed_method {
    default 1;
    GET 0;
    HEAD 0;
    POST 0;
}

Перезапускаем Nginx

/etc/init.d/nginx restart

Готово. Мы оптимизировали наш веб-сервер, мы снизили нагрузку на Apache с помощью веб-сервера Nginx, который позволил нам быстро обрабатывать запросы по выдаче пользователям статического контента.
Но еще есть над чем работать, в следующих статьях будем разбираться что еще можно необходимо сделать для веб-сервера.

При настройке связки Nginx и Apache часто возникают ошибки, связанные с неправильным созданием символьных ссылок для виртуальных хостов. Важно убедиться, что конфигурационный файл корректно размещён в каталоге sites-available и правильно подключён через sites-enabled, а команда ln -s выполняется с корректным путём. Даже небольшая опечатка в пути может привести к тому, что Nginx будет отдавать стандартную страницу из /var/www/index.html.

При использовании мультисайтинга Drupal необходимо учитывать, что Nginx не определяет сайты автоматически, как это делает Apache. Все домены мультисайтов должны быть явно перечислены в директиве server_name. После добавления нужных доменов мультисайт начинает работать корректно.

Стоит понимать, что в рассматриваемой конфигурации Nginx в первую очередь снижает нагрузку на Apache за счёт отдачи статических файлов. Если на сайте преобладает динамический контент (Views, Panels, комментарии), заметного прироста производительности без кэширования может не быть. В таких случаях рекомендуется использовать APC, Memcache, а для анонимных пользователей — Boost или более сложные решения вроде Varnish.

Статический контент — это файлы (CSS, JS, изображения), которые Nginx отдаёт напрямую, без запуска PHP. Динамический контент требует выполнения PHP-кода и обращения к базе данных. Поэтому ускорение напрямую зависит от доли статики и настроек кэширования.

При работе с phpMyAdmin в связке Nginx + Apache дополнительной настройки обычно не требуется — достаточно, чтобы запросы к /phpmyadmin корректно проксировались на Apache. Если возникает ошибка 403 Forbidden, необходимо убедиться, что Apache корректно работает сам по себе (например, по порту 8080), и что его DocumentRoot и .htaccess настроены правильно. Перед настройкой Nginx всегда важно убедиться, что Apache функционирует без ошибок.

Отдельное внимание стоит уделить работе с реальными IP-адресами пользователей при использовании proxy_pass. Если Drupal сохраняет в сессиях адрес 127.0.0.1, необходимо включить режим reverse proxy в settings.php и добавить заголовок X-Forwarded-For в конфигурацию Nginx. Именно из этого заголовка Drupal получает реальный IP клиента.

При ошибках доступа к статическим файлам (Permission denied) следует проверять не только права на файлы, но и пользователя, от имени которого работает Nginx. В системах с mod_ruid2 Nginx должен запускаться от того же пользователя, что и Apache, иначе доступ к файлам сайта будет заблокирован. После корректировки пользователя в конфигурации Nginx проблема с доступом к CSS, JS и изображениям устраняется.

В целом настройка связки Nginx + Apache + PHP требует аккуратной пошаговой проверки: сначала корректная работа Apache, затем проксирование через Nginx, после чего — оптимизация и кэширование. Такой подход позволяет избежать большинства типовых ошибок и добиться стабильной и производительной работы Drupal-сайта.

Добавить комментарий

Filtered HTML

  • Допустимые HTML-теги: <a href hreflang> <em> <strong> <cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <pre> <br> <h1> <h2 id> <h3 id>
  • Строки и абзацы переносятся автоматически.
  • Web page addresses and email addresses turn into links automatically.