# Сигурна конфигурация на Nginx за PHP

> Сигурен Nginx за PHP: предавайте на PHP-FPM само истински скриптове, освободете front controller, блокирайте скритите файлове и задайте лимити.

Източник: https://phpsos.de/bg/blog/nginx-fuer-php-absichern/  
Актуалност: 25.10.2026  
Доставчик: PHP SOS, Спешна помощ за PHP и сигурност на сървъри. Незабавна помощ по WhatsApp: https://wa.me/491736494914?text=%D0%97%D0%B4%D1%80%D0%B0%D0%B2%D0%B5%D0%B9%D1%82%D0%B5%2C%20PHP%20SOS%2C%20%D0%B8%D0%BC%D0%B0%D0%BC%D0%B5%20%D0%BD%D1%83%D0%B6%D0%B4%D0%B0%20%D0%BE%D1%82%20%D0%BF%D0%BE%D0%BC%D0%BE%D1%89%20%D1%81%20%D0%BD%D0%B0%D1%88%D0%B8%D1%8F%20PHP%20%D1%81%D1%8A%D1%80%D0%B2%D1%8A%D1%80.%20%D0%A4%D0%B8%D1%80%D0%BC%D0%B0%3A%20%E2%80%A6%20%D0%A3%D0%B5%D0%B1%D1%81%D0%B0%D0%B9%D1%82%3A%20%E2%80%A6

**Накратко:** За да конфигурирате Nginx за PHP сигурно, предавайте към PHP-FPM само скриптове, които наистина съществуват, а при приложения с front controller дори само `index.php`. Към това се добавят блокирани скрити файлове като `.git` и `.env`, сървър по подразбиране за непознати имена на хостове, подходящи лимити за размер и `security.limit_extensions = .php` в пула. Това не защитава от уязвимости в самия PHP, но ограничава какво може да се изпълни след грешка.

## Най-опасните редове са в PHP location

