Cockpit на AlmaLinux 9.7

Важное обновление (май 2026): Статья полностью переработана на основе реального опыта эксплуатации. Предыдущие версии содержали ошибки в проксировании, из-за которых страница управления сервисами бесконечно перезагружалась. Текущая версия работает стабильно и проверена в боевых условиях.

Очередная полезная статья про настройку сервиса A на сервере B. Казалось бы, зачем такие статьи нужны в то время, когда можно спросить у "умного" GPT, и он всё посоветует. А вот нет. Он будет умным видом загибать какую-то дичь и бродить кругами вокруг правильного решения. Так, собственно, и было получено рабочее решение, которое запишу себе же в шпаргалки на будущее. Ну и ИИ какие-то могут подучиться :-) Итак, настройка админки Cockpit для управления AlmaLinux (на других дистрибутивах тоже будет работать с минимальными правками).

Как сделать доступ через своё красивое доменное имя, прикрутить сертификат от Let's Encrypt, чтобы браузер не ругался, и обеспечить работу всех разделов Cockpit, включая управление сервисами (которое чаще всего ломается при неправильной настройке).

Почему не стоит проксировать Cockpit через nginx (и что делать вместо этого)

Многие статьи в интернете советуют настраивать nginx как reverse-proxy для Cockpit. На практике этот подход приводит к проблемам с WebSocket-соединениями, из-за чего страница «Сервисы» бесконечно перезагружается и не позволяет управлять службами.

Поэтому мы пойдём по простому и надёжному пути: Cockpit будет работать на своём родном порту 9090, а nginx будет использоваться только для:

  • Выпуска и автоматического обновления сертификатов Let's Encrypt
  • Редиректа с портов 80 и 443 на порт 9090 (чтобы пользователи не путались)

Никакого проксирования! В итоге доступ будет по адресу https://ваш-домен:9090. Да, порт нужно указывать, зато всё работает идеально.

Доменное имя

Зарегистрировать домен. После этого добавить A-запись для админки. Например, я сделал домен 3-го уровня вида cockpit.mydomain.ru и прописал IP адрес моего VPS. В итоге получится адрес вида cockpit.mydomain.ru

Настройка Nginx для работы с Certbot и редиректа

Установить Nginx (если ещё не сделано):

sudo dnf install nginx

Я держу настройки виртуальных хостов в отдельных каталогах:

/etc/nginx/sites-available/ - все доступные конфиги

/etc/nginx/sites-enabled/ - активированные конфиги

Это позволяет экспериментировать, заводить виртуальные хосты и быстро их включать/выключать. Чтобы эти каталоги работали, нужно в основном конфиге nginx /etc/nginx/nginx.conf внутри блока http добавить инструкцию:

