• Курсы Академии Кодебай, стартующие в мае - июне, от команды The Codeby

    1. Цифровая криминалистика и реагирование на инциденты
    2. ОС Linux (DFIR) Старт: 16 мая
    3. Анализ фишинговых атак Старт: 16 мая Устройства для тестирования на проникновение Старт: 16 мая

    Скидки до 10%

    Полный список ближайших курсов ...

Гостевая статья Поднимаем LNMP (Linux Nginx MySQL PHP)

Очередная статья по настройке LNMP (Linux Nginx MySQL PHP). Собрал по-кусочкам из многих источников. Выкладываю тут, может кому понадобится.
Действие происходит на Fedora 31 Server. С небольшими правками должно работать и на RedHat/CentOS/Oracle Linux.

1. Начнём с плохого совета - отключаем . В идеале его нужно было-бы правильно настроить, но я с ним никогда не дружил.
Bash:
sed -i 's/^SELINUX=.*/SELINUX=disabled/g' /etc/selinux/config
setenforce 0


2. Устанавливаем основной софт
Ставим nginx, PHP, MariaDB (заменяет MySQL) и certbot для получения сертификатов Let's Encrypt.
Bash:
dnf install -y nginx php-fpm mariadb-server certbot certbot-nginx


3. Устанавливаем модули для PHP
Список модулей может сильно варьироваться в зависимости от нужд. Перечисленные необходимы для работы популярных скриптов/движков (phpmyadmin, phpbb, mybb, drupal, joomla, wordpress), поэтому пока ставим только их.
Bash:
dnf install -y php-mbstring php-mysqlnd php-xml php-json php-gd php-opcache


4. Создаём пользователя и настраиваем права
Безопасности ради, Nginx и PHP работают под отдельным пользователем. В примере использую www:www
Bash:
useradd -M -U -s $(which nologin) www
mkdir /www
chown -R www:www /var/lib/nginx /var/lib/php /www


5. Включаем автостарт и запускаем службы
Bash:
systemctl enable --now nginx mariadb php-fpm


6. Настраиваем учётки у MariaDB
Bash:
mysql_secure_installation


7. Настраиваем PHP
7.1. Фиксим баги:
Bash:
vi /etc/php.ini
Добавляем/раскомментируем строку (потенциально фиксит уязвимости - подробнее описано в комментариях к функции):
Код:
cgi.fix_pathinfo=0

7.2. Настройки PHP-FPM listener:
Bash:
vi /etc/php-fpm.d/www.conf
Код:
user = www
group = www
listen = /run/php-fpm/www.sock

listen.owner = www
listen.group = www
# ИЛИ
;listen.acl_users = www
;listen.acl_groups = www
Тут нужно быть внимательным - параметры listen.acl_users и listen.acl_groups более приоритетны, чем listen.owner и listen.group, поэтому оставляем что-то одно, чтобы не было путаницы.


8. Настраиваем nginx
Рекомендую просто скопировать nginx.conf и настраивать уже его под свои нужны:
Код:
user www www;
worker_processes auto;

events {
    worker_connections  1024;
}

http {
    include       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"';

    sendfile        on;
    #tcp_nopush     on;
    keepalive_timeout 30;
    gzip off;
    server_tokens off;

    # Redirect HTTP to HTTPS
    server {
        listen 80;
        listen [::]:80;
        server_name example.com www.example.com;
        return 301 https://$host$request_uri;
    }

    # Deny requests to server by IP
    server {
        listen 80 default_server;
        listen [::]:80 default_server;
        server_name _;
        return 444;
    }

    # HTTPS
    server {
        listen 443 ssl http2;
        listen [::]:443 ssl http2;
        server_name example.com www.example.com;

        # Main http root
        location / {
            root /www;
            index index.php index.html index.htm;
            autoindex off;
        }

        # Block access to .ht* files
        location ~ /\.ht {
            deny all;
        }

        # Pass PHP scripts to php-fpm
        location ~ [^/]\.php(/|$) {
            fastcgi_split_path_info ^(.+?\.php)(/.*)$;
            if (!-f /www/$fastcgi_script_name) {
                return 404;
            }

            # Mitigate https://httpoxy.org/ vulnerabilities
            fastcgi_param HTTP_PROXY "";
            fastcgi_pass unix:/run/php-fpm/www.sock;
            fastcgi_index index.php;

            # include the fastcgi_param setting
            include fastcgi_params;
            fastcgi_param  SCRIPT_FILENAME   /www/$fastcgi_script_name;
        }

        # SSL configuration
        ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
        ssl_session_timeout 1d;
        ssl_session_cache shared:SSL:50m;
        ssl_session_tickets off;
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
        ssl_prefer_server_ciphers on;

        # HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months)
        add_header Strict-Transport-Security "max-age=63072000; includeSubdomains" always;

        # OCSP Stapling
        # fetch OCSP records from URL in ssl_certificate and cache them
        ssl_stapling on;
        ssl_stapling_verify on;

        ## verify chain of trust of OCSP response using Root CA and Intermediate certs
        ssl_trusted_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
        resolver 1.1.1.1 1.0.0.1;
    }
}

