Добавлена поддержка тестового сертификата через команду --staging. Улучшено логирование процесса получения сертификата и добавлены новые команды для тестирования в документации.

This commit is contained in:
Dmitriy Fofanov
2025-10-30 09:47:23 +03:00
parent 664995334e
commit c5bcd7e8b7
3 changed files with 409 additions and 111 deletions

View File

@@ -119,6 +119,14 @@ letsencrypt-regru --auto
#### 🧪 Команды диагностики и тестирования
```bash
# Получить тестовый сертификат Let's Encrypt (staging)
# - Полностью идентичный процесс с production
# - БЕЗ лимитов на количество запросов (неограниченно!)
# - Идеально для тестирования автоматизации и DNS
# - Браузеры не доверяют (staging CA)
# - НЕ загружается в Nginx Proxy Manager
letsencrypt-regru --staging
# Проверить доступ к API reg.ru
# - Тестирует подключение к API
# - Показывает текущий IP адрес
@@ -138,6 +146,7 @@ letsencrypt-regru --help
# Включить подробный вывод (verbose mode)
letsencrypt-regru --obtain -v
letsencrypt-regru --check -v
letsencrypt-regru --staging -v
```
#### ⚙️ Служебные команды (внутреннее использование)
@@ -1686,6 +1695,53 @@ letsencrypt-regru --auto
---
### Команда `--staging`
**Назначение**: Получает тестовый сертификат из staging окружения Let's Encrypt.
**Что делает:**
1. Запускает полный процесс получения сертификата Let's Encrypt
2. Использует staging CA (Certificate Authority) вместо production
3. Создает TXT запись через API reg.ru (как и в production)
4. Ожидает распространения DNS (60 секунд)
5. Let's Encrypt staging проверяет DNS запись
6. Получает сертификат от staging CA
7. НЕ загружает сертификат в Nginx Proxy Manager
**Пример использования:**
```bash
letsencrypt-regru --staging
letsencrypt-regru --staging -v # с подробным выводом
```
**Преимущества:**
- ✅ **НЕТ ЛИМИТОВ** - неограниченное количество запросов (в отличие от production)
- ✅ **Полная идентичность** - процесс на 100% идентичен production
- ✅ **Реальный DNS** - тестирует весь процесс DNS-валидации
- ✅ **Безопасное тестирование** - не расходует лимиты production (5/неделя)
- ✅ **Быстрая отладка** - можно запускать сколько угодно раз
**⚠️ Ограничения:**
- Браузеры не доверяют staging CA (покажут предупреждение)
- Сертификат нельзя использовать на production сайтах
- Подходит только для тестирования автоматизации
**Когда использовать:**
- ✅ Первая настройка системы
- ✅ Тестирование DNS интеграции
- ✅ Отладка автоматизации
- ✅ Проверка работы hooks
- ✅ Разработка и staging окружения
**Переход на production:**
После успешного тестирования просто запустите:
```bash
sudo letsencrypt-regru --obtain
```
Staging сертификат будет заменен на production.
---
### Команда `--test-cert`
**Назначение**: Создает тестовый самоподписанный сертификат.
@@ -1703,14 +1759,28 @@ letsencrypt-regru --test-cert
**Преимущества:**
- ✅ Не требует интернет соединения
- ✅ Мгновенное создание
- ✅ Нет лимитов Let's Encrypt (5 сертификатов/неделя)
- ✅ Идеально для разработки и тестирования
- ✅ Мгновенное создание (1-2 секунды)
- ✅ Не требует API reg.ru
- ✅ Не требует DNS
- ✅ Идеально для локальной разработки
**⚠️ Внимание:**
- Браузеры покажут предупреждение "сертификат не доверенный"
- Не тестирует DNS и автоматизацию
- Не использовать в production!
**Сравнение: --staging vs --test-cert**
| Параметр | --staging | --test-cert |
|----------|-----------|-------------|
| Интернет | ✅ Требуется | ❌ Не требуется |
| API reg.ru | ✅ Требуется | ❌ Не требуется |
| DNS проверка | ✅ Полная | ❌ Нет |
| Лимиты | ✅ Нет | ✅ Нет |
| Время создания | ~2-3 минуты | ~1-2 секунды |
| Тестирует автоматизацию | ✅ Да | ❌ Нет |
| Использование | Тест перед production | Локальная разработка |
---
### Команда `--test-api`

View File

