Настройка nginx для хостинга

В последнее время замечаю большой интерес к nginx, и организации веб-сервера на его основе.
UP 20.11.2011
Если раньше строили двухзвенную систему (фронтэнд – Nginx, бекэнд – Apache), то сейчас постепенно переходят только на Nginx, полностью отказываясь от Apache. Для таких случаев можно использовать следующий конфиг:

# PHP-FPM (backend)
upstream php-fpm {
	server 127.0.0.1:9000;
}

# Сервера кэширования
upstream memcaches {
	server 127.0.0.1:11211;
}

# Конфиг Nginx (frontend)
server {

  # Защита от бага http://forum.nginx.org/read.php?2,154025,154036
   server_name_in_redirect off;

  # Порт, принимаемые HOST и путь к сайту
  listen 80;
  server_name   site1.ru
		*.site1.ru
		site2.ru
		*.site2.ru;

  set $www_folder '/home/webuser';
  set $root_path '$www_folder/$host/html';
  root $root_path;
  index index.htm index.html index.php;

  # Запросы непосредственно .php-файлов, например index.php (не кэшируются)
  location ~ \.php$ {
	include /etc/nginx/fastcgi_params;
	fastcgi_param SCRIPT_FILENAME $root_path/$fastcgi_script_name;
	fastcgi_param DOCUMENT_ROOT $root_path; # этот параметр нужен несмотря на root в секции server
        fastcgi_pass php-fpm;
  }
  # Копия предыдущего для internal переадресации
  location @phpscripts {
	include /etc/nginx/fastcgi_params;
	fastcgi_param SCRIPT_FILENAME $root_path/$fastcgi_script_name;
	fastcgi_param DOCUMENT_ROOT $root_path; # этот параметр нужен несмотря на root в секции server
        fastcgi_pass php-fpm;
  }

 # Запросы отдельных php-файлов (кэшируются)
 location /utils {
 default_type text/html;
 root  $root_path;
 set             $memcached_key   'nginx_$host$uri?$args';
 memcached_pass  memcaches;
 error_page      404 502 504 405 = @phpscripts;
 }

 # Остальные запросы также идут на PHP-FPM, если $uri не существует (через memcache)
  location / {
     default_type text/html;
     root  $root_path;

     if (!-e $request_filename) {
        return 404;
     }

     error_page      404 502 504 403 405 = @php;
  }

  # Веб-приложение
  location @php {
	include /etc/nginx/fastcgi_params;
	fastcgi_param SCRIPT_FILENAME $root_path/index.php;
        fastcgi_pass php-fpm;
  }

  # Переопеределение 502 ошибки
  error_page	502 = /502.htm;
  location = /502.htm {
         root  $www_folder;
  }  

  # Для js, css, swf, ico и т.д.
  location ~* \.(css|js|swf|ico|png|jpg|gif|jpeg)$ {
	root  $root_path;
	access_log   off;
        expires      30d;
  }

  # Защита от просмотра .htaccess и .htpasswd файлов
  location ~ /\.ht {
	deny  all;
  }

  # Защита от просмотра svn-файлов
  location ~ /.svn/ {
 	deny all;
  } 

  # Статус запросы (/status) и пинг(/ping) запросы от системы мониторинга
  location ~ ^/(status|ping)$ {
      include fastcgi_params;
      fastcgi_pass 127.0.0.1:9000;
      fastcgi_param SCRIPT_FILENAME $fastcgi_script_name;
      allow 127.0.0.1;
      deny all;
  }
}

Если будут вопросы, пишите в комментах.

