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.
poldek:/all-avail> install nginx-light
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:
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:
Sekcja server:
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;
...
}
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]).
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;
...
}
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 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 <fcgi_stdio.h>
na:
#include <fastcgi/fcgi_stdio.h>
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;
}
}
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 "<?php echo \"dupa\"; " | php
czekam aż ktoś kopnie nowszą wersję perla do repo wtedy dokończe z wraperem perla.
W konfiguracji Nginx'a danego vhosta musimy mieć zapis:
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]: <h1>Nginx Connections</h1> # 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]: <h1>Nginx Requests</h1>
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";
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;
}
}