Wdrażanie aplikacji w Laravel 7 Ubuntu & Nginx

Wdrażanie aplikacji w Laravel 7 Ubuntu & Nginx

Zdecydowałem się na wykonanie portfolio w Laravel 7. Tak, aby strona główna była stroną docelową, a wszystkie informacje na niej zawarte można było zmieniać z poziomu panelu administracyjnego. Nie o to chodzi. Doszło do wdrożenia. Znalazłem kilka dobrych tutoriali, jak to zrobić na pełnoprawnym serwerze ze wszystkimi problemami. Nie jestem zbyt mocny we wdrażaniu; generalnie jestem bardziej z przodu niż z pełnym stosem. A jeśli nadal mogę pisać i testować w PHP, to przed zarządzaniem serwerem itp. Jeszcze nie dorosłem. Ale musiałem to rozgryźć.

Teraz przejdziemy przez wszystkie kroki, zaczynając od uruchomienia przez SSH, a kończąc na działającej witrynie. Postaramy się uniknąć wszystkich pułapek.

Być może uda Ci się znaleźć podobne instrukcje w Internecie. W końcu w końcu to znalazłem. To prawda, że ​​​​nie w jednym miejscu, nie bez pomocy StackOverflow i prawie po rosyjsku. Cierpiałem. Dlatego zdecydowałem się uprościć Ci życie.

Wszystko zrobimy z kroplą na DigitalOcean. To oczywiście opcjonalne; możesz wybrać dowolny hosting. Dotrzesz do działającego serwera na Ubuntu, wróć. Dla tych, którzy nadal zdecydują się na korzystanie z DigitalOcean, będzie więcej wskazówek dotyczących konfiguracji domeny. A także Link polecający o wartości 100 dolarów.

Wszystkie kroki specyficzne dla DigitalOcean zostaną podane w przypisach takich jak ten.

Zacznijmy.

TL;DR (tylko podstawowe polecenia)

Utwórz użytkownika

  • ssh root@[IP-адрес вашего дроплета]
  • adduser laravel
  • usermod -aG sudo laravel
  • su laravel

Dodaj do tego SSH

  • mkdir ~/.ssh
  • chmod 700 ~/.ssh
  • vim ~/.ssh/authorized_keys
  • Włóż klucz publiczny
  • chmod 600 ~/.ssh/authorized_keys

Zapora sieciowa

  • sudo ufw allow OpenSSH
  • sudo ufw enable
  • sudo ufw status

nginx

  • sudo apt update
  • sudo apt install -y nginx
  • sudo ufw allow 'Nginx HTTP'
  • sudo ufw status

MySQL

  • sudo apt install -y mysql-server
  • sudo mysql_secure_installation, NYNNY
  • sudo mysql
  • ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '<Ваш пароль для MySQL>';
  • SELECT user,authentication_string,plugin,host FROM mysql.user;
  • FLUSH PRIVILEGES;
  • exit

PHP

  • sudo apt update

  • sudo apt install -y curl wget gnupg2 ca-certificates lsb-release apt-transport-https

  • sudo apt-add-repository ppa:ondrej/php

  • sudo apt update

  • 7.3: sudo apt install -y php7.3-fpm php7.3-mysql

  • 7.4: sudo apt install -y php7.4-fpm php7.4-mysql

  • sudo vim /etc/nginx/sites-available/<Ваш домен>

Podstawowe ustawienia:

server {
        listen 80;
        root /var/www/html;
        index index.php index.html index.htm index.nginx-debian.html;
        server_name <Ваш домен или IP>;

        location / {
                try_files $uri $uri/ =404;
        }

        location ~ .php$ {
                include snippets/fastcgi-php.conf;
                fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
        }

        location ~ /.ht {
                deny all;
        }
}

Tylko konfiguracja HTTP dla Laravel:

server {
    listen 80;
    listen [::]:80;

    root /var/www/html/<Имя проекта>/public;
    index index.php index.html index.htm index.nginx-debian.html;

    server_name <Ваш домен или IP>;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ .php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
    }

    location ~ /.ht {
        deny all;
    }
}

Ustawienie HTTPS dla Laravela:

