Konfiguracja WordPress’a MU na nginx’a

Reguły przekierowań dla WordPress’a MU przy użyciu apache’a są opisane na stronie pomocy: Create A Network: .htaccess and Mod Rewrite. Poniżej widnieją te same reguły ale dla serwera nginx.

if ( $host !~ example\.coml$ ) {
    rewrite ^/wp-content/uploads/(.+) /files/$1;
}
rewrite ^/wp-admin/?$ /wp-admin/index.php last;
rewrite ^/wp-admin/network/?$ /wp-admin/network/index.php last;
rewrite ^/files/(.+) /wp-includes/ms-files.php?file=$1 last;
 
location / {
    try_files $uri /index.php?q=$request_uri&$query_string;
}

Oczywiście „example\.com” należy wymienić na domenę głównego serwisu.

Aktualizacja, ze strony wordpress.org znikły reguły dla apache’a:

#Wordpress Multi site
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
 
# uploaded files
RewriteRule ^files/(.+) wp-includes/ms-files.php?file=$1 [L]
 
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
RewriteRule . index.php [L]
#END WordPress Multi Site

403 dla określonych refererów w nginx

W serwisie klienta jest dużo plików graficznych, które są hotlinkowane. Generalnie klientowi to nie przeszkadza, bo uważa, że sieć jest od tego żeby się dzielić. Jest jedno ale. Jest parę serwisów które mają na tyle dużą oglądalność, że umieszczone tam grafiki pochłaniają po prostu za dużo pasma i należało by je zablokować.

Serwis serwowany jest za pomocą nginx‚a. Samo blokowanie hotlinków jest bardzo proste i w całej sieci można znaleźć mnóstwo przykładów, różniących się warunkiem w location, które sprowadzają się do następującej konfiguracji:

location ~ \.(jpg|png|gif)$ {
valid_referers server_names blocked none frienddomain.com *.frienddomain.com;
if ($invalid_referer) {
return 403;
}
}

W której wpisujemy listę dopuszczonych do hotlinkowania domen, pamiętając o słówku none, które oznacza brak referera.

Ale tak jak pisałem wcześniej, klient chciał zablokować tylko określone domeny, niech to będą foo.ba i bar.fo. Konfiguracja ostatecznie wygląda w taki sposób:

location / {
if ($http_referer ~* "foo.ba|bar.fo" ) {
rewrite .* /foo/ last;
}
[...]
}
location /foo {
return 403;
}

IP użytkownika w tandemie nginx proxy i nginx

Mamy zestaw dwóch serwerów:

  1. nginx – przekazujący ruch do wewnętrznych serwerów (proxy)
  2. nginx – hostujący serwis

Konfiguracja na dla domeny iworks.pl na pierwszym z nich wygląda następująco:

server {
server_name iworks.pl www.iworks.pl;
listen 80;
access_log /var/log/nginx/iworks.pl.access.log;
error_log /var/log/nginx/iworks.pl.error.log;
location / {
proxy_pass ;
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;
}
}

Informacja o prawdziwym IP użytkownika jest przekazywana dalej w linijce: proxy_set_header X-Real-IP $remote_addr;

W celu wykorzystania go na drugim serwerze, tym który hostuje stronę, należy w pliku /etc/nginx/fastcgi_params

Zmienić linijkę
fastcgi_param REMOTE_ADDR $remote_addr;
na
fastcgi_param REMOTE_ADDR $http_x_real_ip;
dzięki czemu na serwerze hostującym adres użytkownika oglądającego stronę będzie „prawdziwy”, zamiast być adresem serwera proxującego.

wordpress i nginx w jednym miejscu stali

Przenoszę serwisy z jednego serwera na drugi i na tym drugim z założenia ma nie być apache’a. na pierwszy ogień poszedł najmniejszy z wordpressów, taki którego można by przenieść nawet ręcznie. Kilka wpisów na krzyż, kilka wtyczek i tworzony wciąż szablon wyglądu.

Na pierwszy ogień przeszła przeprowadzka bazy, więc dump z bazy mysql (systemowa baza serwera) w celu wyciągnięcia danych z tabel db oraz user oraz przerzucenie dwóch rekordów do nowej bazy. Potem CREATE DATABASE nazwa; i import dumpa.

Sama konfiguracja wirtuala to moment, choć sposób wykorzystania php w trybie cgi wymaga własnego wpisu, poszła bez kłopotu.

Do typowej konfiguracji musiałem dodać tylko wpisy dotyczące kodowania i zmienić index katalogu na index.php.

Ponieważ odnośniki są ustawione jako /%postname%/ wymagane jest użycie reguł rewrite’ów, które dla apache’a są tworzone z automatu.

Dla nginx’a wygląda to następująco:

location / {
    root   /ścieżka_do_document_roota;
    if (-e $request_filename) {
        break;
    }
    rewrite ^(.+)$ /index.php?q=$1 last;
}

