Self-signed certificate: когда использовать и как избежать предупреждений
Self-signed certificate: когда использовать и как избежать предупреждений
Self-signed certificate — сертификат, подписанный не доверенным центром сертификации (CA), а собственным ключом владельца. Браузер его не принимает и показывает предупреждение ERR_CERT_AUTHORITY_INVALID. Тем не менее, self-signed остаётся нужной вещью во внутренних сетях, для разработки и для тестовых стендов. Разберём, как правильно создать такой сертификат, когда он уместен, и как избавить команду от постоянных предупреждений.
Когда self-signed — правильный выбор
- Локальная разработка:
localhost,*.local,dev.example.com— Let's Encrypt не выдаёт на эти имена, а покупать сертификат смысла нет. - Внутренние сервисы: админки, мониторинг сайтов, прокси — внутри VPN, куда никто снаружи не зайдёт.
- IoT и embedded-устройства: ограниченная связность, установка CA на клиенты под вашим контролем.
- Тестирование mTLS: быстрая генерация клиентских сертификатов без лишней бюрократии.
- Air-gapped окружения: изолированные сети без доступа к публичным CA.
Для публичного сайта self-signed — всегда плохая идея: пользователи получат красный экран, поисковики пессимизируют. Используйте Let's Encrypt.
Создание self-signed сертификата через openssl
Базовый сертификат на 365 дней для localhost:
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem \
-days 365 -nodes \
-subj "/C=RU/ST=Moscow/O=Dev/CN=localhost"
Но современные браузеры требуют SAN (Subject Alternative Name), без него будет ERR_CERT_COMMON_NAME_INVALID. Правильный способ — с конфигом:
# openssl.cnf
[req]
distinguished_name = req
x509_extensions = v3_req
prompt = no
[req]
C = RU
CN = localhost
[v3_req]
subjectAltName = @alt_names
basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
[alt_names]
DNS.1 = localhost
DNS.2 = dev.example.com
DNS.3 = *.dev.example.com
IP.1 = 127.0.0.1
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem \
-days 365 -nodes -config openssl.cnf
Установка в nginx и проверка
server {
listen 443 ssl;
server_name localhost;
ssl_certificate /etc/nginx/certs/cert.pem;
ssl_certificate_key /etc/nginx/certs/key.pem;
ssl_protocols TLSv1.2 TLSv1.3;
}
curl -k https://localhost/ # -k игнорирует self-signed
openssl s_client -connect localhost:443 -servername localhost
Как убрать предупреждение в браузере (trust store)
Предупреждение исчезнет, если добавить сертификат (или его CA) в системный trust store.
macOS:
sudo security add-trusted-cert -d -r trustRoot \
-k /Library/Keychains/System.keychain cert.pem
Linux (Debian/Ubuntu):
sudo cp cert.pem /usr/local/share/ca-certificates/dev-cert.crt
sudo update-ca-certificates
Windows (PowerShell как админ):
Import-Certificate -FilePath cert.pem `
-CertStoreLocation Cert:\LocalMachine\Root
Firefox хранит отдельный trust store — добавьте через Settings → Privacy & Security → Certificates.
Правильный путь: локальная CA + mkcert
Вместо ручного создания сертификатов для каждого проекта — создайте свою локальную CA, установите её раз в систему, а потом генерируйте под неё сертификаты. Утилита mkcert делает это в две команды:
# Установка (macOS)
brew install mkcert
mkcert -install # Создаёт и регистрирует CA в системе
# Генерация сертификата
mkcert localhost 127.0.0.1 dev.example.com "*.dev.example.com"
# Создаются localhost+3.pem и localhost+3-key.pem
Для команды разработки: корневой CA хранится в шифрованном хранилище 1Password/Vault, каждый разработчик импортирует у себя, дальше mkcert генерирует сертификаты на лету.
Внутренняя PKI для компании
Для среднего и крупного бизнеса self-signed для каждого сервиса не масштабируется. Нужна собственная PKI:
- Корневой CA (offline, на изолированной машине) — подписывает только intermediate.
- Intermediate CA (online) — выдаёт сертификаты серверам.
- Инструменты: HashiCorp Vault (PKI secrets engine), Step CA, cert-manager для Kubernetes.
- Доверие: root CA деплоится через групповые политики AD / MDM на все рабочие станции.
Это похоже на то, как устроены публичные CA, но внутри компании. Сертификаты обновляются автоматически через ACME (как Let's Encrypt) или через API документацию Vault.
Риски и антипаттерны
- ❌ Отключать проверку (
curl -k,verify_ssl=False) в продакшен-коде — это отменяет всю TLS-защиту. - ❌ Копировать ключ CA между разработчиками без шифрования.
- ❌ Self-signed для публичного API — клиенты будут страдать.
- ✅ Использовать mkcert или Vault вместо ручных openssl-команд.
- ✅ Хранить приватные ключи CA в HSM или в зашифрованном Secrets Manager.
- ✅ Ротировать сертификаты — не ставить срок 10 лет.
Часто задаваемые вопросы
Почему Let's Encrypt не подходит для localhost?
Let's Encrypt требует публичной валидации (DNS-01 или HTTP-01). Для localhost и приватных IP её невозможно пройти. Альтернатива — DNS-01 на реальный домен вроде dev.example.com с DNS, указывающим на 127.0.0.1.
Self-signed безопаснее, чем HTTP?
Технически да — трафик шифруется. Но без доверия к сертификату нельзя гарантировать отсутствие MITM. Атакующий может подменить self-signed своим, и пользователь не заметит.
Можно ли использовать один self-signed для нескольких доменов?
Да, через SAN. Добавьте все домены в alt_names. Wildcard тоже работает: DNS.1 = *.example.local. Сравнение wildcard и SAN — в этой статье.
Сколько дней ставить срок действия?
Для dev — 365, этого хватит. Для внутренней PKI — не более 90 дней (принудительная ротация). Публичные CA с 2020 года не выдают больше 398 дней, и это хороший ориентир.
Заключение
Self-signed сертификат — не зло, а инструмент для конкретных задач: локальная разработка, внутренние сервисы, IoT. Главное — автоматизировать через mkcert или PKI и никогда не использовать на публичных сайтах. SSL Checker enterno.io покажет, если случайно задеплоили self-signed в прод, а Monitors будет следить за сроком действия внутренних сертификатов.
Спецификация X.509 — RFC 5280. Утилита mkcert — github.com/FiloSottile/mkcert.
Проверьте ваш сайт прямо сейчас
Проверить →