server {
    listen 80;
    listen [::]:80;

    server_name <Ваш домен> www.<Ваш домен>;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name <Ваш домен> www.<Ваш домен>;
    root /var/www/html/<Имя проекта>/public;

    ssl_certificate /etc/letsencrypt/live/<Ваш домен>/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/<Ваш домен>/privkey.pem;

    ssl_protocols TLSv1.2;
    ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384;
    ssl_prefer_server_ciphers on;

    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-XSS-Protection "1; mode=block";
    add_header X-Content-Type-Options "nosniff";

    index index.php index.html index.htm index.nginx-debian.html;

    charset utf-8;

    location / {
            try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ .php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
    }

    location ~ /.ht {
            deny all;
    }

    location ~ /.well-known {
            allow all;
    }
}

  • sudo ln -s /etc/nginx/sites-available/<Ваш домен> /etc/nginx/sites-enabled/
  • sudo unlink /etc/nginx/sites-enabled/default
  • sudo nginx -t
  • sudo systemctl reload nginx

laravel

  • 7.3: sudo apt install -y php7.3-mbstring php7.3-xml composer unzip

  • 7.4: sudo apt install -y php7.4-mbstring php7.4-xml composer unzip

  • mysql -u root -p

  • CREATE DATABASE laravel DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;

  • GRANT ALL ON laravel.* TO 'root'@'localhost' IDENTIFIED BY '<Ваш пароль от MySQL>';

  • FLUSH PRIVILEGES;

  • exit

  • cd /var/www/html

  • sudo mkdir -p <Имя проекта>

  • sudo chown laravel:laravel <Имя проекта>

  • cd ./<Имя проекта>

  • git clone <ссылка на проект> . / git clone -b <имя ветки> --single-branch <ссылка на проект> .

  • composer install

  • vim .env

APP_NAME=Laravel
APP_ENV=production
APP_KEY=
APP_DEBUG=false
APP_URL=http://<Ваш домен>

LOG_CHANNEL=stack

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=<Ваш пароль от MySQL>

  • php artisan migrate

  • php artisan key:generate

  • sudo chown -R $USER:www-data storage

  • sudo chown -R $USER:www-data bootstrap/cache

  • chmod -R 775 storage

  • chmod -R 775 bootstrap/cache

HTTPS

  • sudo add-apt-repository ppa:certbot/certbot

  • sudo apt install -y python-certbot-nginx

  • sudo certbot certonly --webroot --webroot-path=/var/www/html/<Имя проекта>/public -d <Ваш домен> -d www.<Ваш домен>

  • sudo nginx -t

  • sudo ufw allow 'Nginx HTTPS'

  • sudo ufw status

  • sudo systemctl reload nginx

Utwórz droplet na DigitalOcean i zarejestruj nowy klucz SSH

Wierzę, że sam dowiesz się, jak zarejestrować się w DigitalOcean. Nie jest to łatwe, wymaga wielu weryfikacji i innych rzeczy. Jeśli podczas weryfikacji przy użyciu dokumentów stale pojawia się błąd sieciowy, spróbuj zrobić wszystko przez VPN, powinno pomóc.

W menu u góry kliknij Stwórz->Kropelki. Wybierać Ubuntu.

Jak tylko się zarejestrujesz, otrzymasz 100 dolarów na swoje konto. Ale nie dajcie się zwieść. Masz na to tylko 60 dni. A to jest bardzo mało. Być może, podobnie jak ja, będziesz chciał skorzystać z droższego planu, aby później, gdy zaczną płynąć prawdziwe pieniądze, móc przejść na tańszy. Od razu ci powiem, że to nie zadziała. Możesz go zwiększyć, ale nie możesz go zmniejszyć. Tak to idzie. wybieram Standard->$5.

Wybieram region najbliższy nam Frankfurt. Sieć VPC->domyślnie-fra1

Niezwłocznie dokonamy uwierzytelnienia poprzez SSH. Kliknij Nowy klucz SSH. Jeśli nie masz protokołu SSH, po prawej stronie znajdują się bardzo proste instrukcje. Otwórz terminal bash i wklej ssh-keygen. Następnie przechodzimy do pliku z kluczem publicznym /Users/<Ваше имя пользователя>/.ssh/id_rsa.pub (lub po prostu cat ~/.ssh/id_rsa.pub), skopiuj zawartość i wklej ją do okna po lewej stronie. Jakiekolwiek imię.

Wymyślamy nazwę hosta dla dropletu.

Kliknij Utwórz kroplę

Utwórz nowego użytkownika

  • ssh root@[IP-адрес вашего дроплета]
  • Czy na pewno chcesz kontynuować połączenie (tak/nie/[odcisk palca])? yes
  • Wpisz swoje hasło SSH
  • Utwórz użytkownika laravel: adduser laravel
  • Podaj swoje hasło i inne informacje (podaję tylko imię i nazwisko)
  • Dodaj użytkownika do grupy sudo: usermod -aG sudo laravel

SSH dla nowego użytkownika

  • Przełącz na nowego użytkownika: su laravel