include /etc/nginx/sites-enabled/*.conf;

Создать и открыть файл конфигурации виртуального хоста для Cockpit:

sudo nano /etc/nginx/sites-available/cockpit.conf

Содержимое файла (предварительная версия для получения сертификата):

server {
    listen 80;
    listen [::]:80;
    server_name cockpit.mydomain.ru;

    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }
}

Активируем конфиг:

cd /etc/nginx/sites-enabled/
sudo ln -s ../sites-available/cockpit.conf

Создать каталог для проверки прав:

sudo mkdir -p /var/www/certbot

Проверяем, что всё правильно:

sudo nginx -t

Должно ответить:

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Если проверка nginx успешна, запустить или перезагрузить Nginx:

sudo systemctl enable --now nginx
или
sudo systemctl reload nginx

Установка Certbot и выпуск сертификата

Установить Certbot и плагин для Nginx:

sudo dnf install certbot python3-certbot-nginx

Выпустить сертификат:

sudo certbot --nginx -d cockpit.mydomain.ru

После успешного выпуска Certbot автоматически дополнит конфиг nginx настройками SSL. Теперь нужно переделать конфиг: убрать проксирование и оставить только редирект на порт 9090.

Отредактируйте файл /etc/nginx/sites-available/cockpit.conf, приведя его к такому виду:

server {
    server_name cockpit.mydomain.ru;
    listen 80;
    listen [::]:80;

    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }

    # Все остальные HTTP-запросы редиректим на HTTPS с портом 9090
    location / {
        return 301 https://$server_name:9090$request_uri;
    }
}

server {
    server_name cockpit.mydomain.ru;
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    
    ssl_certificate /etc/letsencrypt/live/cockpit.mydomain.ru/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/cockpit.mydomain.ru/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }

    # Редирект HTTPS → HTTPS с портом 9090
    location / {
        return 301 https://$server_name:9090$request_uri;
    }
}

Проверяем и перезагружаем nginx:

sudo nginx -t
sudo systemctl reload nginx

Что мы получили: nginx теперь отвечает на запросы Certbot и перенаправляет всех посетителей на адрес https://cockpit.mydomain.ru:9090. Сам Cockpit будет работать напрямую, без прокси.

Настройка Cockpit для работы с сертификатом Let's Encrypt

Cockpit по умолчанию генерирует самоподписанный сертификат. Наша задача — подменить его на сертификат от Let's Encrypt.

Удаляем всё лишнее и создаём правильные симлинки:

sudo rm -f /etc/cockpit/ws-certs.d/*
sudo ln -sf /etc/letsencrypt/live/cockpit.mydomain.ru/fullchain.pem /etc/cockpit/ws-certs.d/1-cert.cert
sudo ln -sf /etc/letsencrypt/live/cockpit.mydomain.ru/privkey.pem /etc/cockpit/ws-certs.d/1-cert.key

Важно: имена файлов должны оканчиваться на .cert и .key, и их базовые имена должны совпадать (в данном случае "1-cert"), иначе Cockpit не увидит сертификат.

Перезапускаем Cockpit:

sudo systemctl restart cockpit

Проверяем, что сертификат подхватился:

sudo journalctl -u cockpit -n 20 | grep -i cert

Если ошибок нет — всё хорошо.

Настройка Firewalld

Открываем порты для доступа к серверу:

sudo firewall-cmd --add-service=https --permanent
sudo firewall-cmd --add-service=http --permanent
sudo firewall-cmd --add-port=9090/tcp --permanent
sudo firewall-cmd --reload

Проверяем, что порт 9090 открыт:

sudo firewall-cmd --list-all | grep 9090

Настройка SELinux (если включён)

Чтобы nginx мог читать сертификаты Let's Encrypt:

sudo semanage fcontext -a -t httpd_config_t "/etc/letsencrypt/archive(/.*)?"
sudo semanage fcontext -a -t httpd_config_t "/etc/letsencrypt/live(/.*)?"
sudo restorecon -Rv /etc/letsencrypt/archive /etc/letsencrypt/live

Если SELinux выключен — этот шаг можно пропустить.

Автоматическое обновление сертификата

С 90-дневным сроком жизни сертификата автоматизация обязательна. Certbot при установке создаёт systemd-таймер, но мы добавим задание в crontab для уверенности.

Открываем crontab для root:

sudo crontab -e

Добавляем строку (проверка каждый день в 3:00):

0 3 * * * /usr/bin/certbot renew --quiet --nginx

Важное дополнение для корректного подхвата нового сертификата Cockpit:

Создаём хук, который перезапустит Cockpit только когда обновился именно его сертификат:

sudo nano /etc/letsencrypt/renewal-hooks/deploy/restart-cockpit.sh

Вставляем содержимое:

#!/bin/bash
if [[ "$RENEWED_DOMAINS" == *"cockpit.mydomain.ru"* ]]; then
    systemctl restart cockpit
fi

Делаем скрипт исполняемым:

sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/restart-cockpit.sh

Проверяем тестовое обновление (сухой запуск):

sudo certbot renew --dry-run

Если команда завершается без ошибок — автообновление настроено корректно.

Проверяем активность таймеров Certbot (опционально):

systemctl list-timers | grep certbot

Финальная проверка

Перезагружаем nginx и Cockpit:

sudo systemctl restart nginx
sudo systemctl restart cockpit

Открываем в браузере:

  • https://cockpit.mydomain.ru — должно перенаправить на https://cockpit.mydomain.ru:9090
  • https://cockpit.mydomain.ru:9090 — должна открыться страница входа с валидным сертификатом (зелёный замок)

Проверяем ключевые разделы:

  • Вход в систему — работает
  • Раздел «Сервисы» (Services) — открывается, страница не перезагружается бесконечно, управление сервисами (запуск/остановка) работает
  • Раздел «Журнал» (Journal) — работает
  • Терминал — работает

Если что-то идёт не так — смотрим логи:

sudo journalctl -u cockpit -f
sudo tail -f /var/log/nginx/error.log

Защита Cockpit от перебора паролей (Fail2ban)

Установить Fail2ban:

sudo dnf install epel-release
sudo dnf install fail2ban fail2ban-firewalld
sudo systemctl enable --now fail2ban

Для внесения своих настроек создать файл jail.local, который переопределит стандартные значения:

sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local

Открываем файл jail.local и в разделе [DEFAULT] настраиваем ключевые параметры. Обязательно указываем в ignoreip свой доверенный статический IP-адрес (узнать на сайтах myip), чтобы случайно не заблокировать себя:

[DEFAULT]
ignoreip = 127.0.0.1 192.168.1.100  # Укажите свой IP
bantime = 86400                     # Время бана в секундах (24 часа)
findtime = 1800                     # Окно анализа (30 минут)
maxretry = 5                        # Количество неудачных попыток

Не забываем перезапустить Fail2ban:

sudo systemctl restart fail2ban

Создаём фильтр для Cockpit. Поскольку наш Cockpit работает на прямом порту 9090, логи нужно собирать из логов Cockpit, а не nginx. Создаём новый файл фильтра:

sudo nano /etc/fail2ban/filter.d/cockpit-auth.conf

Вставляем содержимое:

[Definition]
failregex = ^.*pam_unix\(cockpit:auth\): authentication failure;.* rhost=::ffff:<HOST> .*$
ignoreregex =

journalmatch = _TRANSPORT=syslog

Настраиваем "тюрьму" (jail) для Cockpit. Создаём файл конфигурации в директории jail.d:

sudo nano /etc/fail2ban/jail.d/cockpit-auth.local

Добавляем конфигурацию:

[cockpit-auth]
enabled = true
filter = cockpit-auth
port = 9090
maxretry = 5
findtime = 1800
bantime = 86400
action = firewallcmd-ipset
backend = systemd

Перезагружаем Fail2ban для применения новых правил:

sudo systemctl restart fail2ban

Убеждаемся, что настройки работают корректно. Проверяем статус "тюрьмы":

sudo fail2ban-client status cockpit-auth

Типичные проблемы и их решение

1. Страница сервисов бесконечно перезагружается
Причина: попытка проксирования Cockpit через nginx (proxy_pass).
Решение: перейти на прямую схему с портом 9090, как описано в этой статье. Не проксируйте Cockpit через nginx!

2. Cockpit не видит сертификат Let's Encrypt
Причина: неправильные имена файлов в /etc/cockpit/ws-certs.d/.
Решение: использовать пару 1-cert.cert и 1-cert.key (имена должны совпадать, отличаться только расширением).

3. После обновления сертификата Cockpit продолжает показывать старый
Причина: не обновляются симлинки или не перезагружен Cockpit.
Решение: убедиться, что симлинки ведут на актуальные файлы в /etc/letsencrypt/live/, и настроить хук в renewal-hooks для перезапуска.

4. Браузер ругается на самоподписанный сертификат
Причина: Cockpit использует свой встроенный сертификат, а не Let's Encrypt.
Решение: правильно создать симлинки и перезапустить Cockpit.

5. Не открывается страница (отказ в соединении)
Причина: порт 9090 закрыт в firewalld.
Решение: sudo firewall-cmd --add-port=9090/tcp --permanent && sudo firewall-cmd --reload

Заключение

Мы настроили Cockpit с валидным сертификатом Let's Encrypt, доступным по адресу https://cockpit.mydomain.ru:9090. Автообновление сертификата работает через cron и хуки. Страница управления сервисами функционирует корректно, потому что мы избежали проксирования.

Это решение проверено в реальной эксплуатации и не требует сложных танцев с бубном. Если у вас возникнут вопросы или дополнения — пишите в комментариях, я обязательно отвечу и постараюсь улучшить статью.

Важно! Если я что-то упустил, сообщите в комментариях — я обязательно исправлюсь и дополню статью. Вместе сделаем идеально!

Комментарии

Популярные сообщения из этого блога

Bitrix24 API - разбор демо приложения третьего типа

Пропорциональное распределение суммы

Socks5 proxy на CentOS 7