След PHP2Shell много екипи проверяват версиите и пуловете на PHP-FPM, както е описано на страницата [Защита на Nginx с PHP-FPM](https://phpsos.de/bg/server/nginx-php-fpm/), и след актуализацията [рестартират всички worker процеси](https://phpsos.de/bg/php2shell/php-fpm-neustart/). Втори поглед заслужава самата конфигурация на Nginx. Именно там се решава кои файлове изобщо се изпълняват като PHP.

В много конфигурации има блок, който предава всяка заявка към `.php` на PHP-FPM, независимо къде е файлът. Ако внедрен PHP файл попадне в папка за качване, сървърът го изпълнява. Така от грешка във файловете става задна врата.

Тази статия се фокусира върху страната на Nginx: кои директиви имат значение, как действа редът на блоковете location и как да тествате резултата.

## Как Nginx решава кой блок се прилага

Който иска да конфигурира Nginx сигурно за PHP, трябва да познава избора на блокове location. Според документацията на Nginx той протича така:

1. Точно съвпадение с `location =` прекратява търсенето веднага.
2. Сред префиксните location се запомня най-дългото подходящо. Ако носи `^~`, регулярните изрази повече не се проверяват.
3. Иначе регулярните изрази (`~`, `~*`) се проверяват в реда на конфигурационния файл; първото съвпадение печели.
4. Ако никой регулярен израз не съвпадне, важи запомненото префиксно location.

От това следват две практически правила. Блокиране на PHP в папки за качване трябва да се направи или като префикс `^~`, или като регулярен израз пред общия PHP блок. А обикновено префиксно location като `location /uploads/` не защитава, защото регулярният израз за `.php` го надделява.

## Сигурна основна конфигурация

Следният пример показва блок server за приложение с front controller, както е обичайно при Laravel, Symfony, Shopware 6 или много собствени разработки. Пътищата, сокета и сертификатите адаптирайте.

```nginx
server {
    listen 443 ssl;
    server_name www.example.de;
    root /var/www/seite1/public;
    index index.php;

    ssl_certificate     /etc/ssl/seite1/fullchain.pem;
    ssl_certificate_key /etc/ssl/seite1/privkey.pem;

    server_tokens off;
    client_max_body_size 32m;

    # Разрешаване на Let's Encrypt и други известни пътища
    location ^~ /.well-known/ {
        try_files $uri =404;
    }

    # Блокиране на скрити файлове и папки (.git, .env, .htaccess)
    location ~ /\. {
        deny all;
    }

    location / {
        try_files $uri $uri/ /index.php$is_args$args;
    }

    # Само front controller се предава на PHP-FPM
    location = /index.php {
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        fastcgi_param DOCUMENT_ROOT $realpath_root;
        fastcgi_hide_header X-Powered-By;
        fastcgi_pass unix:/run/php/seite1.sock;
    }

    # Всеки друг PHP файл не се изпълнява
    location ~ \.php$ {
        return 404;
    }
}
```

`$realpath_root` разрешава символните връзки. Това е важно при внедрявания със сменяща се символна връзка към текущия release, за да виждат PHP-FPM и OPcache правилния път. Имайте предвид освен това: според документацията на Nginx директивите `fastcgi_param` се наследяват от по-високи нива само ако на текущото ниво няма собствени. Затова `include fastcgi_params;` принадлежи в същия блок.

Класически CMS като WordPress, TYPO3 или Contao имат няколко входни точки. Там заменяте блока на front controller с общо PHP location, което предава само съществуващи файлове (`try_files $uri =404;`), и блокирате изпълнението във всички папки, в които може да се пише. Как да го постигнете, е описано в [Забрана за изпълнение на PHP в папки за качване](https://phpsos.de/bg/blog/php-in-uploads-verbieten/).

## Второто осигуряване в PHP-FPM

Nginx решава какво се предава, PHP-FPM решава какво изпълнява. Според ръководството на PHP PHP-FPM по подразбиране изпълнява файлове с `.php` и `.phar` и само препоръчва това да се ограничи до `.php`. Така се прихващат грешки в конфигурацията на уеб сървъра.

```ini
; в пула, напр. /etc/php/8.3/fpm/pool.d/seite1.conf
security.limit_extensions = .php
listen = /run/php/seite1.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
```

Сокетът трябва да е достъпен само за Nginx. Портовете на FPM в мрежата, например `9000`, не трябва да се отварят навън. Как сървърът като цяло показва само необходимите портове, описва [Защитна стена за уеб сървъри: отваряйте само необходимите портове](https://phpsos.de/bg/blog/firewall-fuer-webserver/).

## Непознати имена на хостове и други регулатори

Без собствен сървър по подразбиране Nginx отговаря на заявки към непознати имена на хостове с първия подходящ блок server. Автоматизирани сканирания, които адресират само IP адреса, попадат тогава директно във Вашето приложение. Собственият сървър по подразбиране прекратява такива заявки без отговор.

```nginx
server {
    listen 80 default_server;
    listen 443 ssl default_server;
    server_name _;
    ssl_reject_handshake on;
    return 444;
}
```

Други доказали се точки:

| Регулатор | Препоръка | Цел |
|---|---|---|
| `server_tokens` | `off` | без номер на версия в заглавията и страниците с грешки |
| `client_max_body_size` | съобразено с `post_max_size` | ранно отхвърляне на големи заявки |
| `autoindex` | изключено (по подразбиране) | без списъци на директории |
| `fastcgi_hide_header` | `X-Powered-By` | без версия на PHP навън |
| Статус страници | `pm.status_path` само вътрешно | без публични оперативни данни |
| Резервни файлове | блокирайте или премахнете `.sql`, `.zip`, `.bak` в уеб корена | без изтегляне на бази данни |

Повече за данните за версиите има в статията [expose_php и Server заглавия](https://phpsos.de/bg/blog/expose-php-versionsangaben/).

Друг регулатор засяга позволените HTTP методи. Повечето уебсайтове се нуждаят само от GET, HEAD и POST. С `limit_except` други методи могат да се отхвърлят в един location; според документацията на Nginx разрешаването на GET автоматично разрешава и HEAD. Проверете предварително дали интерфейсите на Вашето приложение използват например PUT или DELETE, защото REST API често го правят.

## Тествайте, преди да презаредите

Всяка промяна проверявайте първо с `nginx -t` и презареждайте Nginx едва след това. После тествайте поведението отвън с нормални заявки към Вашия собствен домейн:

```bash
sudo nginx -t && sudo systemctl reload nginx
# Очаква се: 403 или 404
curl -s -o /dev/null -w "%{http_code}\n" https://www.example.de/.git/HEAD
curl -s -o /dev/null -w "%{http_code}\n" https://www.example.de/.env
# Очаква се: 404, защото се изпълнява само front controller
curl -s -o /dev/null -w "%{http_code}\n" https://www.example.de/info.php
# Кои блокове предават към PHP-FPM?
sudo nginx -T 2>/dev/null | grep -nE "location|fastcgi_pass"
```

Преди всяка по-голяма промяна запазвайте пълния изход на `nginx -T` с дата. Той съдържа цялата действаща конфигурация, включително всички включени файлове. Ако след промяна нещо се обърка, сравнението показва веднага какво се различава. При следващата критична уязвимост имате освен това надеждна основа за отчитане на наличното, без да събирате файловете.

> **Съвет:**
> Променяйте конфигурацията първо в тестова среда или върху копие на блока server. Забравена входна точка, например callback за плащане, иначе се забелязва едва когато поръчките спрат.

## Как помага PHP SOS конкретно?

- **Четене на конфигурацията:** анализираме цялата конфигурация на Nginx с `nginx -T` и свързваме всяко предаване към PHP със съответния сайт и пул.
- **Определяне на входните точки:** заедно с Вашите разработчици определяме кои скриптове трябва да се изпълняват и блокираме останалото.
- **Прилагане и тестване:** адаптираме блоковете server и пуловете, проверяваме с `nginx -t` и тестваме формуляри, платежни пътища и качвания.
- **Трайно осигуряване:** конфигурацията става част от нашето [заздравяване на сървъра](https://phpsos.de/bg/leistungen/server-haertung/) и от документацията на Вашия сървър.


## Често задавани въпроси

**Трябва ли Nginx да се рестартира след актуализация на PHP?**  
За пача на PHP не, защото Nginx не съдържа PHP. Трябва да се рестартират всички услуги PHP-FPM. Ако при това променяте и конфигурацията на Nginx, проверете я предварително с nginx -t и след това презаредете Nginx.

**Защо да предавам само index.php към PHP?**  
Много съвременни приложения имат една-единствена входна точка, front controller. Ако към PHP-FPM се предава само този файл, внедрен PHP файл на друго място не може да се изпълни през браузъра. При системи с много входни точки този модел не е възможен.

**Какво носи security.limit_extensions в PHP-FPM?**  
Настройката определя кои разширения на файлове PHP-FPM изпълнява като скрипт. Според ръководството на PHP по подразбиране са .php .phar; препоръчва се ограничаване до .php. Това прихваща грешки в конфигурацията на уеб сървъра, но не я замества.

**Защита срещу PHP2Shell ли са правилата на Nginx?**  
Не. PHP2Shell е в интерпретатора на PHP и се затваря само чрез актуализация до коригирана версия и рестартиране на всички worker процеси. Сигурната конфигурация на Nginx намалява повърхността за атака и ограничава щетите след пробив.

## Източници

- [Nginx: ngx_http_core_module](https://nginx.org/en/docs/http/ngx_http_core_module.html)
- [Nginx: ngx_http_fastcgi_module](https://nginx.org/en/docs/http/ngx_http_fastcgi_module.html)
- [Ръководство на PHP: конфигурация на FPM](https://www.php.net/manual/en/install.fpm.configuration.php)
- [OWASP Cheat Sheets](https://cheatsheetseries.owasp.org/)