Wszystkie czynności wykonujemy dalej, aż do końca artykułu, w imieniu użytkownika laravel. Dlatego jeśli nagle ktoś Ci przeszkodzi, zaloguj się ponownie i wejdź su laravel

  • mkdir ~/.ssh
  • chmod 700 ~/.ssh
  • vim ~/.ssh/authorized_keys

Otworzyliśmy plik w Vimie. Jeśli w ogóle się na tym nie znasz, możesz pracować w Nano, masz rację.

Najbardziej podstawowe polecenia Vima

Aby korzystać z edytora Vima w całym artykule, wystarczy wiedzieć, co następuje.

  • Vim ma różne tryby: Tryb normalny, w którym wprowadzasz polecenia i wybierasz tryby i inne.
  • Aby wyjść z dowolnego trybu i powrócić do trybu normalnego, wystarczy nacisnąć Esc
  • Poruszaj się: możesz po prostu używać strzałek
  • Zamknąć bez zapisania <Normal mode>: :q!
  • Wyjdź i zapisz <Normal mode>: :wq
  • Przełącz na tryb wprowadzania tekstu <Normal mode>: i (z angielskiego. wstawić)
  • Wstawiamy nasz klucz publiczny (co zrobiliśmy powyżej)
  • Chronimy przed zmianami: chmod 600 ~/.ssh/authorized_keys

Instalowanie zapory ogniowej

  • Przyjrzyjmy się wszystkim dostępnym ustawieniom: sudo ufw app list
  • Zezwól na OpenSSH (w przeciwnym razie nas zablokuje): sudo ufw allow OpenSSH
  • Uruchommy zaporę sieciową: sudo ufw enable, y
  • Sprawdzanie: sudo ufw status

Status: active

To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere
OpenSSH (v6)               ALLOW       Anywhere (v6)

Wszystko jest dobrze.

Instalacja Nginxa

Podczas instalacji czasami zostaniesz zapytany: „Czy jesteś pewien?” Odpowiedź y (no cóż, tylko jeśli jesteś pewien).

  • sudo apt update
  • sudo apt install nginx

Dodanie Nginx do ustawień zapory

  • sudo ufw app list
  • sudo ufw allow 'Nginx HTTP'
  • sudo ufw status

Status: active

To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere
Nginx HTTP                 ALLOW       Anywhere
OpenSSH (v6)               ALLOW       Anywhere (v6)
Nginx HTTP (v6)            ALLOW       Anywhere (v6)

Przejdź do swojego adresu IP. Jeśli wszystko pójdzie dobrze, powinieneś zobaczyć następujący komunikat.

Wdrażanie aplikacji w Laravel 7 Ubuntu & Nginx

Instalacja MySQL-a

  • sudo apt install mysql-server
  • Uruchomienie automatycznego skryptu zabezpieczającego sudo mysql_secure_installation

Odpowiedz na zadane pytania. Jeśli nie wiesz, co odpowiedzieć, oto kilka sugerowanych opcji:

  • Zweryfikuj wtyczkę hasła - N

  • Usunąć anonimowych użytkowników? — Y

  • Zabronić zdalnego logowania roota? — N

  • Usunąć testową bazę danych i uzyskać do niej dostęp? — N

  • Załadować teraz ponownie tabele uprawnień? — Y

  • Przejdźmy do MySQL: sudo mysql

  • Przyjrzyjmy się metodom dostępu: SELECT user,authentication_string,plugin,host FROM mysql.user;

  • Ustaw hasło dla roota: ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '<Ваш пароль для MySQL>';

  • Przyjrzyjmy się jeszcze raz metodom dostępu: SELECT user,authentication_string,plugin,host FROM mysql.user;

  • Zastosuj zmiany i wyjdź z MySQL: FLUSH PRIVILEGES; и exit

  • Teraz, aby zalogować się do MySQL, musisz użyć mysql -u root -p i wprowadź hasło

Instalowanie PHP

Skorzystajmy z repozytorium strony trzeciej z Ondrej Surý

  • sudo apt update
  • sudo apt install -y curl wget gnupg2 ca-certificates lsb-release apt-transport-https
  • sudo apt-add-repository ppa:ondrej/php
  • sudo apt update

Teraz wybierzmy. W przypadku Laravel 7 możesz wybrać PHP 7.3 lub 7.4. Jedyna różnica będzie w liczbach 3 i 4.

  • 7.3: sudo apt install -y php7.3-fpm php7.3-mysql
  • 7.4: sudo apt install -y php7.4-fpm php7.4-mysql

Menedżer procesów PHP FastCGI (fpm) współpracuje z żądaniami PHP. mysql, oczywiście, do pracy z MySQL.

Od teraz będę robić wszystko na 7.4.

