Traefik — 9. Настройка для работы с сертификатом НУЦ Минцифры

22 апреля 2026

В этой статье я расскажу как получить отечественный SSL-сертификат Национального Удостоверяющего Центра Минцифры России и подключить его к Traefik. А также о граблях, на которые я наступил.

Для получения сертификата необходимо перейти на Госуслуги. Набираем в поиске «Получение DV-сертификата безопасности».

Определяемся с типом сертификата: OV (Organization Validation) и DV (Domain Validation). Выбираем DV-сертификат. Также пока воспользуемся RSA вариантом шифрования. ГОСТ нас пока не интересует.

Теперь нас просят загрузить запрос на выпуск сертификата.

Его можно подготовить по инструкции на Госуслугах, а можно воспользоваться простым скриптом, который упрощает эту задачу:

gen_csr.tar.gz

Показать код

#!/bin/bash
set -e
 
# Проверяем, передан ли параметр домена
if [ -z "$1" ]; then
    echo "Использование: $0 <домен>"
    echo "Пример:        $0 19dx.ru"
    exit 1
fi
 
DOMAIN="$1"
CSR_FILE="${DOMAIN}.csr"
KEY_FILE="${DOMAIN}.key"
CNF_FILE="${DOMAIN}.cnf"
 
# Предупреждение при наличии старых файлов
if [ -f "$KEY_FILE" ] || [ -f "$CSR_FILE" ]; then
    echo "⚠️  Файлы $KEY_FILE или $CSR_FILE уже существуют и будут перезаписаны."
fi
 
# Автоматическое создание конфигурационного файла
echo "📝 Генерация конфигурационного файла: $CNF_FILE"
cat > "$CNF_FILE" <<EOF
[ req ]
distinguished_name = req_distinguished_name
req_extensions = v3_req
x509_extensions = v3_req
prompt = no
string_mask = utf8only
utf8 = yes
[ req_distinguished_name ]
CN = ${DOMAIN}
C = RU
[ v3_req ]
keyUsage = digitalSignature, keyEncipherment, keyAgreement
extendedKeyUsage = serverAuth, clientAuth
subjectAltName = DNS:${DOMAIN}
EOF
 
# Генерация CSR и приватного ключа
echo "🔑 Генерация CSR и приватного ключа для домена: $DOMAIN..."
openssl req -out "$CSR_FILE" -new -newkey rsa:2048 -nodes -keyout "$KEY_FILE" -config "$CNF_FILE"
 
# Проверка/вывод содержимого CSR
echo "📄 Проверка содержимого CSR..."
openssl req -in "$CSR_FILE" -noout -text -nameopt utf8 -config "$CNF_FILE"
 
echo "✅ Готово. Созданы файлы:"
echo "   • $CSR_FILE"
echo "   • $KEY_FILE"
echo "   • $CNF_FILE"

Этот скрипт автоматически создаёт файл запроса, вписывает туда имя домена, подписывает его и формирует закрытый ключ. Для этого просто необходимо передать имя домена в качестве параметра скрипту:

./gen_csr.sh example.ru

В результате будут сформированы три файла:

  • domain.ru.cnf - файл запроса.
  • domain.ru.csr - подписанный файл запроса.
  • domain.ru.key - закрытый ключ.

csr-файл загружаем на Госуслуги.

После этого нас попросят подтвердить права владения доменом. Это можно сделать либо с помощью размещения текстового файла на сервере (он должен быть доступен по HTTP-протоколу!), либо TXT-записи в DNS:

Если всё успешно, то через пару минут в Госуслуги придёт сертификат (в форматах cer и crt, но по сути это полные копии с разными расширениями).

Сначала я пытался скачанный из Госуслуг сертификат сразу подключить к Traefik, потратил много времени, но ничего не заработало. В результате оказалось, что для Traefik нужен сертификат в PEM формате. Сконвертировать его очень просто с помощью команды:

openssl x509 -inform DER -in domain.crt -out domain.pem

Или воспользоваться скриптом:

convert_cert.tar.gz

Показать код

#!/bin/bash
set -e
 
# Проверяем, передан ли параметр домена
if [ -z "$1" ]; then
    echo "Использование: $0 <домен>"
    echo "Пример:        $0 example.ru"
    exit 1
fi
 
DOMAIN="$1"
CRT_FILE="${DOMAIN}.crt"
PEM_FILE="${DOMAIN}.pem"
BAK_FILE="${DOMAIN}.crt.bak"
 
openssl x509 -inform DER -in "$CRT_FILE" -out "$PEM_FILE"
 
mv "$CRT_FILE" "$BAK_FILE"
mv "$PEM_FILE" "$CRT_FILE"
./convert_cert.sh example.ru

В результате выполнения скрипта исходный crt файл будет перезаписан его pem-версией, а исходный файл сохранён с расширением bak.

Создаём каталог для хранения сертификатов ./data/certs/ и пробрасываем его в контейнер. Для этого правим docker-compose.yml:

services:
  traefik:
    image: traefik:v3
    container_name: traefik
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    ports:
      - 80:80
      - 443:443
    networks:
      proxy-net:
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./data/traefik.yml:/traefik.yml:ro
      - ./data/custom/:/custom/:ro
      - ./data/certs/:/certs/:ro
      - ./data/acme.json:/acme.json
      - /var/log/traefik:/var/log/traefik
 
...

Помещаем crt и key файлы в ./data/certs/ и создаём файл ./data/custom/tls.yml со следующим содержимым:

tls:
  certificates:
    - certFile: /certs/example.ru.crt
      keyFile: /certs/example.ru.key
    - certFile: /certs/test.example.ru.crt
      keyFile: /certs/test.example.ru.key

Здесь, для примера, присутствует два сертификата: для доменов example.ru и test.example.ru.

P.S. Сначала я пытался поместить эти строки в файл статической конфигурации, но почему-то ничего не заработало. Traefik отказывался загружать сертификаты.

Теперь правим файл динамической конфигурации ./data/custom/host.yml . Вместо «tls: certResolver: letsEncrypt» в роутере необходимо прописать строку «tls: {}»:

http:
  routers:
    test-router:
      entryPoints:
      - https
      service: service-test
      rule: Host(`example.ru`)
      tls: {}

Теперь можно и проверить работоспособность. Для этого выполняем команду:

openssl s_client -connect example.ru:443 </dev/null 2>/dev/null | openssl x509 -noout -subject -issuer

Результат должен быть следующим:

subject=CN = example.ru, C = RU
issuer=C = RU, O = The Ministry of Digital Development and Communications, CN = Russian Trusted Sub CA

В выводе видно, что сертификат сервера выдан Национальным Удостоверяющим Центром.

Теперь главное не забывать каждые 90 дней перевыпускать сертификат.

  • docker/traefik_i_sertifikat_mincifry.txt
  • Последнее изменение: 23.04.2026 21:06
  • r0wbh