Apache не запускается с ошибкой No space left on device, хотя df -h показывает свободное место. Обычно диск тут ни при чём. Код ошибки 28 (ENOSPC) ядро возвращает и тогда, когда кончились семафоры System V. Apache использует их как мьютексы между своими процессами. Если Apache падал и не успел их удалить, «осиротевшие» семафоры копятся, пока ядро не откажет в новых.
Самое частое решение: остановить Apache, найти командой ipcs -s семафоры пользователя веб-сервера, удалить их командой ipcrm и запустить Apache снова. Чтобы проблема не вернулась, переводим Apache на мьютексы, которые не текут, директивой Mutex, и ищем, почему Apache падает. Повышать лимиты в kernel.sem на современных ядрах обычно не нужно.
Статья написана по двум старым заметкам 2012–2017 годов про CentOS 5/6 и Apache 2.2 и переработана для Apache 2.4 на Debian 12 и 13, Ubuntu 24.04 и AlmaLinux / Rocky Linux 9 и 10.
Как выглядит ошибка
В Apache 2.2 сообщение было таким:
[emerg] (28)No space left on device: Couldn't create accept lock (/etc/httpd/logs/accept.lock.12345)
В Apache 2.4 мьютексы переписали, и текст другой. В названии указано, какой мьютекс не удалось создать:
[core:emerg] [pid 12345] (28)No space left on device: AH00023: Couldn't create the mpm-accept mutex
[core:emerg] [pid 12345] (28)No space left on device: AH00023: Couldn't create the ssl-cache mutex
Иногда в журнале нет ничего полезного, только Configuration Failed. Так было в одном из исходных случаев автора: проверка синтаксиса проходила, режим отладки ничего не давал. Причину показал strace:
strace -f -o /tmp/trace.txt /usr/sbin/httpd -DFOREGROUND
grep ENOSPC /tmp/trace.txt
Примерно так выглядела нужная строка:
semget(IPC_PRIVATE, 1, IPC_CREAT|0600) = -1 ENOSPC (No space left on device)
Системный вызов semget создаёт семафор System V. ENOSPC от него означает «превышен лимит семафоров», а не «нет места на диске». На Debian и Ubuntu бинарник называется /usr/sbin/apache2, и запускать его напрямую лучше через apache2ctl, чтобы подхватились переменные из /etc/apache2/envvars.
Где смотреть журналы
| Что | Debian, Ubuntu | AlmaLinux, Rocky |
|---|---|---|
| Сервис | apache2.service | httpd.service |
| Журнал ошибок | /var/log/apache2/error.log | /var/log/httpd/error_log |
| Журнал systemd | journalctl -u apache2 -n 50 | journalctl -u httpd -n 50 |
| Проверка конфигурации | apache2ctl configtest | apachectl configtest |
| Каталог lock-файлов | /var/lock/apache2 (APACHE_LOCK_DIR) | /run/httpd |
Старое сообщение CentOS 6 httpd dead but subsys locked в системах с systemd не встречается. Теперь сервис просто переходит в состояние failed, а причину видно в systemctl status и журнале.
Шаг 1. Убедиться, что дело не в диске
Ошибка 28 бывает и настоящей. Прежде чем трогать семафоры, исключите очевидное:
df -h / /var /run /dev/shm
df -i / /var /run
Обратите внимание на df -i. Кончившиеся inode тоже дают No space left on device при свободных гигабайтах. Чаще всего их съедают миллионы мелких файлов сессий PHP или кэша. Если мьютексы Apache работают через файлы, они создаются в каталоге lock-файлов, и переполненный /run (это tmpfs в памяти) даст ту же ошибку. POSIX-семафоры живут в /dev/shm, его заполнение тоже проявится как ENOSPC.
Шаг 2. Посмотреть семафоры
ipcs -s
Вывод примерно такой:
------ Semaphore Arrays --------
key semid owner perms nsems
0x00000000 32768 www-data 600 1
0x00000000 32769 www-data 600 1
0x00000000 32770 www-data 600 1
...
Владелец — пользователь, от которого работает Apache: www-data на Debian и Ubuntu, apache на AlmaLinux. Посчитать семафоры по владельцам:
ipcs -s | awk 'NR>3 && NF {print $3}' | sort | uniq -c | sort -rn
И сравнить с лимитами ядра:
ipcs -ls
sysctl kernel.sem
Параметр kernel.sem — это четыре числа: SEMMSL (семафоров в одном наборе), SEMMNS (всего семафоров в системе), SEMOPM (операций за один вызов) и SEMMNI (наборов в системе). Apache на каждый мьютекс создаёт один набор, поэтому упирается обычно в последнее число.
Если Apache остановлен, а семафоров его пользователя сотни или тысячи — это утечка. Работающий Apache держит лишь несколько наборов.
Шаг 3. Удалить осиротевшие семафоры
Сначала полностью остановите Apache. Удалять семафоры работающего сервера нельзя: процессы, которые их используют, начнут сбоить.
# Debian, Ubuntu
systemctl stop apache2
pgrep -a apache2 # должно быть пусто
# AlmaLinux, Rocky
systemctl stop httpd
pgrep -a httpd
Удаляем только семафоры пользователя веб-сервера. Для AlmaLinux замените www-data на apache:
ipcs -s | awk '$3 == "www-data" {print $2}' | xargs -r -n1 ipcrm -s
Запускаем и проверяем:
systemctl start apache2
systemctl status apache2
ipcs -s
В интернете и в старой версии этой статьи встречается цикл, который удаляет вообще все семафоры в системе:
for id in `ipcs -s | awk '{print $2}'`; do ipcrm -s $id; done
Так делать не стоит. Семафоры System V используют и другие программы: СУБД, сервер приложений, сторонние демоны. Удалив их семафоры, вы сломаете уже работающие сервисы. То же относится к ipcrm --all=sem. Фильтруйте по владельцу.
Шаг 4. Директива Mutex: чтобы семафоры не текли
В Apache 2.4 механизм межпроцессных блокировок задаёт директива Mutex. По умолчанию (Mutex default) механизм выбирает библиотека APR при сборке. Узнать, какой выбран в вашей сборке:
apache2ctl -V | grep SERIALIZE # Debian, Ubuntu
httpd -V | grep SERIALIZE # AlmaLinux, Rocky
Например, Apache 2.4.58 в Ubuntu 24.04 выводит такие строки:
-D APR_USE_PROC_PTHREAD_SERIALIZE
-D APR_USE_PTHREAD_SERIALIZE
-D SINGLE_LISTEN_UNSERIALIZED_ACCEPT
Это значит, что по умолчанию используются мьютексы pthread в разделяемой памяти, а не семафоры System V. Если же вывод содержит APR_USE_SYSVSEM_SERIALIZE, или в конфиге явно стоит Mutex sysvsem, утечка семафоров возможна. Документация Apache прямо предупреждает: семафоры SysV «текут», если процесс падает, не удалив их.
Явный Mutex sysvsem часто приезжает со старыми конфигами при переносе сайтов с CentOS 6. Найдите его:
grep -rn -i '^\s*Mutex' /etc/apache2/ # Debian, Ubuntu
grep -rn -i '^\s*Mutex' /etc/httpd/ # AlmaLinux, Rocky
Директивы Apache 2.2 AcceptMutex, LockFile, RewriteLock и SSLMutex в 2.4 удалены, их заменяет Mutex. Если такие строки остались в конфиге, Apache 2.4 не запустится с ошибкой о неизвестной директиве.
Варианты, которые не оставляют мусора в таблице семафоров:
| Механизм | Что это | Когда подходит |
|---|---|---|
default | Выбор APR; в современных сборках для Linux обычно pthread | Почти всегда. Лучше просто убрать явный Mutex sysvsem |
pthread | Мьютексы POSIX в разделяемой памяти | Linux умеет восстанавливать такой мьютекс после падения процесса |
file:/путь | Блокировка через lock-файл (fcntl или flock) | Надёжно и наглядно; каталог только на локальном диске, не на NFS |
posixsem | Семафоры POSIX в /dev/shm | Работает, но по документации может подвесить сервер, если упал процесс, державший мьютекс |
sysvsem | Семафоры System V | Причина этой ошибки. Использовать только при явной необходимости |
На Debian и Ubuntu в /etc/apache2/apache2.conf уже есть закомментированная строка с файловым вариантом. Её достаточно раскомментировать:
Mutex file:${APACHE_LOCK_DIR} default
На AlmaLinux добавьте файл /etc/httpd/conf.d/mutex.conf:
Mutex file:/run/httpd default
Не кладите lock-файлы в /tmp или /var/tmp. Документация Apache предупреждает: любой пользователь может заранее создать там файл с тем же именем и не дать серверу запуститься. Есть и вторая причина. У сервиса Apache в systemd включён PrivateTmp=true и на Debian, и на AlmaLinux. Сервис видит свой собственный /tmp, а вы из консоли — общий. Если запускать Apache то через systemd, то вручную, lock-файлы окажутся в разных местах, а ошибки будет трудно понять.
Проверяем и перезапускаем:
apache2ctl configtest && systemctl restart apache2 # Debian, Ubuntu
apachectl configtest && systemctl restart httpd # AlmaLinux, Rocky
После перезапуска в каталоге lock-файлов появятся файлы вида mpm-accept.12345, а ipcs -s перестанет пополняться наборами пользователя Apache.
Почему семафоры остаются: ищем причину падений
Apache удаляет свои семафоры при нормальной остановке. Утечка — признак того, что главный процесс завершается аварийно. Мьютекс можно сменить, но причину падений нужно найти:
- OOM killer. Когда кончается память, ядро убивает процессы, иногда и главный процесс Apache. Проверка:
journalctl -k | grep -i -E 'out of memory|killed process'. - Падения модулей.
Segmentation faultв журнале ошибок Apache. Классические виновники — mod_php с проблемным расширением, сторонние модули, собранные под другую версию. Лечится обновлением модуля или переходом с mod_php на PHP-FPM. - Жёсткая остановка.
kill -9по процессам Apache из скриптов «перезапуска», которые писали для старых серверов. Используйтеsystemctl restartилиapachectl graceful. - Сторонние модули со своими семафорами. Не все модули используют общий механизм Apache. Если после смены
Mutexсемафоры продолжают копиться, отключайте подозрительные модули по одному и смотрите наipcs -s.
Переход с mod_php на PHP-FPM убирает сразу две проблемы: Apache работает в режиме event, а PHP падает в своих процессах, не задевая веб-сервер. Как это настроить, описано в статье Несколько версий PHP и PHP-FPM на одном сервере.
Нужно ли повышать kernel.sem
В исходной статье лимиты поднимали так:
kernel.msgmni = 1024
kernel.sem = 250 256000 32 10241
Для ядер CentOS 5 и 6 это имело смысл: по умолчанию там было всего 128 наборов семафоров. С ядра 3.19 значения по умолчанию сильно выросли. На Debian 12 и 13, Ubuntu 24.04 и AlmaLinux 9 и 10 обычно стоит:
$ sysctl kernel.sem
kernel.sem = 32000 1024000000 500 32000
Старые цифры из статей 2010-х годов эти лимиты не повышают, а понижают: 10241 наборов вместо 32000. Не копируйте их. Если вы упёрлись в 32000 наборов, это утечка, и её нужно чистить, а не расширять лимит.
Если поднять лимит всё же нужно (например, этого требует документация другой программы), делайте это отдельным файлом в /etc/sysctl.d, а не правкой /etc/sysctl.conf:
cat > /etc/sysctl.d/90-sem.conf <<'EOF'
kernel.sem = 32000 1024000000 500 32000
EOF
sysctl --system
sysctl kernel.sem
В kernel.sem задаются все четыре числа сразу, поэтому сначала посмотрите текущие значения и меняйте только нужное.
Apache в контейнере
Семафоры System V принадлежат пространству имён IPC. В контейнерах LXC (в том числе в Proxmox VE) и Docker у контейнера своя таблица семафоров. Команда ipcs -s на хосте не покажет семафоры контейнера, смотреть нужно внутри. Лимиты kernel.sem тоже свои у каждого пространства имён. В старых контейнерах OpenVZ лимиты задавал хост, и ошибка часто приходила именно оттуда.
На хосте с systemd 248 и новее можно дать сервису отдельное пространство имён IPC параметром PrivateIPC=yes в override-файле (systemctl edit apache2). Тогда при остановке сервиса его семафоры исчезают вместе с пространством имён. Но и в ipcs -s с хоста их видно не будет, а модули, которые общаются с другими процессами через IPC, перестанут их видеть. Это дополнительная мера, а не замена правильной директиве Mutex.
Симптомы, причины и решения
| Симптом | Причина | Решение |
|---|---|---|
(28)No space left on device: AH00023: Couldn't create the ... mutex, место на диске есть | Кончились наборы семафоров System V | Остановить Apache, удалить семафоры его пользователя через ipcrm, сменить Mutex |
То же, ipcs -s почти пуст | Файловый мьютекс, переполнен /run или кончились inode; переполнен /dev/shm при posixsem | df -h, df -i, освободить место |
Только Configuration Failed в журнале | Причина скрыта, часто те же семафоры | strace -f, искать ENOSPC |
| Семафоры копятся снова через дни или недели | Аварийное завершение Apache: OOM, segfault модулей, kill -9 | Найти причину падений в журналах, перейти на PHP-FPM |
| Apache 2.4 не стартует после переноса конфига с 2.2 | Директивы AcceptMutex, LockFile, RewriteLock, SSLMutex | Заменить на Mutex |
| Ошибка только внутри контейнера | Лимиты IPC пространства имён контейнера | Чистить и смотреть ipcs внутри контейнера |
Частые вопросы
Почему ошибка говорит про место на диске, если дело в семафорах?
Ядро Linux возвращает один и тот же код ошибки ENOSPC в разных ситуациях. Для semget он означает, что превышен лимит наборов семафоров или семафоров в системе. Apache просто печатает стандартный текст этого кода — No space left on device. Поэтому df ничего не показывает.
Безопасно ли удалять семафоры командой ipcrm?
Безопасно, если Apache остановлен и вы удаляете только семафоры его пользователя (www-data или apache). Опасно удалять все семафоры подряд: среди них могут быть семафоры работающих СУБД и других сервисов. Удалённый семафор восстановить нельзя, программа, которая его использовала, начнёт сбоить до перезапуска.
Помогает ли перезагрузка сервера?
Да, семафоры System V живут в памяти ядра и исчезают при перезагрузке. Но это то же самое, что удалить их вручную, только с простоем всех сервисов. И если Apache продолжит падать, через какое-то время ошибка вернётся. Перезагрузка лечит симптом, директива Mutex и поиск причины падений — проблему.
Встречается ли эта ошибка на Nginx?
Практически нет. Nginx не использует семафоры System V для синхронизации своих процессов. Если вы видите No space left on device у Nginx, ищите настоящую нехватку места или inode: под кэш, временные файлы или журналы.
Нужно ли отключать SELinux, если Apache не стартует?
Нет. В исходном случае автора setenforce 0 проверяли «на всякий случай», и он ничего не изменил: SELinux к семафорам отношения не имеет. Отключать SELinux целиком ради диагностики не нужно. Если подозреваете его, посмотрите отказы командой ausearch -m avc -ts recent на AlmaLinux и исправьте конкретное правило или контекст файлов.
Какой механизм Mutex выбрать на новом сервере?
Ничего не выбирать и оставить Mutex default: в современных сборках Apache для Linux это обычно pthread, и семафоры System V не используются. Проверьте вывод apache2ctl -V или httpd -V. Если там APR_USE_SYSVSEM_SERIALIZE или вы уже столкнулись с утечкой, задайте Mutex file: с каталогом на локальном диске.