Nginx Tuning pod niewielki serwer VPS

Nginx Tuning pod niewielki serwer VPS

12 sierpnia 2021 6 przez gielo

Tuning i test poniższej konfiguracji był przeprowadzany na niewielkim i tanim (około 20zł brutto/m-c) serwerze vps, 1 core, 2GB ram, 20GB ssd, na którym działa oczywiście Nginx, serwer pocztowy, dns, mysql i kilka innych usług przydatnych przy hostowaniu własnej strony internetowej. Na serwerze działa jedna strona oparta o cms WordPress. Sama konfiguracja bazuje na kilku podobnych rozwiązaniach znalezionych kiedyś w sieci. Jest ona na tyle uniwersalna, że z powodzeniem można ją także zastosować dla niewielkiego sklepu internetowego, małego portalu informacyjnego itp.

Konfiguracja nie obejmuje load balancingu, proxy, akceleratora Varnish, a Nginx działa jako jedyny serwer www. Zaletą poniższej konfiguracji jest prostota oraz szybkość jej wdrożenia na naszym serwerze, także co jest nie bez znaczenia dość łatwe jej dostrojenie pod nasz serwer i działającą na nim stronę. Wadą? tak, takie rozwiązanie posiada także kilka wad ale o nich powiem na końcu tego artykułu.

Serwer Nginx zainstalujemy z repozytorium Ondřej Surý, jako że posiada dość przydatny moduł kompresji Brotli, który jest szybszy i mniej obciąża serwer niż Gzip. Same serwery Nginx dostępne są w nowszej wersji niż te dostępne w oficjalnym repozytorium Ubuntu, czy Debiana. Najpierw dodajemy repozytorium. Wybierz jedne z poniższych repozytoriów.

W miarę najnowsza wersja serwera Nginx dla ubuntu. Może być za to mniej stabilna.

$ sudo add-apt-repository ppa:ondrej/nginx-mainline

Starsza ale za to stabilna wersja serwera Nginx dla Ubuntu

$ sudo add-apt-repository ppa:ondrej/nginx

oraz Instalacja serwera Nginx

$ sudo apt update
$ sudo apt install nginx

Uruchomienie SWAP

Kolejnym krokiem będzie uruchomienie pliku wymiany SWAP, jeśli go jeszcze nie posiadasz. O tym jak uruchomić SWAP, pisałem w innym artykule Instalacja SWAP. Swap przy niewielkiej ilości pamięci na serwerze vps, pozwala na jego nieprzerwaną pracę np. w wyniku wzmożonego ruchu podczas świąt lub gdy jakaś inna usługa chwilowo wysyci nam pamięć. Pomaga on niejako przejąć na siebie część tego dodatkowego obciążenia.

Tuning Nginx

Tuning samego serwera Nginx polega na dopisaniu kilku reguł do pliku konfiguracyjnego /etc/nginx/nginx.conf i dostosowaniu przedstawionych wartości do konfiguracji i obciążenia serwera. Przedstawiona konfiguracja optymalizowana była pod nieobciążony serwer VPS. Gdy ruch na twojej stronie z czasem zacznie rosnąć, warto zmodyfikować niektóre parametry. Znajdź wąskie gardła i zwiększ dany parametr jeśli uważasz, że jest ustawiony zbyt nisko. Przeładuj serwer nginx i obserwuj, czy zmiany przyniosły oczekiwany rezultat, jeśli nie przyniosły, wróć do poprzedniej konfiguracji, zmodyfikuj kolejny parametr, który może poprawić pracę serwera itd.

# Z ilu rdzeni ma korzystać Nginx
   worker_processes 1;

# limit deskryptorów plików dla procesów roboczych
   worker_rlimit_nofile 100000;

events {
# Maksymalna ilość workerów/procesów Nginx.
# Liczba klientów, którzy mogą być jednocześnie obsługiwani przez serwer WWW Nginx
   worker_connections 4000;

# akceptuj jak najwięcej połączeń.
# jeśli jest włączony on, proces roboczy od razu akceptuje wszystkie nowe połączenia
# jeśli jest wyłączony off, akceptuje jedno nowe połączenie naraz
   multi_accept on;

# jawne wybranie metody przetwarzania połączenia.
# epoll jest wydajną metodą używana w linuksie od kerneli w wersji 2.6+
   use epoll;
}

http {
# limity pamięci podręcznej cache
    open_file_cache max=20000 inactive=20s;
    open_file_cache_valid 30s;
    open_file_cache_min_uses 1;
    open_file_cache_errors on;
    }