Konfigurowanie Nginxa

  • sudo vim /etc/nginx/sites-available/<Ваш домен>

Zamiast „<Twoja domena>” wpisz domenę (np. mysite.ru), z którego chcesz skorzystać w przyszłości. Jeśli jeszcze jej nie masz, napisz ją, a następnie powtórz kroki opisane w tym rozdziale dla swojej domeny, gdy ją wybierzesz.

Wprowadź następujące informacje:

server {
        listen 80;
        root /var/www/html;
        index index.php index.html index.htm index.nginx-debian.html;
        server_name <Ваш домен или IP>;

        location / {
                try_files $uri $uri/ =404;
        }

        location ~ .php$ {
                include snippets/fastcgi-php.conf;
                fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
        }

        location ~ /.ht {
                deny all;
        }
}

Jeśli zamiast tego wybierzesz wersję 7.3 php7.4-fpm.sock pisać w php7.4-fpm.sock.

Słuchaj na porcie 80 server_namekiedy dotrzemy do żądania root /var/www/html weź plik indeksu. Jeśli po server_name Coś jest, szukamy takiego pliku. Jeśli go nie znajdziemy, wyrzucamy 404. Jeśli kończy się na .php, przebiec fpm... Jeśli jest .ht, zakazać (403).

  • Tworzenie linku z sites-available в sites-enabled: sudo ln -s /etc/nginx/sites-available/<Ваш домен> /etc/nginx/sites-enabled/
  • Usunięcie linku do default: sudo unlink /etc/nginx/sites-enabled/default
  • Sprawdzanie błędów: sudo nginx -t
  • Ponowne uruchomienie: sudo systemctl reload nginx

Sprawdzanie pracy:

  • sudo vim /var/www/html/info.php
  • Piszemy: <?php phpinfo();
  • Chodźmy do <Ваш IP>/info.php

Powinieneś zobaczyć coś takiego:

Wdrażanie aplikacji w Laravel 7 Ubuntu & Nginx

Teraz ten plik można usunąć: sudo rm /var/www/html/info.php

Zainstaluj Laravela

  • 7.3: sudo apt install php7.3-mbstring php7.3-xml composer unzip

  • 7.4: sudo apt install php7.4-mbstring php7.4-xml composer unzip

  • Przejdźmy do MySQL: mysql -u root -p

  • Utwórz bazę danych o nazwie laravel: CREATE DATABASE laravel DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;

  • Zapewniamy dostęp do roota laravel: GRANT ALL ON laravel.* TO 'root'@'localhost' IDENTIFIED BY '<Ваш пароль от MySQL>';

  • FLUSH PRIVILEGES;

  • exit

  • cd /var/www/html

  • Utwórz folder dla projektu: sudo mkdir -p <Имя проекта>

  • Zapewniamy użytkownikowi laravel prawa do projektu: sudo chown laravel:laravel <Имя проекта>

Następnie musisz przenieść projekt. Na przykład klonowanie z Githuba.

  • cd ./<Имя проекта>
  • git clone <ссылка на проект> .

Warto wziąć pod uwagę, że jeśli nie zapisałeś plików statycznych (np /public) na Githubie, to oczywiście ich nie będziesz mieć. Na przykład utworzyłem osobny wątek, aby rozwiązać ten problem deploy, z którego już sklonowałem: git clone -b <имя ветки> --single-branch <ссылка на проект> ..

  • Instalowanie zależności: composer install
  • Utwórz .env: vim .env

Podstawowa wersja wygląda tak:

APP_NAME=Laravel
APP_ENV=production
APP_KEY=
APP_DEBUG=false
APP_URL=http://<Ваш домен>

LOG_CHANNEL=stack

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=<Ваш пароль от MySQL>

Jeśli skopiujesz plik .env, zamień APP_ENV na produkcyjny, APP_DEBUG na fałszywy i wprowadź poprawne ustawienia MySQL.

  • Migracja bazy danych: php artisan migrate
  • Generowanie kodu: php artisan key:generate

Zmiana uprawnień:

  • sudo chown -R $USER:www-data storage
  • sudo chown -R $USER:www-data bootstrap/cache
  • chmod -R 775 storage
  • chmod -R 775 bootstrap/cache

Ostatnią rzeczą, jaka pozostała, jest ponowna konfiguracja Nginx dla Laravel:

sudo vim /etc/nginx/sites-available/<Ваш домен>

server {
    listen 80;
    listen [::]:80;

    root /var/www/html/<Имя проекта>/public;
    index index.php index.html index.htm index.nginx-debian.html;

    server_name <Ваш домен или IP>;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ .php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
    }

    location ~ /.ht {
        deny all;
    }
}