@@ -457,40 +457,75 @@ display_summary() {
echo " • Логи: ${LOG_DIR}"
echo " • Сертификаты: ${CERT_DIR}"
echo ""
echo "🔧 Доступные команды:"
echo "🔧 Основные команды:"
echo " • letsencrypt-regru --check # Проверить срок действия сертификата"
echo " • letsencrypt-regru --obtain # Получить новый сертификат"
echo " • letsencrypt-regru --obtain # Получить новый production сертификат"
echo " • letsencrypt-regru --renew # Обновить существующий сертификат"
echo " • letsencrypt-regru --test-cert # Создать тестовый самоподписанный сертификат"
echo " • letsencrypt-regru --auto # Автоматическая проверка и обновление"
echo ""
echo "🧪 Команды тестирования:"
echo " • letsencrypt-regru --staging # Тестовый Let's Encrypt (БЕЗ лимитов!)"
echo " • letsencrypt-regru --test-cert # Самоподписанный (локальная разработка)"
echo " • letsencrypt-regru --test-api # Проверить доступ к API reg.ru"
echo " • letsencrypt-regru --test-dns # Тестовое создание DNS записи TXT"
echo " • letsencrypt-regru --auth-hook # Certbot auth hook (внутреннее)"
echo " • letsencrypt-regru --cleanup-hook # Certbot cleanup hook (внутреннее)"
echo " • letsencrypt-regru --help # Показать справку"
echo " • letsencrypt-regru --test-dns # Протестировать DNS записи"
echo ""
echo "📋 Дополнительные команды:"
echo " • letsencrypt-regru --help # Показать полную справку"
echo " • letsencrypt-regru --obtain -v # Подробный вывод (verbose)"
echo ""
echo "💡 Рекомендуемый workflow:"
echo " 1. letsencrypt-regru --test-api # Проверить API"
echo " 2. letsencrypt-regru --test-dns # Проверить DNS"
echo " 3. letsencrypt-regru --staging # Тестовый сертификат (сколько угодно раз)"
echo " 4. letsencrypt-regru --obtain # Production сертификат"
echo ""
echo "⏰ Автоматическое обновление:"
echo " • Сервис запускается каждые 12 часов"
echo " • Управление: systemctl status letsencrypt-regru.timer"
echo ""
echo "📊 Просмотр логов:"
echo " • journalctl -u letsencrypt-regru -f"
echo " • tail -f ${LOG_DIR}/letsencrypt_regru.log"
echo "<EFBFBD> Просмотр логов:"
echo " • journalctl -u letsencrypt-regru -f # Системные логи (реальное время)"
echo " • tail -f ${LOG_DIR}/letsencrypt_regru.log # Файл логов"
echo ""
echo "📖 Документация:"
echo "<EFBFBD>📖 Документация:"
echo " • README: ${APP_DIR}/README.md"
echo "Docs: ${APP_DIR}/docs/"
echo " • GitHub: https://github.com/DFofanov/configure_nginx_manager"
echo ""
echo "🔍 Сравнение режимов тестирования:"
echo ""
echo " --staging (рекомендуется для тестирования):"
echo " ✅ Полный процесс Let's Encrypt"
echo " ✅ Тестирует DNS и автоматизацию"
echo " ✅ БЕЗ лимитов (неограниченно)"
echo " ⚠️ Браузеры не доверяют (staging CA)"
echo " ⏱ ~2-3 минуты"
echo ""
echo " --test-cert (для локальной разработки):"
echo " ✅ Мгновенное создание (~1 сек)"
echo " ✅ Работает без интернета"
echo " ❌ НЕ тестирует DNS/автоматизацию"
echo " ⚠️ Браузеры не доверяют (самоподпись)"
echo ""
echo " --test-dns (проверка DNS):"
echo " ✅ Тестирует только DNS"
echo " ✅ Не создает сертификат"
echo " ⏱ ~1-2 минуты"
echo ""
if grep -q '"npm_enabled": true' "${CONFIG_DIR}/config.json" 2>/dev/null; then
echo "🔗 Интеграция с Nginx Proxy Manager: ВКЛЮЧЕНА"
echo " Сертификаты будут автоматически синхронизироваться с NPM"
echo " Production сертификаты будут автоматически синхронизироваться с NPM"
echo " (Staging и test-cert сертификаты НЕ загружаются в NPM)"
echo ""
fi
msg_warn "ВАЖНО: Отредактируйте конфигурацию при необходимости:"
echo " nano ${CONFIG_DIR}/config.json"
echo ""
echo "🎉 Готово к использованию! Начните с команды:"
echo " letsencrypt-regru --test-api"
echo ""
}
# Функция обновления