16 Comments

  1. Не подскажите как обьяснить nginx-у что .jpeg = .JPEG?
    Меня вот этот кусочек интересует:
    # Для js, css, swf, ico и т.д.
    location ~* \.(css|js|swf|ico|png|jpg|gif|jpeg)$ {
    root $root_path;
    access_log off;
    expires 30d;
    }

    1. Анатолий, есть спец. символы в регулярках:

      pattern matching with regular expressions using the symbols ~* and ~:
      * ~ is case-sensitive match
      * ~* specifies a case-insensitive match (firefox matches FireFox)

      См. http://wiki.nginx.org/HttpRewriteModule

  2. Здравствуйте, а зачем писать location @phpscripts, разве где то это используется в коде?

    1. Пардоньте, забыл одну секцию. См. /utls в коняиге. Это нужно для запросов вне веб-приложения.

  3. Добрый день. У меня с данным конфигом проблема.

    nginx |nginx: [warn] server name “/var/www” has suspicious symbols in /etc/nginx/vhosts.d/test1:18

    nginx: [emerg] no port in upstream “memcaches” in /etc/nginx/vhosts.d/test1:66

    что мне подправить, что бы довести до работоспособности его?

    1. Для этого надо добавить кусок в начало файла (в статье тоже обновил):

      # Сервера кэширования
      upstream memcaches {
      server 127.0.0.1:11211;
      }

      И прописать нормальный server_name, например такой:

      server_name mydomain.ru;

      Хотя вообще странно, что он так ругается. У меня с масками нормально работает.

  4. Предлагаю вынести директивы upstream php-fpm и upstream memcaches в /etc/nginx/nginx.conf в директиву html, это даст нам возможность указывать директивы в одном глобальном месте и для всех сайтов + не будет ошибки о дублировании upstream есть вы создаете несколько файлов в /etc/nginx/sites-available.

    1. Согласен. У меня обычно один файл в /etc/nginx/sites-available для всех сайтов, поэтому такой ошибки не возникает. Однако если их много, то да – лучше вынести в общий конфиг.

  5. А вы не подскажите? Есть сайт в локалке недавно перенес на nginx 1.0.5 ,на сайте контент фильмы и т.д отдача по http вот кусок php скрипта :

    if(isset($_SERVER[‘HTTP_USER_AGENT’]) and strpos($_SERVER[‘HTTP_USER_AGENT’],’MSIE’))
    Header(‘Content-Type: application/force-download’);
    else
    */
    Header(‘Content-Type: application/octet-stream’);
    header(‘Accept-ranges: bytes’);
    header(‘Content-Length: ‘.$f_size);
    header(“Content-disposition: attachment; filename=\”$fname\””);
    $dwnld=$bd->QUERY(“insert cont_stat set stat_obj=?, stat_objtype=?, stat_date=?, stat_act=?, stat_ip=?”,$file[‘owner’],$tp,time(),’download_start’,$_SERVER[‘REMOTE_ADDR’]);
    $handle = @fopen($file[‘link’], “rb”);
    fpassthru($handle);
    fclose($handle);
    $bd->QUERY(“update cont_stat set stat_date=?, stat_act=? where stat_id=?”,time(),’download_complete’,$dwnld);
    switch($type){
    case ‘flm’:
    $bd->QUERY(“update cont_films set film_rait=film_rait+1, film_lastdate=? where film_id=?”,time(),$file[‘owner’]);
    break;
    case ‘prg’:
    $bd->QUERY(“update cont_progs set prog_rait=prog_rait+1, prog_lastdate=? where prog_id=?”,time(),$file[‘owner’]);
    break;
    case ‘mus’:
    $bd->QUERY(“update cont_mus set mus_rait=mus_rait+1, mus_lastdate=? where mus_id=?”,time(),$file[‘owner’]);
    break;
    case ‘gam’:
    $bd->QUERY(“update cont_games set gam_rait=gam_rait+1, gam_lastdate=? where gam_id=?”,time(),$file[‘owner’]);
    break;
    }
    }
    else header(“Location: error-norights”);
    }
    else header(“Location: error-nofile”);
    ****************************************************************************************************************
    возможно ли кэшировать контент на ssd диск ?
    уже бьюсь месяц и не пойму как это реализовать рабочий конфиг сервера получился вот такой:
    ***********************************************************************************************************************
    server {
    listen 80;
    server_name localhost;

    root /home/ariadna/www;
    index index.php;
    client_max_body_size 100M;
    client_body_buffer_size 128k;

    location /nginx_status {
    stub_status on;
    access_log off;
    allow 127.0.0.1;
    deny all;
    }
    location /phpmyadmin {
    alias /usr/share/phpmyadmin;
    index index.html index.htm index.php;
    break;
    }
    location /www {
    alias /var/cache/munin/www;
    index index.php index.html index.htm;
    break;
    }

    location /admin {
    rewrite ^/admin~ /index.php?page=admin? last;
    }

    location / {
    rewrite ^/down~(.*)-(.*)$ /download.php?type=$1&id=$2? last;
    rewrite ^/error-(.*)$ /index.php?page=Error&id=$1? last;
    rewrite ^/film-(.*)$ /index.php?page=film&id=$1 last;
    rewrite ^/gallery-(.*)$ /index.php?page=gal&id=$1? last;
    rewrite ^/Kino~j(.*)-(.*)$ /index.php?page=Kino&janr=$1&id=$2? last;
    rewrite ^/Kino~n(.*)-(.*)$ /index.php?page=Kino&name=$1&id=$2? last;
    rewrite ^/prog-(.*)$ /index.php?page=prog&id=$1? last;
    rewrite ^/progs~j(.*)-(.*)$ /index.php?page=progs&janr=$1&id=$2? last;
    rewrite ^/progs~n(.*)-(.*)$ /index.php?page=progs&name=$1&id=$2? last;
    rewrite ^/music-(.*)$ /index.php?page=music&id=$1? last;
    rewrite ^/musics~j(.*)-(.*)$ /index.php?page=musics&janr=$1&id=$2? last;
    rewrite ^/musics~n(.*)-(.*)$ /index.php?page=musics&name=$1&id=$2? last;
    rewrite ^/game-(.*)$ /index.php?page=game&id=$1? last;
    rewrite ^/games~j(.*)-(.*)$ /index.php?page=games&janr=$1&id=$2? last;
    rewrite ^/games~n(.*)-(.*)$ /index.php?page=games&name=$1&id=$2? last;
    rewrite ^/top-(.*)$ /index.php?page=top&type=$1? last;
    rewrite ^/(.*)-(.*)$ /index.php?page=$1&id=$2? last;
    rewrite ^/([A-Za-z0-9\_\-]+)$ /index.php?page=$1? last;
    }
    error_page 404 403 500 /404.php;

    location ~ \.php$ {
    #fastcgi_pass 127.0.0.1:9000;
    fastcgi_pass unix:/tmp/php5-fpm.sock;
    fastcgi_index index.php;
    #fastcgi_cache_path /ssd/data/fastcgi_temp 1 2;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;
    fastcgi_intercept_errors on;
    fastcgi_ignore_client_abort off;
    fastcgi_connect_timeout 360;
    fastcgi_send_timeout 180;
    fastcgi_read_timeout 180;
    fastcgi_buffer_size 128k;
    fastcgi_buffers 32 256k;
    fastcgi_busy_buffers_size 512k;
    fastcgi_temp_file_write_size 512k;
    fastcgi_max_temp_file_size 0;
    }

    location ~ /\.ht {
    deny all;
    }
    }

    ****************************************************************************************************************
    Буду очень благодарен за помощь или хотя бы пример !!

    1. Привет!
      Конечно можно это организовать. Для этого надо сделать две вещи.
      Первая, чтобы php создавал кэш. Вторая, чтобы nginx проверял существование кэша и, если он есть – отдавал.
      Это делается вот таким условием: if (!-e $request_filename) {
      SSD подключаете, как обычный локейшен.

  6. Что у меня ваш пример не запустился.
    Подскажите если nginx дублирует get параметры в урле что может быть?

    1. Посмотрите по логам, в чём дело. А запрос то какой?

  7. Здравствуйте. Можете помочь с проблемой?
    Подключаю php традиционным скриптом
    location ~ \.php$ {
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME /private/var/www/$fastcgi_script_name;
    include fastcgi_params;
    }

    И делаю реврайт такой
    location / {
    if (!-e $request_filename){
    rewrite ^(.*)$ /?modRewrite=$1 break;
    }
    }

    То например /catalog работает (перенаправляет на /index.php?modRewrite=catalog), а вот /catalog.php не работает – отдает 404
    Я думал он будет отправлять на /index.php?modRewrite=catalog.php
    В лог пишет такую ошибку
    *14 FastCGI sent in stderr: “Primary script unknown” while reading response header from upstream, client: 127.0.0.1, server: zf.dev, request: “GET /catalog.php HTTP/1.1”, upstream: “fastcgi://127.0.0.1:9000”, host: “localhost”

    Можете подсказать в чем затык? 🙁

    1. Возможно, у вас затык в том, что файл catalog.php существует, и упавление идёт на вторую ветку (которой у вас нет).

      location / {
      if (!-e $request_filename){
      rewrite ^(.*)$ /?modRewrite=$1 break;
      } else {
      // сюда
      }
      }

Leave a Comment