Podobnie jak ostatnim razem, jeśli zamiast tego wybierzesz wersję 7.3 php7.4-fpm.sock pisać w php7.4-fpm.sock.

Zakładanie domeny na DigitalOcean

Wszystko jest właściwie bardzo proste. Kupujesz domenę (w dowolnym miejscu), przełączasz się na DigitalOcean w Stwórz->Domeny/DNS. поле Dodaj domenę wchodzisz do tej domeny i klikasz dodaj. Następnie przejdź do ustawień domeny i do pola NAZWA HOSTA Wchodzić @. Wybierz projekt i kliknij Utwórz rekord.
Teraz przejdź do strony, na której kupiłeś domenę, znajdź tam „Serwery DNS” (lub coś podobnego) i wejdź na serwery DigitalOcean (tj. ns1.digitalocean.com, ns2.digitalocean.com, ns3.digitalocean.com). Teraz musisz trochę (lub dużo) poczekać, aż te ustawienia zostaną zaakceptowane. Gotowy!
Jedynym problemem jest to, że Twoja witryna będzie otwierać się tylko jako HTTP. Aby mieć HTTPS, przejdź do następnej części.

Konfigurowanie protokołu HTTPS

Zainstaluj certbota i przekaż mu nazwę domeny (format mysite.ru) i nazwę domeny z www (www.mysite.ru).

  • sudo add-apt-repository ppa:certbot/certbot
  • sudo apt install python-certbot-nginx
  • sudo certbot certonly --webroot --webroot-path=/var/www/html/<Имя проекта>/public -d <Ваш домен> -d www.<Ваш домен>

Teraz musisz ponownie skonfigurować Nginx (nie zapomnij zastąpić swoich wartości):

server {
    listen 80;
    listen [::]:80;

    server_name <Ваш домен> www.<Ваш домен>;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name <Ваш домен> www.<Ваш домен>;
    root /var/www/html/<Имя проекта>/public;

    ssl_certificate /etc/letsencrypt/live/<Ваш домен>/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/<Ваш домен>/privkey.pem;

    ssl_protocols TLSv1.2;
    ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384;
    ssl_prefer_server_ciphers on;

    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-XSS-Protection "1; mode=block";
    add_header X-Content-Type-Options "nosniff";

    index index.php index.html index.htm index.nginx-debian.html;

    charset utf-8;

    location / {
            try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ .php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
    }

    location ~ /.ht {
            deny all;
    }

    location ~ /.well-known {
            allow all;
    }
}

Myślę, że już rozumiesz, co należy zmienić w PHP 7.3.

Tutaj właściwie wszystko jest proste. Po prostu przekierowujemy wszystkie żądania z HTTP (port 80) na HTTPS (port 443). I tam robimy wszystko tak samo jak poprzednio, ale z szyfrowaniem.

Pozostaje tylko ustawić uprawnienia w zaporze sieciowej:

  • sudo nginx -t
  • sudo ufw app list
  • sudo ufw allow 'Nginx HTTPS'
  • sudo ufw status
  • sudo systemctl reload nginx

Teraz wszystko powinno działać jak należy.

[Zaawansowane] Instalowanie Node.js

Jeśli nagle zajdzie potrzeba uruchomienia poleceń npm bezpośrednio na serwerze, musisz zainstalować Node.js.

  • sudo apt update
  • sudo apt install -y nodejs npm
  • nodejs -v

To wszystko, zatrzymałem się na tym etapie. W zasadzie jestem zadowolony z wyniku. Być może przejdę z DigitalOcean gdzieś bliżej Rosji i taniej. Ale ponieważ przeszedłem już wszystkie rundy weryfikacyjne na stronie i zrobiłem tam wszystko, pokazałem je na przykładzie. Ponadto ich początkowe 100 dolarów to doskonała odskocznia do szkolenia.

PS Specjalne podziękowania dla autora to sedno, który stał się podstawą wszystkich powyższych działań. W niektórych przypadkach nie działa to w przypadku Laravel 7, naprawiłem to.

PPS Jeśli jesteś czołowym inżynierem, który myśli w oparciu o polecenia basha, nie oceniaj surowo. Może się wydawać, że ten artykuł jest na niskim poziomie, ale byłbym szczęśliwy, gdybym go znalazł, gdy go potrzebowałem. Jeśli są propozycje ulepszeń, jestem za.

Źródło: www.habr.com

Kup niezawodny hosting dla stron z ochroną DDoS, serwery VPS VDS 🔥 Kup niezawodny hosting stron internetowych z ochroną DDoS, serwery VPS VDS | ProHoster