Hint. Чтобы заменить домен на свой, можно сделать так:
Bash:
sed -i 's/example.com/mydomain.com/g' /etc/nginx/nginx.conf


9. Настройка HTTPS
Сертификат получать будем от
В зависимости от используемого DNS, потребуется поставить соответствующий плагин:
Код:
python3-certbot-dns-ovh
python3-certbot-dns-nsone
python3-certbot-dns-gehirn
python3-certbot-dns-google
python3-certbot-dns-linode
python3-certbot-dns-luadns
python3-certbot-dns-rfc2136
python3-certbot-dns-route53
python3-certbot-dns-cloudxns
python3-certbot-dns-dnsimple
python3-certbot-dns-cloudflare
python3-certbot-dns-dnsmadeeasy
python3-certbot-dns-sakuracloud
python3-certbot-dns-digitalocean

Я использую cloudflare, поэтому ставим его:
Bash:
dnf install -y python3-certbot-dns-cloudflare

Получаем сертификат:
Bash:
certbot certonly --dns-cloudflare --dns-cloudflare-credentials ~/.secrets/certbot/cloudflare.ini -d example.com

Для проверки SSL, можно использовать сайт Там-же есть полезные советы по настройке.
1603735827094.png


Исправляем потерциальные ошибки:
1. Не запускается nginx
* Проверить конфиг:
Bash:
nginx -t
* Проверить логи службы:
Bash:
systemctl status nginx.service
journalctl -xe


2. nginx и PHP запущены, но даже самые простые скрипты не работают
* Проверить, под какими пользователями запущены службы:
Bash:
ps -ef | grep -e nginx -e php-fpm
Все процессы, кроме 'nginx: master process', который работает от root'a, должны быть запущены от нашего пользователя (www:www).
Пример:
Код:
root       11246       1  0 13:39 ?        00:00:00 php-fpm: master process (/etc/php-fpm.conf)
www        11247   11246  0 13:39 ?        00:00:01 php-fpm: pool www
www        11248   11246  0 13:39 ?        00:00:02 php-fpm: pool www
www        11249   11246  0 13:39 ?        00:00:01 php-fpm: pool www
www        11250   11246  0 13:39 ?        00:00:01 php-fpm: pool www
www        11251   11246  0 13:39 ?        00:00:02 php-fpm: pool www
www        11254   11246  0 13:42 ?        00:00:00 php-fpm: pool www
root       11755       1  0 15:33 ?        00:00:00 nginx: master process /usr/sbin/nginx
www        11756   11755  0 15:33 ?        00:00:00 nginx: worker process

* Проверить права на файл сокетов:
Bash:
ls -la /run/php-fpm/www.sock
Пример:
Код:
srw-rw---- 1 www www 0 Jan 23 13:39 /run/php-fpm/www.sock


3. Простые скрипты работают, а сложные не запускаются, либо выдают ошибки:
Смотреть логи nginx. Подсказка, скорее всего, будет там:
Bash:
tail -f /var/log/nginx/error.log
Например, если мы видим ошибку
Код:
2020/01/23 13:12:23 [error] 10670#0: *7 FastCGI sent in stderr: "PHP message: PHP Fatal error:  Uncaught Error: Class 'Locale' not found in /www/vanilla/applications/dashboard/controllers/api/LocalesApiController.php:103
то стоит поискать недостающий модуль:
Код:
# dnf search php- | grep -i locale
Last metadata expiration check: 0:29:20 ago on Thu 23 Jan 2020 12:44:39 PM EET.
php-symfony-locale.noarch : Symfony Locale Component
# dnf install php-symfony-locale
...


При копировании/репостинге ссылка на оригинал ( ) обязательна.

EOF :)
 
  • Нравится
Реакции: Vlg и BearSec
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!