===== Wstęp =====
Ostatnio przeszedłem z Apache na Nginx'a i postanowiłem napisać małe "how to" jak to wykonać - może komuś się przyda. Czemu się zdecydowałem na Nginx'a? Apache zajmuje dużo pamięci oraz jest mniej wydajny.
===== Instalacja =====
poldek:/all-avail> install nginx-light
===== Konfiguracja =====
Opis pliku konfiguracji **/etc/nginx/nginx-light.conf** (opisuje to co możemy zmieniać):
user nginx nginx;
worker_processes 5;
error_log /var/log/nginx/nginx-light_error.log;
pid /var/run/nginx-light.pid;
Kolejno:
* pierwsza linia definiuje na jakim użytkowniku ma być uruchomiona usługa,
* worker_process - ile ma być uruchomionych wątków Nginx'a,
* error_log definiuje plik, gdzie będą zapisywane błędy,
* pid - gdzie ma być zapisywany process ID - nie zmieniamy.
events {
worker_connections 2048;
use epoll;
}
Worker_connections - ilość requestów na wątek.
http {
include /etc/nginx/mime.types;
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 /var/log/nginx/nginx-light_access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
server_names_hash_bucket_size 128;
types_hash_max_size 2048;
types_hash_bucket_size 64;
#keepalive_timeout 0;
keepalive_timeout 65;
limit_zone test-limit $binary_remote_addr 10m;
#gzip on;
server {
listen 80;
server_name localhost;
access_log /var/log/nginx/nginx-light_access.log main;
client_max_body_size 10M;
location / {
autoindex on;
root /home/services/nginx/html;
index index.html index.htm index.php;
limit_conn test-limit 15;
}
# location /nginx_status {
# stub_status on;
# access_log off;
# allow 127.0.0.1;
# deny all;
# }
# error_page 404 /404.html;
# error_page 500 502 503 504 /50x.html;
# location = /50x.html {
# root /home/services/http/error-pages;
# }
# location = /404.html {
# root /home/services/http/error-pages;
# }
# location ~ \.php$ {
# include /etc/nginx/fastcgi.params;
# fastcgi_pass 127.0.0.1:1026;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /home/services/nginx/html$fastcgi_script_name;
# }
}
}
Sekcja http:
* log_format - definiujemy jak ma wyglądać wpis w logach - listę zmiennych znajdziemy tu: http://wiki.nginx.org/HttpCoreModule#Variables,
* access_log - plik gdzie zapisujemy logi,
* gzip - kompresja (opis niżej),
Sekcja server:
* listen - na jakim porcie ma nasłuchiwać vhost, pierwszy vhost jest domyslnym vhostem, możliwe kombinacje co do portu i adres IP to: listen IP:port; gdzie * = 0.0.0.0 (np *:80),
* server_name - definiujemy vhost'a, a po spacji definiujemy aliasy, aczkolwiek przy domyślnym vhoście nie ma to znaczenia,
* location / - tu ustawiamy opcje dotyczącego katalogu root w vhoście,
* autoindex - on włącza tworzenie się autoindeksów,
* root - definiowania katalogu root dla danego vhost'a,
* index - tu definiujemy domyslne pliki, które będą otwierane po wejściu do katalogu,
* location /nginx_status - włącza status Nginx'a pod danym virtualnym katalogiem vhost'a - przydatne do statystyk (opis niżej),
* error_page - definiowanie plików w przypadku błędów - 404, 500, itp,
* location ~ \.php$ - definiowanie obsługi plików PHP przez demona FastCGI (opis niżej).
Wszelkie zmiany powinny zostać przetestowane składniowo przez Nginx'a, służy to tego komenda:
$ nginx-light -t
i powinna ona zwrócic coś takiego:
$ the configuration file /etc/nginx/nginx-light.conf syntax is ok
$ configuration file /etc/nginx/nginx-light.conf test is successful
w przypadku błędu pojawi się informacja gdzie jest błąd.
Logi z błędami w krótkim czasie robią się bardzo duże - to głównie za sprawą różnego rodzaju botów. Przydatną opcją jest wyłączenie logownia próby pobrania plików/katalogów których nie ma na serwerze, a ślady w logach są. Wyłączyć możemy za pomocą przydatnej opcji:
http {
...
log_not_found off;
...
}
==== IPv6 ====
Najpierw trzeba sprawdzić czy Nginx został skompilowany z opcją --with-ipv6. Aby to sprawdzić wykonajmy:
$ nginx-light -V
Jeśli Nginx obsługuje IPv6 to w sekcji serwer danego vhosta modyfikujemy listen:
listen [::]:80;
taki wpis oznacza, że serwer nasłuchuje na IPv4 oraz IPv6, jeśli chcemy, aby tylko i wyłącznie nasłuchiwał na IPv6 ustawiamy:
listen [::]:80 ipv6only=on;
zamiast [::] możemy podać adres (np: [ffff:a:b:c::01]).
==== SSL ====
Tworzymy certyfikaty SSL. Aby to zrobić trzeba zainstalować narzędzia Openssl'a:
$ install openssl-tools
Generowanie certyfikatów:
$ openssl genrsa -out /etc/nginx/server.key 1024
$ openssl req -new -x509 -days 365 -key /etc/nginx/server.key -out /etc/nginx/server.crt
$ chmod 600 /etc/nginx/server.*
Do sekcji http dopisujemy:
ssl_certificate server.crt;
ssl_certificate_key server.key;
w sekcji **server** głównego vhosta wpisujemy:
listen 443 default_server ssl;
w przypadku IPv6:
listen [::]:443 default_server ssl;
w kolejnych vhostach wystarczy wpisać:
listen 443;
Oczywiście każdy vhost może mieć osobny certyfikat, np:
server {
...
listen 443;
ssl_certificate server1.crt;
ssl_certificate_key server1.key;
...
}
...
server {
...
listen 443;
ssl_certificate server2.crt;
ssl_certificate_key server2.key;
...
}
==== Vhosty ====
Domyślnie działa nam główny vhost - czyli domyślny. Aby utworzyć kolejnego trzeba dodać do konfiguracji kolejną sekcje **server** w sekcji **http**. Aby mieć porządek w pliku konfiguracji polecam dodanie na końcu sekcji **http** (przed **}**) opcji:
include /etc/nginx/vhosts.d/*.conf;
która będzie dodawała konfiguracje z plików (z rozszerzeniem **conf**) z katalogu **/etc/nginx/vhosts.d/**. Tego katalogu nie ma więc musimy go stworzyć:
$ mkdir /etc/nginx/vhosts.d/
$ chmod 700 /etc/nginx/vhosts.d/
Przykładowy konfig vhosta:
server {
listen [::]:80;
server_name nasz.vhost.ltd;
access_log /home/users/kamil/www/nasz.vhost.ltd/access.log main;
error_log /home/users/kamil/www/nasz.vhost.ltd/error.log error;
location / {
autoindex on;
root /home/users/kamil/www/nasz.vhost.ltd/htdocs;
index index.html index.htm;
}
}
Z czasem on się zmieni w zależności co będziemy chcieli osiągnąć w danym vhoście.
==== CGI ====
CGI będzie nam potrzebne, aby uruchomić np Mailman'a. Ale żeby to zrobić musimy sobie skompilować program do obsługi CGI. A więc zatem instalujemy kompilator:
poldek:/all-avail> install gcc gcc-c++ gcc-objc++ gcc-objc libstdc++- libstdc++-devel git-core autoconf automake fcgi fcgi-devel
Ściągamy i kompilujemy **FcgiWrap**:
$ mkdir ~/install
$ cd ~/install
$ git clone git://github.com/gnosek/fcgiwrap.git
$ cd fcgiwrap
$ ./configure
$ make
Jeśli podczas make będziecie mieć taki błąd:
fcgiwrap.c:30:24: fatal error: fcgi_stdio.h: No such file or directory
edytujemy plik **fcgiwrap.c** i zmieniamy w nim **linię nr 30** z:
#include
na:
#include
Po skompilowaniu kopiujemy binarkę do **/usr/local/bin/**
$ cp ~/install/fcgiwrap/fcgiwrap /usr/local/bin/
Tworzymy plik **/etc/init.d/fcgiwrap** i zapisujemy w nim:
#!/usr/bin/perl
use strict;
use warnings FATAL => qw( all );
use IO::Socket::UNIX;
my $bin_path = '/usr/local/bin/fcgiwrap';
my $socket_path = $ARGV[0] || '/tmp/cgi.sock';
my $num_children = $ARGV[1] || 1;
close STDIN;
unlink $socket_path;
my $socket = IO::Socket::UNIX->new(
Local => $socket_path,
Listen => 100,
);
die "Cannot create socket at $socket_path: $!\n" unless $socket;
for (1 .. $num_children) {
my $pid = fork;
die "Cannot fork: $!" unless defined $pid;
next if $pid;
exec $bin_path;
die "Failed to exec $bin_path: $!\n";
}
Nadajemy odpowiednie uprawnienia:
$ chmod 750 /etc/init.d/fcgiwrap
$ chown root:nginx /etc/init.d/fcgiwrap
Uruchamiamy:
$ sudo -u nginx /etc/init.d/fcgiwrap
$ chmod 770 /tmp/cgi.sock
Dodpisujemy na koniec pliku **/etc/rc.d/rc.local** dwa powyższe polecenia.
Przykładowa konfiguracja vhosta Mailmana:
server {
listen [::]:80;
listen [::]:443;
server_name mailman.host.ltd lists.host.ltd;
access_log /var/log/httpd/mailman.orchia.pl_access.log main;
error_log /var/log/httpd/mailman.orchia.pl_error.log error;
root /usr/lib/mailman/cgi-bin;
location = / {
rewrite ^ /mailman/listinfo permanent;
}
location / {
rewrite ^ /mailman$uri;
}
location ~ ^/mailman(/[^/]*)(/.*)?$ {
fastcgi_split_path_info (^/mailman/[^/]*)(.*)$;
include fastcgi.params;
fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SCRIPT_FILENAME $document_root$1;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $document_root$2;
fastcgi_pass unix:/tmp/cgi.sock;
}
location /icons {
alias /usr/lib/mailman/icons;
}
location /mailman/pipermail {
alias /var/lib/mailman/archives/public;
autoindex on;
}
}
==== PHP ====
Instalujemy PHP'a:
poldek:/all-avail> install php-common php-cgi php-cli php-fpm
Ustawiamy zmienne w pliku **/etc/php/php-fpm.conf**
pid = run/php/fpm.pid
daemonize = yes
listen = 127.0.0.1:9000
listen.allowed_clients = 127.0.0.1
user = nginx
group = nginx
pm = dynamic
pm.min_spare_servers = 5
pm.max_spare_servers = 35
Tworzymy strukturę katalogów pod vhosta:
$ mkdir -p /home/users/user/www/moj.vhost.ltd/htdocs
$ mkdir -p /home/users/user/www/moj.vhost.ltd/tmp
$ chmod -R 750 /home/users/user/www/moj.vhost.ltd/htdocs
$ chmod -R 770 /home/users/user/www/moj.vhost.ltd/tmp
$ chown -R user:http /home/users/user/www/moj.vhost.ltd
Tworzymy plik **/etc/nginx/vhosts.d/moj.vhost.ltd** i zapisujemy w nim konfigurację:
server {
listen [::]:80;
server_name cp.kamilm.net;
access_log /home/users/user/www/moj.vhost.ltd/access.log main;
error_log /home/users/user/www/moj.vhost.ltd/error.log error;
location / {
root /home/users/user/www/moj.vhost.ltd/htdocs;
index index.html index.htm index.php;
}
location ~ \.php$ {
include /etc/nginx/fastcgi/moj.vhost.ltd.param;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /home/users/user/www/moj.vhost.ltd/htdocs$fastcgi_script_name;
}
}
Tworzymy katalog na konfigurację paramterów PHP'a dla vhostów:
$ mkdir /etc/nginx/fastcgi
$ chmod 700 /etc/nginx/fastcgi
Tworzymy plik **/etc/nginx/fastcgi/moj.vhost.ltd.param** i zapisujemy w nim:
fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param DOCUMENT_URI $document_uri;
fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param SERVER_PROTOCOL $server_protocol;
fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SERVER_SOFTWARE nginx/$nginx_version;
fastcgi_param REMOTE_ADDR $remote_addr;
fastcgi_param REMOTE_PORT $remote_port;
fastcgi_param SERVER_ADDR $server_addr;
fastcgi_param SERVER_PORT $server_port;
fastcgi_param SERVER_NAME $server_name;
# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param REDIRECT_STATUS 200;
fastcgi_param PHP_VALUE "open_basedir=/home/users/user/www/moj.vhost.ltd/htdocs:/home/users/user/www/moj.vhost.ltd/tmp:/usr/share/php/:/usr/share/pear/
upload_tmp_dir=/home/users/user/www/moj.vhost.ltd/tmp
session.save_path=/home/users/user/www/moj.vhost.ltd/tmp
sendmail_path='/usr/sbin/sendmail -f user -t -i'";
Robimy reload Nginx'a:
$ /etc/init.d/nginx-light reload
Gdy normalne strony działają, a w PHP nie chcą - pisze np: **Bad Gateway** to najpierw sprawdźmy czy konfiguracja PHP'a jest dobra. Sprawdzić możemy prostym przykładem:
$ echo "
location /nginx_status {
stub_status on;
access_log off;
allow 127.0.0.1;
deny all;
}
Czasem bywa tak, że danego vhosta możemy odpytywać nie z localhost'a tylko z wew/zew IP - należy go dopisać do **allow**. Wystarczy przeładować Nginx'a i możemy się odwoływać do http://vhost.ltd/nginx_status - gdy to zadziała możemy pobierać dane i wciągać je do naszego systemu statystyk. Np w MRTG:
Tworzymy plik nginx_vhost.ltd.conf:
#
# Nginx stat
#
# connections
WorkDir: /home/users/vftp/www/stats.sun.orchia.pl/htdocs
Target[nginx_con]: `/etc/mrtg/conf.d/mrtg-nginx con`
Options[nginx_con]: growright, integer, nobanner, nopercent, transparent
Title[nginx_con]: Nginx Connections
MaxBytes[nginx_con]: 2048
YLegend[nginx_con]: Connections
ShortLegend[nginx_con]: con
LegendI[nginx_con]:
LegendO[nginx_con]: con:
Legend1[nginx_con]: Connections
Legend2[nginx_con]: Connections
PageTop[nginx_con]: Nginx Connections
# requests
Target[nginx_req]: `/etc/mrtg/conf.d/mrtg-nginx req`
Options[nginx_req]: gauge, growright, nobanner, nopercent, transparent
Title[nginx_req]: Nginx Requests
MaxBytes[nginx_req]: 2048
YLegend[nginx_req]: request/s
ShortLegend[nginx_req]: req/s
Legend1[nginx_req]: Requests per Second
Legend2[nginx_req]: Requests per Second
LegendI[nginx_req]:
LegendO[nginx_req]: Requests:
PageTop[nginx_req]: Nginx Requests
Do pliku **/etc/mrtg/conf.d/mrtg-nginx** zapisujemy:
#!/usr/bin/perl
# $Revision: 2 $
# $Date: 2008-09-12 15:11:40 +0300 (Fri, 12 Sep 2008) $
my %opt = (
# http link to nginx stub_status, be sure turn on stub_status in nginx conf
nginx_status => 'http://localhost:80/nginx_status',
# path for program what may dump web page, normaly lynx -dump
# lynx => 'lynx -dump',
lynx => 'wget -q -Y off -O -',
);
$opt{var} = $ARGV[0] if $ARGV[0];
$opt{nginx_status} = $ARGV[1] if $ARGV[1] and $ARGV[1]=~/^http:\/\/\w+/;
$opt{var} ||= '';
my $do = `$opt{lynx} $opt{nginx_status}`;
if ($opt{var} eq 'req') {
$do=~/^Active connections:\s*(\d+)\s*$/ms or warn "Error! Can't find data!\nIN :\n$do";
$opt{d2} = $opt{d1} = $1;
}
elsif ($opt{var} eq 'con') {
$do=~/^\s*(\d+)\s+(\d+)\s+(\d+)\s*$/ms or warn "Error! Can't find data!\nIN :\n$do";
$opt{d2} = $opt{d1} = $3;
}
#elsif { $do=~/^Reading:\s+(\d+).*Writing:\s+(\d+).*Waiting:\s+(\d+)/; }
else {
$opt{var} = 'ERROR';
$opt{d2} = $opt{d1} = 0;
warn "Error! Please read the help and set (req|con)\n";
}
print "$opt{d1}\n";
print "$opt{d2}\n";
#print "$opt{up}\n" if $opt{up};
print "Nginx $opt{var}\n";
===== Inne =====
**HTTP Auth**:
server {
...
location / {
...
auth_basic "Restricted";
auth_basic_user_file /home/users/user/www/moj.vhost.ltd/.htpasswd;
}
}
Plik **/home/users/user/www/moj.vhost.ltd/.htpasswd** możemy wygenerować za pomocą skryptu, który musimy pobrać:
$ wget http://trac.edgewall.org/browser/trunk/contrib/htpasswd.py?format=txt
$ mv ./htpasswd.py?format=txt ./htpasswd.py
$ chmod 755 ./htpasswd.py
Aby plik działał musimy mieć zainstalowany pakier **python-modules**:
poldek:/all-avail> install python-modules
Uruchamiamy wg składni:
$ ./htpasswd.py -c -b /home/users/user/www/moj.vhost.ltd/.htpasswd admin tajne_haslo
**HTTP -> HTTPS**:
server {
...
listen 80;
rewrite ^(.*) https://$server_name$1 permanent;
...
}
server {
...
listen 443;
fastcgi_param HTTPS on;
...
}
**Zend**:
server {
...
location / {
...
if (!-f $request_filename) {
rewrite ^(.*)$ /index.php last;
break;
}
}