nginx + ssl

Jakiś czas temu stawiałem wiki, gdzie kolejnym krokiem po tym jak serwis został zablokowany poprzez htaccess było przestawienie całości do pracy z certyfikatem ssl z wykorzystaniem szyfrowania. Konieczność jeżeli mają tam być przechowywane np. hasła rootów.

Certyfikat który podpiąłem jest certyfikatem który sam podpisałem.

generowanie klucza prywatnego

wykonanie następującego polecenia:
openssl genrsa -des3 -out server.key 1024
spowoduje wygenerowanie klucza:
Generating RSA private key, 1024 bit long modulus
.........++++++
..............++++++
e is 65537 (0x10001)
Enter pass phrase for server.key:
Verifying - Enter pass phrase for server.key:

pierwszą wadą tego klucza jest fakt posiadania przez niego hasła, co by oznaczało, że przy każdym restarcie serwera korzystającego z tego klucza, istniała by potrzeba wpisywania tego hasła.

generowanie CSR

Pierwszym elementem prowadzącym do wygenerowania certyfikatu jest wygenerowanie pliku który dopiero potem będzie podpisany przez wcześniej wygenerowany klucz prywatny.

openssl req -new -key server.key -out server.csr

zostaniemy poproszeni o hasło:

Enter pass phrase for server.key:

By potem wypełnić dane:

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]:PL
State or Province Name (full name) [Some-State]:mazowieckie
Locality Name (eg, city) []:Warszawa
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Firma
Organizational Unit Name (eg, section) []:
Common Name (eg, YOUR name) []:
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

utworzenie klucza bez hasła

Aby usunąć „wadę” i posiadać klucz bez hasła należy wykonać:
cp server.key server.key.org
openssl rsa -in server.key.org -out server.key

podpisanie CSR’a

Na sam koniec generowania klucza ssl, musimy go podpisać np na rok:
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
Co daje nam efekt:
Signature ok
subject=/C=PL/ST=mazowieckie/L=Warszawa/O=Firma
Getting Private key

instalacja klucza i certyfikatu

Ponieważ używanym serwerem jest nginx to kopiuję sobie:
cp server.crt /etc/nginx/ssl/cert.pem
cp server.key /etc/nginx/ssl/cert.key
podpinanie do konfiguracji

do konfiguracji dodałem:
listen 443;
ssl on;
ssl_certificate /usr/local/nginx/conf/cert.pem;
ssl_certificate_key /usr/local/nginx/conf/cert.key;

potem restart i śmiga... prawie.

Okazało się że wiki działa dobrze, ale nie grzeje :D. Całość wiki działa dobrze, oprócz niektórych odnośników. Np. "losowa strona" powoduje przejście na port 80. Kluczem jest zmiana konfiguracji w pliku: LocalSettings.php
$wgServer = "https://serwer...";

wiki potrzebna od zaraz

Jak liczba obsługiwanych maszyn zrobi się większa niż jeden (lub dwadzieścia, jak to woli) to warto by było gdzieś zapisać pewne rzeczy związane z działaniem skryptów, konfiguracją usług oraz wielu innych ważnych i mniej ważnych rzeczy. Oczywiście można wszystko trzymać w plikach, a pliki w repozytorium, ale przy osiągnięciu pewnej masy zapisanych informacji zaczynają się trudności w dostępie do zgromadzonej wiedzy, szczególnie, że serwerów i usług raczej przybywa niż ubywa. Wydaje się, że rozwiązaniem jest postawienie wiki. I tak właśnie się stało, choć z przygodami.

Po pierwsze wiki to raczej filozofia budowy strony i trzymania informacji, a nie konkretne rozwiązanie programistyczne, co odkryłem z pewnym zdziwieniem, próbując dobrać taki soft, który spełniałby nasze wymagania. Na początek miało to być perlowe i pracować z postgresem. Korzystając ze strony Wiki Choice Wizard i wyklikując pracowicie poszczególne wymagania w pewnym momencie osiągnąłem grala: na liście pozostał tylko jeden soft o wdzięcznej nazwie mojomojo. Spełniało wszystkie wymagania a dodatkowo najmilsza możliwa licencja: BSD.

Instalacja poszła jak z płatka, problemy zaczęły się po chwili i były związane z założeniami. Na serwerze usługi są rozdzielone pomiędzy chrooty. W tej sprawie interesują nas 2 z nich. Pierwszym chrootem jest chroot zwany głównym webowym, w których działa nginx jako serwer proxujący. Założeniem było również to, że ma proxować urla do serwera działającego w innych chroocie na losowym porcie (bezpieczeństwo), czyli serwis pracujący w domena/wiki znajduje się na innym serwerze. Konfiguracja wygląda następująco:
Czytaj dalej wiki potrzebna od zaraz