# Apache httpd - веб-сервер
_Протоколы · LinuxLab Knowledge Base_
**TL;DR:** Apache httpd - веб-сервер. На RHEL пакет `httpd`, конфиг `/etc/httpd/conf/httpd.conf`.
На Debian/Ubuntu пакет `apache2`, конфиг `/etc/apache2/apache2.conf` + `sites-enabled/`.
## Apache vs nginx - когда что
В современном Linux два мейнстрим веб-сервера:
- **Apache** - process-per-request (worker/event MPM), модульный, `.htaccess`,
PHP через mod_php. Стандарт для shared hosting, LAMP-стека, легаси.
- **nginx** - event-driven, легче на ресурсах, проще конфиг, лучше для
static + reverse proxy.
Apache всё ещё имеет смысл когда:
- Нужны `.htaccess`-овые правки силами user'ов без рестарта.
- mod_*-экосистема (mod_wsgi, mod_authnz_ldap, mod_security).
- Готовый продукт ожидает Apache (ZendServer, cPanel, mailman).
В остальных случаях - nginx или Caddy.
## Установка - пакетные различия
| Дистрибутив | Пакет | Демон | Конфиг | run-as |
|-----------------|-----------|----------------|------------------------------------------------|----------|
| RHEL/Fedora | `httpd` | `httpd` | `/etc/httpd/conf/httpd.conf` + `conf.d/` | `apache` |
| Debian/Ubuntu | `apache2` | `apache2` | `/etc/apache2/apache2.conf` + `sites-enabled/` | `www-data` |
```bash
# RHEL
sudo dnf install httpd
sudo systemctl enable --now httpd
# Debian
sudo apt install apache2
sudo systemctl enable --now apache2
```
Дальше `httpd` для краткости, на Debian замени на `apache2`.
## Структура каталогов на Debian (модель «sites-available»)
```
/etc/apache2/
├── apache2.conf ← главный, читает все остальные
├── ports.conf ← Listen 80, 443
├── conf-available/ ← фрагменты
├── conf-enabled/ ← симлинки на активные
├── mods-available/ ← все модули (.load + .conf)
├── mods-enabled/ ← симлинки на активные модули
├── sites-available/ ← конфиги virtual host'ов
│ ├── 000-default.conf
│ └── example.org.conf
└── sites-enabled/ ← симлинки на активные
└── example.org.conf -> ../sites-available/example.org.conf
```
Активация через утилиты:
```bash
sudo a2ensite example.org # symlink в sites-enabled
sudo a2dissite example.org # снять
sudo a2enmod ssl rewrite # включить модули
sudo a2dismod autoindex
sudo systemctl reload apache2
```
RHEL такого разделения **нет** - все конфиги дропаются в `/etc/httpd/conf.d/*.conf`,
модули загружаются через `LoadModule` в `/etc/httpd/conf.modules.d/*.conf`.
## Process model - почему root и www-data одновременно
Apache **стартует от root** чтобы открыть [[capabilities|порты <1024]]
(80, 443 требуют CAP_NET_BIND_SERVICE), потом **fork'ает worker'ов как
unprivileged user** (`www-data` или `apache`).
```bash
ps -ef | grep httpd
# root 1234 1 0 /usr/sbin/httpd -DFOREGROUND ← parent (master)
# apache 1235 1234 0 /usr/sbin/httpd -DFOREGROUND ← worker
# apache 1236 1234 0 /usr/sbin/httpd -DFOREGROUND ← worker
```
Worker'ы обрабатывают запросы. Если в них уязвимость - exploit имеет
только права `apache`, не root. Поэтому `/var/www/html/` должна быть
читаемая `apache`, но не writable (иначе RCE → запись на диск).
## VirtualHost - несколько сайтов на одном IP
Один хост может обслуживать несколько доменов на одном IP по `Host:`
заголовку из HTTP/1.1.
```apache
# /etc/apache2/sites-available/example.org.conf
ServerName example.org
ServerAlias www.example.org
DocumentRoot /var/www/example.org
ErrorLog ${APACHE_LOG_DIR}/example.org-error.log
CustomLog ${APACHE_LOG_DIR}/example.org-access.log combined
Options -Indexes +FollowSymLinks
AllowOverride All # разрешить .htaccess
Require all granted
```
Подвохи:
- **Первый VirtualHost = default**: запросы с неизвестным `Host:` падают
в него. Часто хочется default-конфиг с 444 ответом для защиты от
«спам-запросов на IP».
- **`*:80` vs `IP:80`** - `*` ловит все интерфейсы; явный IP - только этот.
- **`` vs `` vs ``** - каталог на диске vs
URL-путь vs паттерн файла. Путать опасно: правила контроля доступа
могут не сработать.
## HTTPS - mod_ssl + Let's Encrypt
```bash
# 1. Включить модуль
sudo a2enmod ssl
sudo systemctl reload apache2
# 2. Получить сертификат (certbot пропишет конфиг сам)
sudo apt install certbot python3-certbot-apache
sudo certbot --apache -d example.org -d www.example.org
# certbot создаст:
# /etc/apache2/sites-available/example.org-le-ssl.conf
```
Минимальный SSL-VirtualHost вручную:
```apache
ServerName example.org
DocumentRoot /var/www/example.org
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/example.org/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.org/privkey.pem
# Современные шифры
SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
SSLCipherSuite HIGH:!aNULL:!MD5
SSLHonorCipherOrder on
```
Про сам [tls-handshake](/kb/tls-handshake.md) - отдельная статья.
## Reverse proxy для backend-приложения
```apache
ServerName api.example.org
ProxyPreserveHost On
ProxyPass / http://127.0.0.1:8000/
ProxyPassReverse / http://127.0.0.1:8000/
RequestHeader set X-Forwarded-Proto "http"
```
Нужны модули `proxy` и `proxy_http`:
```bash
sudo a2enmod proxy proxy_http
```
Backend (uvicorn/gunicorn/etc.) слушает loopback:8000, Apache на 80/443
отдаёт TLS, заголовки и rate-limit'ы.
## .htaccess - правила per-каталог без перезагрузки
Основная фича Apache - файл `.htaccess` в любом каталоге может содержать
директивы конфига и применяется БЕЗ рестарта сервера. Удобно для
shared hosting'а где user-у дают только FTP-доступ.
```apache
# /var/www/example.org/.htaccess
Options -Indexes
ErrorDocument 404 /404.html
RewriteEngine On
RewriteRule ^old-page$ /new-page [R=301,L]
```
Чтобы это работало - в VirtualHost должно стоять `AllowOverride All`
для каталога. По умолчанию - `None` (.htaccess игнорируется).
Цена: Apache **читает .htaccess на каждый запрос** в этой иерархии.
На high-load - выключай и переноси правила в основной конфиг.
## Управление
```bash
sudo systemctl reload httpd # перечитать конфиг без обрыва соединений
sudo systemctl restart httpd # полный рестарт
sudo apachectl configtest # проверка синтаксиса (== httpd -t)
sudo apachectl -S # показать все VirtualHost'ы и их правила
sudo apachectl -M # список загруженных модулей
```
**Всегда** `configtest` перед `reload`. Иначе syntax error → демон не
перезапустится, и сайт ляжет.
## Логи
RHEL: `/var/log/httpd/{access,error}_log`.
Debian: `/var/log/apache2/{access,error}.log`.
```bash
sudo tail -f /var/log/apache2/error.log # ошибки в реалтайме
sudo tail -f /var/log/apache2/access.log # запросы
```
Формат `combined` (default):
```
192.168.0.5 - - [29/Apr/2026:14:23:11 +0300] "GET / HTTP/1.1" 200 1234 "-" "Mozilla/5.0..."
↑ ↑ ↑ ↑
client request code size
```
Logrotate конфиг обычно `/etc/logrotate.d/httpd` ротирует daily/weekly.
## Безопасность - обязательный минимум
1. **Не запускать как root postfork**: убедись `User apache` / `User www-data`
стоит в конфиге.
2. **Скрыть версию**: `ServerTokens Prod` + `ServerSignature Off` в
`apache2.conf`.
3. **Отключить листинг каталогов**: `Options -Indexes` для всех ``.
4. **Запретить .git/.env**: `` + `Require all denied`.
5. **HSTS**: `Header always set Strict-Transport-Security "max-age=63072000"`.
6. **[fail2ban](/kb/fail2ban.md)** на лог error.log - банить тех кто долбит 404 и 401.
7. **mod_security** + OWASP ruleset - WAF для типичных атак.
## Дебаг - типичные проблемы
```bash
# 1. Запущен?
systemctl status httpd
ss -tlnp 'sport = :80' # слушает порт?
# 2. Куда идут логи в реалтайме
sudo tail -F /var/log/httpd/error_log
# 3. Какой VirtualHost матчится для имени
sudo apachectl -S | grep example.org
# 4. Простой curl-тест
curl -I http://localhost
curl -kvI https://example.org
```
Частые ошибки:
- **403 Forbidden** на чистом сайте → SELinux на RHEL. Проверить
`ls -Z /var/www/html` - нужен контекст `httpd_sys_content_t`.
`sudo restorecon -R /var/www/html`.
- **Permission denied** в логе → `apache`/`www-data` не может прочитать
DocumentRoot. `chmod o+rX -R` или нужный ACL.
- **Address already in use** при старте → кто-то другой уже на 80
(`ss -tlnp 'sport = :80'` найдёт).
## Команды
```bash
sudo apachectl configtest
```
Проверка синтаксиса конфига перед reload - обязательно, иначе сайт упадёт
```bash
sudo apachectl -S
```
Показать все VirtualHost'ы и какой выбран по умолчанию - диагностика matching'а
```bash
sudo a2ensite example.org && sudo systemctl reload apache2
```
Активировать VirtualHost из sites-available на Debian - symlink + reload
```bash
sudo certbot --apache -d example.org
```
Получить Let's Encrypt сертификат и автоматически настроить SSL-VirtualHost
```bash
sudo tail -F /var/log/apache2/error.log
```
Реалтайм лог ошибок - главный инструмент дебага 500/403/permissions
## См. также
- [TLS handshake](/kb/tls-handshake.md)
- [HTTP/1.1, HTTP/2, HTTP/3](/kb/http-protocol.md)
- [curl - HTTP-клиент из терминала](/kb/cmd-curl.md)
- [fail2ban - автобан по логам](/kb/fail2ban.md)
- [systemd - init и менеджер сервисов](/kb/systemd.md)