# włączenie dyrektywy sendfile eliminuje etap kopiowania danych do bufora i umożliwia
# bezpośrednie kopiowanie danych z jednego deskryptora pliku do drugiego.
   sendfile on;

# wysyła nagłówki w jednym kawałku.
   tcp_nopush on;

# Wyłącza informację o wersji serwera nginx.
   server_tokens off;

# jeśli wyłączone, zwiększa wydajność I/O dysku,
# poprzez wyłączenie dostępu do logów.access_log off;
   access_log off;

# nie buforuj przesyłanych danych.
# Dobre dla niewielkich ilości danych przesyłanych w czasie rzeczywistym.
   tcp_nodelay on;

# zezwól serwerowi na zamknięcie nieaktywnego połączenia
# (gdy klient nie odpowiada). Zwalnia pamięć.
   reset_timedout_connection on;

# zwolnij pamięć po zadanym czasie, gdy klient przestanie odpowiadać
   send_timeout 4;

# serwer zakończy połączenie keepalive po tym czasie
   keepalive_timeout 15;

# Ustawia maksymalną liczbę żądań, które mogą być obsługiwane za pośrednictwem
# jednego połączenia podtrzymującego.
# Po wykonaniu maksymalnej liczby żądań połączenie jest zamykane.
   keepalive_requests 100000;

# limit dla ilości jednoczesnych połączeń z jednego adresu IP IP
   limit_conn_zone $binary_remote_addr zone=conn_limit_per_ip:40m;

# ograniczenie liczby zapytań w danej sesji
   limit_req_zone $binary_remote_addr zone=req_limit_per_ip:40m rate=20r/s;

# jeśli rozmiar żądania jest większy niż rozmiar bufora,
# wtedy cała lub częściowa treść tego żądania jest zapisywana w pliku tymczasowym
   client_body_buffer_size  10k;

# rozmiar bufora do odczytu żądania nagłówka klienta
   client_header_buffer_size 1k;

# Maksymalny, dozwolony rozmiar żądania klienta
   client_max_body_size 8m;

# maksymalna ilość i rozmiar buforów dla nagłówków
   large_client_header_buffers 4 4k;

# limit czasu odczytu treści żądania klienta
   client_body_timeout   3m;

# jak długo czekać, aż klient wyśle nagłówek żądania
   client_header_timeout 3m;

## Brotli Settings ##
# Włącza kompresje brotli
   brotli on;

<# Poziom kompresji od 0-11. Czym wyższy poziom kompresji tym wyższe zużycie CPU
# za to mniejsza ilość danych przesyłanych do przeglądarki klienta.
   brotli_comp_level 1;

# Włącza lub wyłącza sprawdzanie istnienia wstępnie skompresowanych plików z rozszerzeniem .br.
# Dzięki tej wartości, wstępnie skompresowany plik jest używany we wszystkich przypadkach,
# bez sprawdzania, czy klient go obsługuje
   brotli_static on;

# Ustawia kompresję dla plików nie mniejszych niż 1000 bajtów.
   brotli_min_length 1000;

# Pozwala na kompresję klientom podłączonym przez proxy.
# Parametry określają ilość buforów oraz ich wielkość.
# W tym przypadku jest to 16 buforów po 8k.
   brotli_buffers 16 8k;

# Określa co ma byc objęte kompresją
   brotli_types text/xml image/svg+xml application/x-font-ttf image/vnd.microsoft.icon application/x-font-opentype application/json font/eot application/vnd.ms-fontobject application/javascript font/otf ap
}

Poniższy wpis dodaj do pliku z konfiguracją twojej strony w nginx – twojastrona.vhost

   # ograniczenie ilości połączeń oraz liczby zapytań w sesji dla danej strefy/strony www
server {
    limit_conn conn_limit_per_ip 20;
    limit_req zone=req_limit_per_ip burst=20 nodelay;
}

Nie kopiuj całej konfiguracji do swojego pliku konfiguracyjnego. Zastąp jedynie odpowiednie wpisy powyższymi wartościami lub dopisz całe dyrektywy jeśli ich nie ma.

Podane wartości nie są optymalne jak już wspomniałem i powinny być dostosowane przez ciebie w celu ich lepszego dostrojenia. Powyższa konfiguracja działa dobrze ale może działać lepiej jeśli dostosujesz podane wartości pod własny serwer i jego obciążenie.

Na co zwrócić szczególna uwagę ?

