W tym poradniku skupimy się na poprawnym wystawieniu strony internetowej przez serwer WWW nginx.
1. Aktualizacja systemu
Na początku aktualizujemy listę pakietów oraz zainstalowane oprogramowanie:
apt update
apt upgrade -y
Następnie instalujemy podstawowe narzędzia:
apt install -y curl wget ca-certificates unzip
2. Instalacja nginx
Instalujemy pełną wersję nginx:
apt install -y nginx-full
Po instalacji nginx prawdopodobnie będzie próbował uruchomić się na standardowym porcie 80.
Możemy sprawdzić jego stan:
systemctl status nginx
oraz aktualnie otwarte porty:
ss -lntp
Na tym etapie interesuje nas zmiana konfiguracji nginx tak, aby nie używał portów 80 i 443.
3. Usunięcie domyślnej konfiguracji nginx
Debian domyślnie tworzy konfigurację:
/etc/nginx/sites-available/default
oraz link:
/etc/nginx/sites-enabled/default
Najprościej usunąć aktywny link:
rm -f /etc/nginx/sites-enabled/default
Nie jest konieczne usuwanie samego pliku z sites-available.
4. Instalacja PHP-FPM
Instalujemy PHP wraz z najczęściej używanymi rozszerzeniami:
apt install -y \
php-fpm \
php-cli \
php-curl \
php-gd \
php-mbstring \
php-mysql \
php-xml \
php-zip \
php-intl \
php-bcmath \
php-opcache
Sprawdzamy zainstalowaną wersję PHP:
php -v
Przykładowo na Debianie może pojawić się:
PHP 8.4.x
Możemy również sprawdzić dostępny socket PHP-FPM:
ls -la /run/php/
Przykładowy wynik:
php8.4-fpm.sock
php8.4-fpm.pid
To właśnie socket:
/run/php/php8.4-fpm.sock
będziemy później wykorzystywać w nginx.
W dalszej części poradnika używam PHP 8.4. Jeżeli system posiada inną wersję, należy odpowiednio zmienić nazwę socketu.
5. Utworzenie katalogu strony
Załóżmy, że będziemy obsługiwali domenę:
example.pl
Tworzymy dla niej katalog:
mkdir -p /var/www/example.pl/public
Nadajemy odpowiednie uprawnienia:
chown -R www-data:www-data /var/www/example.pl
Możemy od razu utworzyć prosty plik PHP:
nano /var/www/example.pl/public/index.php
i wpisać:
<?php
phpinfo();
6. nginx na niestandardowym porcie HTTP
Tworzymy konfigurację:
nano /etc/nginx/sites-available/example.pl.conf
Na początek konfigurujemy wyłącznie HTTP:
server {
listen 10080;
listen [::]:10080;
server_name example.pl www.example.pl;
root /var/www/example.pl/public;
index index.php index.html;
access_log /var/log/nginx/example.pl-access.log;
error_log /var/log/nginx/example.pl-error.log;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.4-fpm.sock;
}
location ~ /\.ht {
deny all;
}
}
Najważniejszym elementem jest:
listen 10080;
Zamiast standardowego:
listen 80;
nginx będzie więc nasłuchiwał na porcie 10080.
Aktywujemy konfigurację:
ln -s /etc/nginx/sites-available/example.pl.conf \
/etc/nginx/sites-enabled/example.pl.conf
Sprawdzamy składnię:
nginx -t
Jeżeli otrzymamy:
syntax is ok
test is successful
restartujemy nginx:
systemctl restart nginx
7. Sprawdzenie portu
Sprawdzamy:
ss -lntp | grep nginx
Powinniśmy zobaczyć między innymi:
LISTEN 0 511 0.0.0.0:10080
oraz ewentualnie:
LISTEN 0 511 [::]:10080
Strona będzie dostępna pod adresem:
http://example.pl:10080/
albo bezpośrednio przez IP:
http://PUBLICZNY_ADRES_IP:10080/
jeżeli przekierowanie NAT zostało odpowiednio skonfigurowane.
8. Firewall
Jeżeli na VPS działa ufw, należy zezwolić na nowe porty:
ufw allow 10080/tcp
ufw allow 10443/tcp
Możemy sprawdzić reguły:
ufw status
Jeżeli firewall obsługiwany jest przez nftables, odpowiednie porty również muszą być przepuszczone.
Przykładowo:
nft add rule inet filter input tcp dport 10080 accept
nft add rule inet filter input tcp dport 10443 accept
Należy przy tym pamiętać, że ręcznie dodane w ten sposób reguły mogą nie przetrwać restartu systemu. W środowisku produkcyjnym powinny znaleźć się w trwałej konfiguracji nftables.
9. Konfiguracja HTTPS na porcie 10443
Zakładając, że posiadamy już certyfikat:
/etc/ssl/example.pl/fullchain.pem
/etc/ssl/example.pl/privkey.pem
możemy rozszerzyć konfigurację nginx.
Edytujemy:
nano /etc/nginx/sites-available/example.pl.conf
Konfiguracja może wyglądać następująco:
server {
listen 10080;
listen [::]:10080;
server_name example.pl www.example.pl;
return 301 https://$host:10443$request_uri;
}
server {
listen 10443 ssl;
listen [::]:10443 ssl;
server_name example.pl www.example.pl;
root /var/www/example.pl/public;
index index.php index.html;
ssl_certificate /etc/ssl/example.pl/fullchain.pem;
ssl_certificate_key /etc/ssl/example.pl/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
access_log /var/log/nginx/example.pl-access.log;
error_log /var/log/nginx/example.pl-error.log;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.4-fpm.sock;
}
location ~ /\.ht {
deny all;
}
}
Sprawdzamy konfigurację:
nginx -t
i przeładowujemy nginx:
systemctl reload nginx
Strona HTTPS będzie dostępna jako:
https://example.pl:10443/
10. Przekierowanie HTTP → HTTPS
W przypadku niestandardowych portów trzeba pamiętać o jednym ważnym szczególe.
Typowa konfiguracja nginx zawiera:
return 301 https://$host$request_uri;
W naszym przypadku byłoby to jednak błędne.
Przeglądarka zinterpretowałaby:
https://example.pl/
jako połączenie na standardowy port:
443
Dlatego przy publicznym HTTPS działającym rzeczywiście na 10443 należy używać:
return 301 https://$host:10443$request_uri;
Dzięki temu:
http://example.pl:10080/test
zostanie przekierowane na:
https://example.pl:10443/test
11. Kiedy NIE dodawać :10443 do przekierowania
Istnieje jednak drugi scenariusz.
Załóżmy, że NAT wygląda tak:
PUBLIC_IP:80 -> VPS:10080
PUBLIC_IP:443 -> VPS:10443
Z punktu widzenia użytkownika strona działa wtedy normalnie:
https://example.pl/
Mimo że nginx wewnątrz VPS nasłuchuje na:
10443
W takim przypadku przekierowanie powinno być standardowe:
return 301 https://$host$request_uri;
a nie:
return 301 https://$host:10443$request_uri;
Trzeba więc rozróżnić port nginx na VPS od portu widocznego z Internetu.
12. PHP-FPM
nginx nie wykonuje kodu PHP samodzielnie.
Po otrzymaniu zapytania do:
index.php
przekazuje je do PHP-FPM poprzez:
/run/php/php8.4-fpm.sock
Możemy sprawdzić stan PHP-FPM:
systemctl status php8.4-fpm
oraz uruchomić usługę automatycznie przy starcie:
systemctl enable php8.4-fpm
Analogicznie dla nginx:
systemctl enable nginx
13. Test PHP
Tworzymy:
nano /var/www/example.pl/public/test.php
z zawartością:
<?php
echo 'PHP działa poprawnie.<br>';
echo 'Wersja PHP: ' . PHP_VERSION;
Następnie otwieramy:
http://example.pl:10080/test.php
lub:
https://example.pl:10443/test.php
Powinniśmy otrzymać informację o działającym PHP.
Po wykonaniu testów plik można usunąć:
rm /var/www/example.pl/public/test.php
Szczególnie nie należy pozostawiać publicznie dostępnego:
phpinfo();
na serwerze produkcyjnym.
14. Testowanie nginx z poziomu VPS
Jeżeli DNS nie jest jeszcze skonfigurowany, możemy sprawdzić nginx lokalnie.
HTTP:
curl -I \
-H 'Host: example.pl' \
http://127.0.0.1:10080/
HTTPS:
curl -kI \
-H 'Host: example.pl' \
https://127.0.0.1:10443/
Możemy także przetestować stronę przez publiczny adres:
curl -I http://PUBLIC_IP:10080/
Jeżeli nginx działa lokalnie, ale nie działa przez publiczny adres IP, problem najprawdopodobniej znajduje się po stronie:
- DNAT,
- FORWARD,
- firewalla hosta,
- firewalla VPS,
- albo routingu.
15. Sprawdzanie logów
Najważniejszym źródłem informacji podczas diagnostyki są logi nginx.
Dla naszej domeny:
tail -f /var/log/nginx/example.pl-access.log
oraz:
tail -f /var/log/nginx/example.pl-error.log
Log samej usługi nginx:
journalctl -u nginx -f
PHP-FPM:
journalctl -u php8.4-fpm -f
16. Podstawowe zabezpieczenia nginx
Możemy nieco poprawić domyślną konfigurację.
Edytujemy:
nano /etc/nginx/nginx.conf
Można między innymi wyłączyć prezentowanie wersji nginx:
server_tokens off;
W sekcji http warto również ustawić rozsądne limity:
client_max_body_size 64M;
Po każdej zmianie:
nginx -t && systemctl reload nginx
17. PHP — podstawowa konfiguracja
Konfigurację PHP-FPM znajdziemy przykładowo w:
/etc/php/8.4/fpm/php.ini
Możemy dostosować między innymi:
memory_limit = 256M
upload_max_filesize = 64M
post_max_size = 64M
max_execution_time = 60
Po zmianach restartujemy PHP-FPM:
systemctl restart php8.4-fpm
18. Przykładowa kompletna konfiguracja nginx
Docelowy plik:
/etc/nginx/sites-available/example.pl.conf
może wyglądać następująco:
server {
listen 10080;
listen [::]:10080;
server_name example.pl www.example.pl;
return 301 https://$host:10443$request_uri;
}
server {
listen 10443 ssl;
listen [::]:10443 ssl;
server_name example.pl www.example.pl;
root /var/www/example.pl/public;
index index.php index.html;
ssl_certificate /etc/ssl/example.pl/fullchain.pem;
ssl_certificate_key /etc/ssl/example.pl/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
access_log /var/log/nginx/example.pl-access.log;
error_log /var/log/nginx/example.pl-error.log;
client_max_body_size 64M;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
try_files $uri =404;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_pass unix:/run/php/php8.4-fpm.sock;
fastcgi_index index.php;
}
location ~ /\.(?!well-known).* {
deny all;
}
}
Aktywujemy stronę:
ln -s /etc/nginx/sites-available/example.pl.conf \
/etc/nginx/sites-enabled/example.pl.conf
a następnie:
nginx -t && systemctl reload nginx