View File

@@ -974,6 +974,7 @@ class LetsEncryptManager:
Returns:
True если успешно
"""
try:
self.logger.info("=== DNS Challenge: Добавление TXT записи ===")
# Извлекаем основной домен из validation_domain
@@ -983,25 +984,39 @@ class LetsEncryptManager:
# Для DNS-01 challenge всегда используем _acme-challenge
subdomain = "_acme-challenge"
self.logger.info(f"Домен: {base_domain}, Поддомен: {subdomain}")
self.logger.info(f"Validation Domain: {validation_domain}")
self.logger.info(f"Base Domain: {base_domain}")
self.logger.info(f"Subdomain: {subdomain}")
self.logger.info(f"Token: {validation_token[:20]}...")
# Добавляем TXT запись
self.logger.info("Добавление TXT записи через API reg.ru...")
success = self.api.add_txt_record(base_domain, subdomain, validation_token)
if success:
if not success:
self.logger.error("Не удалось добавить TXT запись")
return False
self.logger.info("✅ TXT запись успешно добавлена")
# Ждем распространения DNS
wait_time = self.config.get("dns_propagation_wait", 60)
self.logger.info(f"Ожидание распространения DNS ({wait_time} секунд)...")
time.sleep(wait_time)
# Проверяем DNS запись (используем base_domain для проверки)
self.logger.info("Проверка распространения DNS...")
if self.verify_dns_record_external(base_domain, subdomain, validation_token):
self.logger.info("DNS валидация готова")
self.logger.info("DNS запись подтверждена через публичные DNS")
return True
else:
self.logger.warning("DNS запись не распространилась вовремя, но продолжаем...")
self.logger.warning("⚠️ DNS запись не обнаружена через публичные DNS, но продолжаем...")
self.logger.warning("Let's Encrypt может использовать свои DNS серверы")
return True
except Exception as e:
self.logger.error(f"💥 Ошибка в dns_challenge_hook: {e}")
self.logger.exception("Traceback:")
return False
def dns_cleanup_hook(self, validation_domain: str, validation_token: str) -> bool:
@@ -1081,13 +1096,23 @@ class LetsEncryptManager:
"""
return self.verify_dns_record_external(self.domain, subdomain, expected_value)
def obtain_certificate(self) -> bool:
def obtain_certificate(self, staging: bool = False) -> bool:
"""
Получение нового сертификата
Args:
staging: Использовать staging окружение Let's Encrypt (для тестирования)
Returns:
True если успешно
"""
if staging:
self.logger.info("=== Запрос ТЕСТОВОГО SSL сертификата (Let's Encrypt Staging) ===")
self.logger.warning("⚠️ ВНИМАНИЕ: Это тестовый сертификат из staging окружения!")
self.logger.warning("⚠️ Браузеры не будут доверять этому сертификату")
self.logger.warning("⚠️ Используйте для тестирования DNS и автоматизации")
self.logger.warning("⚠️ Staging НЕ имеет лимитов запросов (в отличие от production)")
else:
self.logger.info("=== Запрос нового SSL сертификата ===")
# Формируем список доменов
@@ -1102,17 +1127,28 @@ class LetsEncryptManager:
# Создаём временные wrapper скрипты для hooks
import tempfile
# Получаем путь к конфигурации из аргументов командной строки
config_path = None
for i, arg in enumerate(sys.argv):
if arg in ['-c', '--config'] and i + 1 < len(sys.argv):
config_path = os.path.abspath(sys.argv[i + 1])
break
if not config_path:
self.logger.error("Не указан путь к конфигурации. Используйте --config /path/to/config.json")
return False
# Auth hook wrapper
auth_hook_script = tempfile.NamedTemporaryFile(mode='w', suffix='.sh', delete=False)
auth_hook_script.write('#!/bin/bash\n')
auth_hook_script.write(f'{sys.executable} {os.path.abspath(__file__)} --auth-hook\n')
auth_hook_script.write(f'{sys.executable} {os.path.abspath(__file__)} --config {config_path} --auth-hook\n')
auth_hook_script.close()
os.chmod(auth_hook_script.name, 0o755)
# Cleanup hook wrapper
cleanup_hook_script = tempfile.NamedTemporaryFile(mode='w', suffix='.sh', delete=False)
cleanup_hook_script.write('#!/bin/bash\n')
cleanup_hook_script.write(f'{sys.executable} {os.path.abspath(__file__)} --cleanup-hook\n')
cleanup_hook_script.write(f'{sys.executable} {os.path.abspath(__file__)} --config {config_path} --cleanup-hook\n')
cleanup_hook_script.close()
os.chmod(cleanup_hook_script.name, 0o755)
@@ -1127,16 +1163,28 @@ class LetsEncryptManager:
"--agree-tos",
"--non-interactive",
"--expand",
] + domain_args
]
# Добавляем --staging для тестового окружения
if staging:
cmd.append("--staging")
cmd.append("--break-my-certs") # Разрешает перезапись production сертификатов staging версиями
cmd.extend(domain_args)
self.logger.info("=" * 80)
if staging:
self.logger.info("ЗАПУСК CERTBOT (STAGING MODE)")
else:
self.logger.info("ЗАПУСК CERTBOT")
self.logger.info("=" * 80)
self.logger.info(f"Режим: {'STAGING (тестовый)' if staging else 'PRODUCTION (боевой)'}")
self.logger.info(f"Команда: {' '.join(cmd)}")
self.logger.info(f"Python: {sys.executable}")
self.logger.info(f"Скрипт: {os.path.abspath(__file__)}")
self.logger.info(f"Auth hook: {sys.executable} {os.path.abspath(__file__)} --auth-hook")
self.logger.info(f"Cleanup hook: {sys.executable} {os.path.abspath(__file__)} --cleanup-hook")
self.logger.info(f"Конфигурация: {config_path}")
self.logger.info(f"Auth hook: {sys.executable} {os.path.abspath(__file__)} --config {config_path} --auth-hook")
self.logger.info(f"Cleanup hook: {sys.executable} {os.path.abspath(__file__)} --config {config_path} --cleanup-hook")
self.logger.info("=" * 80)
try:
@@ -1341,7 +1389,59 @@ def main():
# Парсинг аргументов командной строки
parser = argparse.ArgumentParser(
description="Автоматическое управление SSL сертификатами Let's Encrypt через API reg.ru"
description="Автоматическое управление SSL сертификатами Let's Encrypt через API reg.ru",
epilog="""
════════════════════════════════════════════════════════════════════════════════
ПРИМЕРЫ ИСПОЛЬЗОВАНИЯ
════════════════════════════════════════════════════════════════════════════════
Основные команды:
%(prog)s -c config.json --check Проверить срок действия
%(prog)s -c config.json --obtain Получить production сертификат
%(prog)s -c config.json --renew Обновить сертификат
%(prog)s -c config.json --auto Авто-режим (для cron/systemd)
Команды тестирования:
%(prog)s -c config.json --staging Тестовый Let's Encrypt (БЕЗ лимитов!)
%(prog)s -c config.json --test-cert Самоподписанный (локально)
%(prog)s -c config.json --test-api Проверить API reg.ru
%(prog)s -c config.json --test-dns Проверить DNS записи
Отладка:
%(prog)s -c config.json --obtain -v Подробный вывод
════════════════════════════════════════════════════════════════════════════════
РЕКОМЕНДУЕМЫЙ WORKFLOW
════════════════════════════════════════════════════════════════════════════════
1. Проверка настройки:
%(prog)s -c config.json --test-api ✓ API доступен?
%(prog)s -c config.json --test-dns ✓ DNS работает?
2. Тестирование (неограниченно):
%(prog)s -c config.json --staging ✓ Полный процесс SSL
3. Production:
%(prog)s -c config.json --obtain ✓ Боевой сертификат
════════════════════════════════════════════════════════════════════════════════
СРАВНЕНИЕ РЕЖИМОВ ТЕСТИРОВАНИЯ
════════════════════════════════════════════════════════════════════════════════
--staging Полный Let's Encrypt, БЕЗ лимитов, ~2-3 мин, тестирует всё
--test-cert Самоподпись, мгновенно, БЕЗ интернета, для локальной разработки
--test-dns Только DNS, ~1-2 мин, не создает сертификат
════════════════════════════════════════════════════════════════════════════════
ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ
════════════════════════════════════════════════════════════════════════════════
Документация: https://github.com/DFofanov/configure_nginx_manager
Поддержка: https://github.com/DFofanov/configure_nginx_manager/issues
Лимиты LE: 5 сертификатов/неделю на домен (production only, staging БЕЗ лимитов)
""",
formatter_class=argparse.RawDescriptionHelpFormatter
)
parser.add_argument(
"-c", "--config",
@@ -1353,54 +1453,69 @@ def main():
help="Создать пример файла конфигурации",
metavar="FILE"
)
parser.add_argument(
"--obtain",
help="Получить новый сертификат",
action="store_true"
)
parser.add_argument(
"--renew",
help="Обновить существующий сертификат",
action="store_true"
)
parser.add_argument(
# Основные команды
main_group = parser.add_argument_group('Основные команды')
main_group.add_argument(
"--check",
help="Проверить срок действия сертификата",
action="store_true"
)
parser.add_argument(
main_group.add_argument(
"--obtain",
help="Получить новый production сертификат Let's Encrypt",
action="store_true"
)
main_group.add_argument(
"--renew",
help="Обновить существующий сертификат",
action="store_true"
)
main_group.add_argument(
"--auto",
help="Автоматический режим: проверка и обновление при необходимости (для cron/systemd)",
action="store_true"
)
# Команды тестирования
test_group = parser.add_argument_group('Команды тестирования')
test_group.add_argument(
"--staging",
help="Получить тестовый сертификат Let's Encrypt (staging CA, БЕЗ лимитов)",
action="store_true"
)
test_group.add_argument(
"--test-cert",
help="Создать самоподписанный сертификат (локальная разработка, БЕЗ интернета)",
action="store_true"
)
test_group.add_argument(
"--test-api",
help="Проверить доступ к API reg.ru (показывает IP, баланс)",
action="store_true"
)
test_group.add_argument(
"--test-dns",
help="Протестировать создание/удаление DNS записи (полная симуляция SSL процесса)",
action="store_true"
)
# Служебные команды
service_group = parser.add_argument_group('Служебные команды (внутреннее использование)')
service_group.add_argument(
"--auth-hook",
help="Внутренний хук для DNS аутентификации (используется certbot)",
help="Certbot authentication hook (создание DNS записи)",
action="store_true"
)
parser.add_argument(
service_group.add_argument(
"--cleanup-hook",
help="Внутренний хук для очистки DNS (используется certbot)",
help="Certbot cleanup hook (удаление DNS записи)",
action="store_true"
)
# Дополнительные параметры
parser.add_argument(
"-v", "--verbose",
help="Подробный вывод",
action="store_true"
)
parser.add_argument(
"--auto",
help="Автоматический режим: проверка и обновление при необходимости",
action="store_true"
)
parser.add_argument(
"--test-cert",
help="Создать самоподписанный тестовый сертификат (для разработки и тестирования)",
action="store_true"
)
parser.add_argument(
"--test-api",
help="Протестировать подключение к API reg.ru",
action="store_true"
)
parser.add_argument(
"--test-dns",
help="Протестировать создание и удаление DNS записи (полный цикл как при SSL)",
help="Подробный вывод для диагностики",
action="store_true"
)
@@ -1627,6 +1742,7 @@ def main():
# Обработка хуков для certbot
if args.auth_hook:
try:
logger.info("=" * 80)
logger.info("🔑 AUTH HOOK ВЫЗВАН")
logger.info("=" * 80)
@@ -1638,16 +1754,32 @@ def main():
logger.info(f"CERTBOT_DOMAIN: {domain}")
logger.info(f"CERTBOT_VALIDATION: {token[:20]}..." if token else "CERTBOT_VALIDATION: None")
if domain and token:
if not domain or not token:
logger.error("CERTBOT_DOMAIN или CERTBOT_VALIDATION не установлены")
logger.error("Переменные окружения:")
for key in os.environ:
if key.startswith("CERTBOT_"):
logger.error(f" {key}: {os.environ[key]}")
return 1
api = RegRuAPI(config["regru_username"], config["regru_password"], logger)
manager = LetsEncryptManager(config, api, logger)
success = manager.dns_challenge_hook(domain, token)
return 0 if success else 1
if success:
logger.info("✅ AUTH HOOK ЗАВЕРШЕН УСПЕШНО")
return 0
else:
logger.error("CERTBOT_DOMAIN или CERTBOT_VALIDATION не установлены")
logger.error("❌ AUTH HOOK ЗАВЕРШИЛСЯ С ОШИБКОЙ")
return 1
except Exception as e:
logger.error(f"💥 КРИТИЧЕСКАЯ ОШИБКА В AUTH HOOK: {e}")
logger.exception("Traceback:")
return 1
if args.cleanup_hook:
try:
logger.info("=" * 80)
logger.info("🧹 CLEANUP HOOK ВЫЗВАН")
logger.info("=" * 80)
@@ -1658,14 +1790,29 @@ def main():
logger.info(f"CERTBOT_DOMAIN: {domain}")
logger.info(f"CERTBOT_VALIDATION: {token[:20]}..." if token else "CERTBOT_VALIDATION: None")
if domain and token:
if not domain or not token:
logger.error("CERTBOT_DOMAIN или CERTBOT_VALIDATION не установлены")
logger.error("Переменные окружения:")
for key in os.environ:
if key.startswith("CERTBOT_"):
logger.error(f" {key}: {os.environ[key]}")
return 1
api = RegRuAPI(config["regru_username"], config["regru_password"], logger)
manager = LetsEncryptManager(config, api, logger)
success = manager.dns_cleanup_hook(domain, token)
return 0 if success else 1
if success:
logger.info("✅ CLEANUP HOOK ЗАВЕРШЕН УСПЕШНО")
return 0
else:
logger.error("CERTBOT_DOMAIN или CERTBOT_VALIDATION не установлены")
return 1
logger.warning("⚠️ CLEANUP HOOK ЗАВЕРШИЛСЯ С ПРЕДУПРЕЖДЕНИЕМ (не критично)")
return 0 # Cleanup hook не должен блокировать получение сертификата
except Exception as e:
logger.error(f"💥 ОШИБКА В CLEANUP HOOK: {e}")
logger.exception("Traceback:")
return 0 # Cleanup hook не должен блокировать получение сертификата
# Проверка прав root
if os.geteuid() != 0:
@@ -1710,9 +1857,55 @@ def main():
logger.info(f"Сертификат действителен ({days_left} дней)")
return 0
elif args.staging:
# Получение ТЕСТОВОГО сертификата из staging окружения
logger.info("")
logger.info("🧪" * 40)
logger.info("РЕЖИМ STAGING: Тестовый сертификат Let's Encrypt")
logger.info("🧪" * 40)
logger.info("")
logger.info("📋 ИНФОРМАЦИЯ О STAGING РЕЖИМЕ:")
logger.info(" • Сертификат будет выдан staging CA (не доверенный)")
logger.info(" • Браузеры покажут предупреждение о безопасности")
logger.info("НЕТ лимитов на количество запросов (в отличие от production)")
logger.info(" • Идеально для тестирования автоматизации и DNS")
logger.info(" • Полностью идентичный процесс с production")
logger.info("")
logger.info("⚠️ НЕ используйте staging сертификаты на production сайтах!")
logger.info("")
success = manager.obtain_certificate(staging=True)
if success:
logger.info("")
logger.info("=" * 80)
logger.info("✅ ТЕСТОВЫЙ СЕРТИФИКАТ УСПЕШНО ПОЛУЧЕН")
logger.info("=" * 80)
logger.info("")
logger.info("📂 Расположение: /etc/letsencrypt/live/%s/" % config['domain'])
logger.info("")
logger.info("🔄 Следующие шаги:")
logger.info(" 1. ✅ Проверьте что процесс прошел успешно")
logger.info(" 2. ✅ Убедитесь что DNS записи создаются корректно")
logger.info(" 3. ✅ Проверьте автоматизацию")
logger.info(" 4. 🚀 Когда всё готово - получите production сертификат:")
logger.info(" sudo letsencrypt-regru --obtain")
logger.info("")
logger.info("💡 ВАЖНО: Staging сертификаты хранятся в той же директории,")
logger.info(" что и production. Для получения production сертификата")
logger.info(" просто запустите команду --obtain")
logger.info("")
# Синхронизация с NPM (если включено)
if config.get("npm_enabled", False):
logger.warning("⚠️ Staging сертификат НЕ загружается в Nginx Proxy Manager")
logger.warning(" (staging сертификаты не предназначены для production)")
return 0 if success else 1
elif args.obtain:
# Принудительное получение нового сертификата
success = manager.obtain_certificate()
success = manager.obtain_certificate(staging=False)
if success:
manager.display_certificate_info()
reload_webserver(logger)