Ответы пользователя по тегу PHP-FPM
  • Как установить PHP 5.4 на Nginx в Ubuntu Server 16.04?

    Если кратко, то можно так собрать:

    Установка php-5.4.45 + fpm

    mkdir -p /opt/php-5.4.45
    rm -rf /usr/local/src/php5-build && mkdir /usr/local/src/php5-build
    cd /usr/local/src/php5-build
    wget de2.php.net/distributions/php-5.4.45.tar.gz
    tar -vzxf php-5.4.45.tar.gz && cd php-5.4.45
    ./configure --prefix=/opt/php-5.4.45 --with-pdo-pgsql --with-zlib-dir --with-freetype-dir --enable-mbstring --with-libxml-dir=/usr --enable-soap --enable-calendar --with-curl --with-mcrypt --with-zlib --with-gd --with-pgsql --disable-rpath --enable-inline-optimization --with-bz2 --with-zlib --enable-sockets --enable-sysvsem --enable-sysvshm --enable-pcntl --enable-mbregex --enable-exif --enable-bcmath --enable-zip --with-pcre-regex --with-mysqli --with-mysql --with-pdo-mysql --with-mysqli --with-jpeg-dir=/usr --with-png-dir=/usr --enable-gd-native-ttf --with-openssl --with-fpm-user=www-data --with-fpm-group=www-data --with-libdir=/lib/x86_64-linux-gnu --enable-ftp --with-imap --with-imap-ssl --with-kerberos --with-gettext --with-xmlrpc --with-xsl --enable-fpm
    make && make install
    cp /usr/local/src/php5-build/php-5.4.45/php.ini-production /opt/php-5.4.45/lib/php.ini
    cp /opt/php-5.4.45/etc/php-fpm.conf.default /opt/php-5.4.45/etc/php-fpm.conf
    mkdir /opt/php-5.4.45/etc/php-fpm.d

    Редактируем некоторые параметры в /opt/php-5.4.45/etc/php-fpm.conf

    include=etc/php-fpm.d/*.conf
    [global]
    pid = run/php-fpm.pid
    log_level = error

    Меняем настройки в /opt/php-5.4.45/lib/php.ini по своему вкусу, у меня так:

    date.timezone = "Asia/Yekaterinburg"
    expose_php = Off
    short_open_tag = On
    max_execution_time = 600
    max_input_time = 300
    max_input_vars = 5000
    memory_limit = 512M
    error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT & ~E_NOTICE
    post_max_size = 128M
    ;default_charset = "UTF-8"
    upload_max_filesize = 128M
    default_socket_timeout = 120
    mysql.connect_timeout = 120

    Если в Linux используется sysv, то создаем файл /etc/init.d/php-5.4.45-fpm, см. https://gist.github.com/CHERTS/bcf1006e90777ead77c...

    Назначаем права и автостарт
    # chmod 755 /etc/init.d/php-5.4.45-fpm
    # insserv -v /etc/init.d/php-5.4.45-fpm
    Запускаем:
    # /etc/init.d/php-5.4.45-fpm start

    Если в Linux используется systemd, то создаем файл
    /lib/systemd/system/php-5.4.45-fpm.service
    исходник https://gist.github.com/CHERTS/bcf1006e90777ead77c...

    Если в Linux используется systemd выполняем:
    # chown root:root /lib/systemd/system/php-5.4.45-fpm.service
    # systemctl daemon-reload
    # systemctl enable php-5.4.45-fpm.service
    # systemctl start php-5.4.45-fpm.service

    Проверить статус можно командой
    # systemctl status php-5.4.45-fpm.service

    Удалить
    # systemctl stop php-5.4.45-fpm.service
    # systemctl disable php-5.4.45-fpm.service
    # systemctl daemon-reload
    # systemctl reset-failed
    # rm /lib/systemd/system/php-5.4.45-fpm.service
    # systemctl daemon-reload

    Далее в каталоге /opt/php-5.4.45/etc/php-fpm.d/ создаем файл пула php-fpm с именем к примеру mysite.conf
    Содержание mysite.conf например такое (mysiteuser и mysitegroup - это имена системного пользователя и группу от имени которых будет работать данный пулл, в php_admin_value[open_basedir] указывается путь до корневого каталога сайта, на этот каталог у mysiteuser и mysitegroup должны быть полные права):

    [mysite]
    listen = /var/lib/php5-fpm/mysite.sock
    listen.owner = mysiteuser
    listen.group = mysitegroup
    listen.mode = 0660
    user = mysiteuser
    group = mysitegroup
    pm = dynamic
    pm.max_children = 8
    pm.start_servers = 2
    pm.min_spare_servers = 1
    pm.max_spare_servers = 5
    pm.max_requests = 500
    chdir = /
    php_admin_value[open_basedir] = /var/www/mysite/web:/usr/share/php5:/usr/share/php:/tmp:/usr/share/phpmyadmin:/etc/phpmyadmin:/var/lib/phpmyadmin
    php_admin_value[session.save_path] = /var/www/mysite/tmp
    php_admin_value[upload_tmp_dir] = /var/www/mysite/tmp

    После рестартуем
    systemctl status php-5.4.45-fpm.service
    или
    /etc/init.d/php-5.4.45-fpm restart

    В настройках nginx в качестве сокета php-fpm указываем /var/lib/php5-fpm/mysite.sock

    Вот как то так.
    Ответ написан
  • Почему php-fpm не находит файл?

    Ошибка "FastCGI sent in stderr: "Primary script unknown" while reading response header from upstream" говорит о том, что Nginx не может найти указанный в файле конфигурации скрипт, речь про эту строку:

    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;


    Рекомендация тут простая - проверьте все пути и убедитесь, что все нужные файлы существуют и лежат на своих местах.

    Конкретно в Вашем случае я не вижу определения директивы root за пределами location / или в нем.

    Если вы не можете разобраться, в каком каталоге Nginx ищет нужный скрипт, то на узле vh2_fphp7.0 запускаете:

    tcpdump port 9000 -A | strings

    Вывод покажет всю нужную информацию, в том числе путь к скрипту.

    Так же можно включить логирование:
    http {
       ...
       log_format scripts '$document_root$fastcgi_script_name > $request';
       server {
       ...
       access_log /var/log/nginx/mysite-scripts.log scripts;
       ...
       }
    }


    Так же возможно вы неправильно написали регулярку в директиве fastcgi_split_path_info, см. оф. документацию.

    Так же проверьте значение cgi.fix_pathinfo = 1 (в некоторых мануалах советуют cgi.fix_pathinfo = 0 что может привести к не правильной обработке переменной PHP_SELF не равной DOCUMENT_URI).

    Кстате строки

    if (!-f $document_root$fastcgi_script_name) {
            return 404;
        }


    по моему абсолютно излишни, уберите их или используйте try_files.
    Я конечно понимаю, что сами разработчики Nginx в этой статье написали так..., но....

    location ~ \.php$ {
            try_files       $uri = 404;
            fastcgi_pass    127.0.0.1:9001;
            include         /etc/nginx/fastcgi_params;
            fastcgi_index   index.php;
            fastcgi_param   SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
    Ответ написан
  • Почему медленно работает сайт?

    listen = 127.0.0.1:9001


    1. Используйте unix socket, это увеличит скорость работы связки nginx + php-fpm

    Пример пула php-fpm:

    [site.ru]
    listen = /var/lib/php5-fpm/siteru.sock
    listen.owner = site
    listen.group = site
    listen.mode = 0660
    ...


    Пример настройки nginx:
    location ~ \.php$ {
      ...
      fastcgi_pass unix:/var/lib/php5-fpm/siteru.sock;
      ...
    }


    pm = ondemand


    2. Используйте модель dynamic, при ondemand скорее всего вы упираетесь в pm.max_children

    Пример для dynamic:

    pm = dynamic
    pm.max_children = 10
    pm.start_servers = 2
    pm.min_spare_servers = 1
    pm.max_spare_servers = 5
    pm.max_requests = 500


    3. Включите лог медленных запросов на mysql, включите дебаг в yii2, включите отладочные логи на php-fpm

    Пример включения отладочных логов для php-fpm:
    ; Перенаправлять вывод процесса в лог
    catch_workers_output = yes
    ; Если скрипт выполняется больше указанного времени, писать отладочную информацию в slowlog
    request_slowlog_timeout = 3
    ; Лог-файл для медленных запросов
    slowlog = /var/log/fpm-php/siteru.slow.log
    Ответ написан
  • Какие прорехи в безопасности могут быть в конфигурации nginx?

    1. Постоянный редирект с / на index.php

    location = / {
            rewrite ^ $scheme://$host/index.php permanent;
        }
    
        location / {
            deny all;
            return 404;
        }
        location ~* ^/index\.php$ {
            try_files $uri $uri/ =404;
            fastcgi_index index.php;
            fastcgi_pass php5-fpm-sock;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            include /etc/nginx/fastcgi_params;
        }



    Очень странная логика, особенно использование $host и некорректное использование try_files. Про try_files почитайте тут.

    $host
    в порядке приоритета: имя хоста из строки запроса, или имя хоста из поля “Host” заголовка запроса, или имя сервера, соответствующего запросу


    Если у вас не определен default_server и server_name site.ru; стоит первым в списке, то к вам будут прилетать все запросы с любым полем Host, в том числе пустым, что является очень опасной практикой.
    Лучше использовать переменную $server_name, но все равно, если вам нужно обращения по любым url обрабатывать только через index.php, то правильно это делается так:

    /NONEXISTENTFILE меняете на заранее фейковый файл который не может существовать, например /d7sdhsdhsdf8sfhgsfd8fh438dfjh

    ...
            error_page 404 = @cms;
    
            location / {
                try_files /NONEXISTENTFILE @cms;
            }
    
            location @cms {
                    fastcgi_pass      unix:/var/lib/php5-fpm/xxxxx.sock;
                    fastcgi_index    index.php;
                    fastcgi_param   SCRIPT_FILENAME $document_root/index.php;
                    fastcgi_param   SCRIPT_NAME /index.php;
                    include             /etc/nginx/fastcgi_params;
            }
    ...


    2. Запрещаем любую статику кроме gif|jpg|png|js|css|ttf|woff|ico
    location ~* \.(gif|jpg|png|js|css|ttf|woff|ico)$ {
            try_files $uri =404;
            expires 30d;
        }



    Логичнее и правильнее будет сделать так:

    try_files $uri =404; нам не понадобится, т.к. у нас есть error_page 404 = @cms; который в случае отсутствия картинки перенаправит запрос в @cms

    ...
            error_page 404 = @cms;
    
            location ~* ^.+\.(gif|jpg|png|js|css|ttf|woff|ico)$ {
                    expires 30d;
                    access_log off;
                    log_not_found off;
            }
    
            location / {
                try_files /NONEXISTENTFILE @cms;
            }
    ...


    По поводу json.php и в принципе ограничения доступа, правильнее делать это через map или geo, например так:

    http {
    ....
            geo $my_client_ip $denied {
                    default 1;
                    127.0.0.1 0;
                    XX.XX.XX.XX 0; # <- IP1 с которого можно заходить
                    YY.YY.YY.YY 0;    # <- IP2 с которого можно заходить
            }
    
    server {
            listen       443 ssl;
            server_name  site.ru;
            root         /var/www/html/;
    ...
            set $my_client_ip $remote_addr;
            if ($http_x_forwarded_client_ip ~ "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}") {
                    set $my_client_ip $http_x_forwarded_client_ip;
            }
    
            error_page 403 = @deny;
    
            location @deny {
                    root /var/www/deny;
                    rewrite ^(.*)$ /index.html break;
            }
    
            location ~* ^/json\.php$ {
                    if ($denied) {
                            return 403;
                    }
                    try_files /NONEXISTENTFILE @json;
            }
    
            location @json {
                    try_files       $uri = 404;
                    fastcgi_pass    unix:/var/lib/php5-fpm/xxxxx.sock;
                    fastcgi_index   index.php;
                    fastcgi_param   SCRIPT_FILENAME $document_root$fastcgi_script_name;
                    include         /etc/nginx/fastcgi_params;
            }
    
    }
    }


    4. Разрешаем доступ к /admin только с 1-го IP, для /admin/phpmyadmin


    Не делайте так! Организуйте для phpMyAdmin отдельный поддомен с отдельным виртуальным сервером и отдельной обработкой php5-fpm через отдельный сокет.
    Никогда не храните "левые" (вспомогательные) утилиты в общем каталоге web-приложения, это плохая практика. К примеру: Если в phpMyAdmin будет найдена критическая уязвимость, то даже в случае ограничения доступа к нему с определенного IP существует вероятность, что она может быть проэксплуатирована и тогда через неё поломают ваше web-приложение - оно вам нужно?

    По поводу location ~* /admin/ аналогично как для json.php.

    Ну и все рекомендации выше от Кирилл Несмеянов относительно hsts, ssl, ciphers, dh, ocsp stapling поддерживаю.
    Ответ написан
  • Как правильно организовать балансировку нагрузки?

    Если Вы уверены, что Web-приложение справляется с нагрузкой, то возможно на балансировщике стоит увеличить таймауты, добавьте в location /

    proxy_connect_timeout 120s;
    proxy_send_timeout 120s;
    proxy_read_timeout 120s;


    На 3-х вебсерверах если Вы используете php-fpm то лучше работать через unix-сокеты, а не через tcp, через сокеты будет быстрее.

    Возможно стоит посмотреть в сторону параметра least_conn в upstream, то есть запросы сначала будут отправляются бэкенду с наименьшим количеством активных подключений (но с учетом весов). Подробнее тут.
    Если какой-то бэкенд мощнее других, то используйте определение веса через weight
    Так же настройте директивы max_fails и fail_timeout в блоке upstream (в моем примере ниже параметры проставлены для примера).

    Так же включите логи на балансировщике, это сильно упростит отладку:

    http {
        ...
        log_format upstream_log '[$time_local] $remote_addr - $remote_user - $server_name to: $upstream_addr: $request upstream_response_time $upstream_response_time msec $msec request_time $request_time';
    
    upstream servers {
                    least_conn;
                    server ip1;
                    server ip2 max_fails=3 fail_timeout=30s;
                    server ip3 max_fails=5 fail_timeout=30s;
                    keepalive 16;
            }
    
    server {
                    listen 80;
                    access_log /var/log/nginx/servers-access.log upstream_log;
                    error_log /var/log/nginx/servers-error.log debug;
    
                    location / {
                            proxy_pass http://servers;
                            proxy_http_version 1.1;
                            proxy_set_header Connection "";
                            proxy_connect_timeout 120s;
                            proxy_send_timeout 120s;
                            proxy_read_timeout 120s;
            }
    }
    Ответ написан