worker_processes – Jeśli posiadasz w swoim serwerze jeden rdzeń procesora to sprawa jest jasna i wartość dla tej dyrektywy powinna wynosić 1. Jeśli posiadasz więcej rdzeni, to warto się zastanowić nad tym, aby wynosiła ona , ilość posiadanych rdzeni-1, czyli dla dwóch posiadanych rdzeni 1, dla trzech 2, dla czterech 3 itp. Chodzi o to, aby ten jeden rdzeń został zawsze do dyspozycji innych usług działających na serwerze jak poczta, serwery baz danych, procesy systemowe itp.

worker_connection – Jest ograniczony ustawieniami w systemie, więc aby zwiększenie wartości miało sens trzeba dokonać także odpowiednich zmian w samym systemie. Utwórz najpierw odpowiedni katalog

$ sudo mkdir -p /etc/systemd/system/nginx.service.d

następnie utwórz w nim plik


$ sudo touch nginx.conf

Wyedytuj ten plik i dodaj do niego poniższy wpis

[Service]
LimitNOFILE=30000

Zapisz i przeładuj

$ sudo systemctl daemon-reload

limit_conn conn_limit_per_ip 20;
limit_req zone=req_limit_per_ip burst=20 nodelay;

Powyższe wartości powinny być optymalne, jednak warto przeprowadzić dodatkowe testy dla własnej strony i odpowiednio dla niej je zmodyfikować.

Sprawdź teraz poprawność pliku konfiguracyjnego /etc/nginx/nginx.conf, czy po przeprowadzonych modyfikacjach nie zawiera błędów

$ sudo nginx -t

Jeżeli nie ma błędów to przeładuj serwer nginx

$ sudo systemctl reload nginx

Jeżeli wszystko poszło dobrze, to stuningowałeś właśnie swój serwer przez co powinien pracować bardziej wydajnie, a strony otwierać się szybciej.

Poniżej przedstawiam swój test ab, który przeprowadziłem dla testowanego serwera po dokonaniu tuningu.

$ sudo ab -n 1000 -c 100 https://www.teststrony/

Jak widać na przedstawionym zdjęciu Failed requests wynosi 924, czyli serwer skutecznie odrzuca nadmierną ilość żądań co w efekcie odciąża serwer i zabezpiecza go przed nadmierną aktywnością różnych botów lub ataków typu Dos.

W dalszej kolejności należy przeprowadzić testy dla samej strony internetowej hostowanej na serwerze, aby sprawdzić czy przeprowadzona optymalizacja jest skuteczna, jak wpłynęła na szybkość ładowania się naszej strony oraz, czy sama strona nie zawiera błędów, które mogą sprawiać problemy.

Poniżej zamieściłem linki do trzech narzędzi online, dzięki którym takie testy możesz przeprowadzić. Warto skorzystać z wszystkich trzech, jako że pracują one w trochę inny sposób.

https://gtmetrix.com/
https://www.webpagetest.org/
https://developers.google.com/speed/pagespeed/insights/

Podsumowanie

O zaletach takiego tuningu wspomniałem na początku tekstu. Ewentualnymi wadami może być tutaj brak loadbalancingu i równoważenia obciążenia, a także brak jakiegoś serwera cachującego jak np. varnish co na pewno dodatkowo zmniejszyło by obciążenie i poprawiło wydajność. Uważam jednak, że nawet ta dość prosta do wdrożenia metoda jest warta uwagi i jest lepszą alternatywą dla współdzielonego hostingu np. przy prowadzeniu własnego bloga, małego sklepu internetowego itp.

Odpowiednia konfiguracja serwera Nginx jest tak naprawdę tylko jednym z elementów poprawy szybkości obsługiwanych przez niego stron internetowych. Oprócz tuningu samego serwera, warto także jednak wdrożyć jakieś usługi cachujące (warto jednak sprawdzić, czy nie przyniosą one odwrotnego efektu do zamierzonego), aby dodatkowo odciążyć nasz serwer. Przy tak małym serwerze za wiele nie poszalejemy ale nawet i tutaj warto uruchomić np. memcached (ustawiając odpowiednio jego limity) oraz coś na wzór expires. W Wordpresie do tego celu można wykorzystać np. wtyczkę W3 Total Cache.

Co do samego Memcached, to warto dokładnie przetestować jak zachowuje się serwer i działająca na nim strona po jego użyciu. Zdarzało mi się, że na niektórych serwerach vps, strona działała wyraźnie wolniej z Memcached niż bez niego. Dość ciekawe zjawisko i prawdę mówiąc nie wiem co było tego przyczyną. Podejrzewam jednak, że ma to ścisły związek z pamięcią ram na takim VPS, więc warto dokładnie przemyśleć co cachować. Może się zdarzyć, że zapytania do bazy danych będą jedyną rzeczą, na którą będzie stać twój serwer przy małej ilości pamięci. Warto o tym pamiętać.