Добавлена поддержка тестового сертификата через команду --staging. Улучшено логирование процесса получения сертификата и добавлены новые команды для тестирования в документации.
This commit is contained in:
76
README.md
76
README.md
@@ -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`
|
||||
|
||||
@@ -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 ""
|
||||
}
|
||||
|
||||
# Функция обновления
|
||||
|
||||
@@ -974,35 +974,50 @@ class LetsEncryptManager:
|
||||
Returns:
|
||||
True если успешно
|
||||
"""
|
||||
self.logger.info("=== DNS Challenge: Добавление TXT записи ===")
|
||||
try:
|
||||
self.logger.info("=== DNS Challenge: Добавление TXT записи ===")
|
||||
|
||||
# Извлекаем основной домен из validation_domain
|
||||
# Убираем wildcard если есть
|
||||
base_domain = validation_domain.replace("*.", "")
|
||||
# Извлекаем основной домен из validation_domain
|
||||
# Убираем wildcard если есть
|
||||
base_domain = validation_domain.replace("*.", "")
|
||||
|
||||
# Для DNS-01 challenge всегда используем _acme-challenge
|
||||
subdomain = "_acme-challenge"
|
||||
# Для 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 запись
|
||||
success = self.api.add_txt_record(base_domain, subdomain, validation_token)
|
||||
# Добавляем TXT запись
|
||||
self.logger.info("Добавление TXT записи через API reg.ru...")
|
||||
success = self.api.add_txt_record(base_domain, subdomain, validation_token)
|
||||
|
||||
if not success:
|
||||
self.logger.error("Не удалось добавить TXT запись")
|
||||
return False
|
||||
|
||||
self.logger.info("✅ TXT запись успешно добавлена")
|
||||
|
||||
if success:
|
||||
# Ждем распространения 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
|
||||
|
||||
return False
|
||||
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,14 +1096,24 @@ 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 если успешно
|
||||
"""
|
||||
self.logger.info("=== Запрос нового SSL сертификата ===")
|
||||
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 сертификата ===")
|
||||
|
||||
# Формируем список доменов
|
||||
domains = [self.domain]
|
||||
@@ -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)
|
||||
self.logger.info("ЗАПУСК CERTBOT")
|
||||
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,45 +1742,77 @@ def main():
|
||||
|
||||
# Обработка хуков для certbot
|
||||
if args.auth_hook:
|
||||
logger.info("=" * 80)
|
||||
logger.info("🔑 AUTH HOOK ВЫЗВАН")
|
||||
logger.info("=" * 80)
|
||||
try:
|
||||
logger.info("=" * 80)
|
||||
logger.info("🔑 AUTH HOOK ВЫЗВАН")
|
||||
logger.info("=" * 80)
|
||||
|
||||
# Certbot передает домен и токен через переменные окружения
|
||||
domain = os.environ.get("CERTBOT_DOMAIN")
|
||||
token = os.environ.get("CERTBOT_VALIDATION")
|
||||
# Certbot передает домен и токен через переменные окружения
|
||||
domain = os.environ.get("CERTBOT_DOMAIN")
|
||||
token = os.environ.get("CERTBOT_VALIDATION")
|
||||
|
||||
logger.info(f"CERTBOT_DOMAIN: {domain}")
|
||||
logger.info(f"CERTBOT_VALIDATION: {token[:20]}..." if token else "CERTBOT_VALIDATION: None")
|
||||
logger.info(f"CERTBOT_DOMAIN: {domain}")
|
||||
logger.info(f"CERTBOT_VALIDATION: {token[:20]}..." if token else "CERTBOT_VALIDATION: None")
|
||||
|
||||
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
|
||||
|
||||
if domain and token:
|
||||
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
|
||||
else:
|
||||
logger.error("CERTBOT_DOMAIN или CERTBOT_VALIDATION не установлены")
|
||||
|
||||
if success:
|
||||
logger.info("✅ AUTH HOOK ЗАВЕРШЕН УСПЕШНО")
|
||||
return 0
|
||||
else:
|
||||
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:
|
||||
logger.info("=" * 80)
|
||||
logger.info("🧹 CLEANUP HOOK ВЫЗВАН")
|
||||
logger.info("=" * 80)
|
||||
try:
|
||||
logger.info("=" * 80)
|
||||
logger.info("🧹 CLEANUP HOOK ВЫЗВАН")
|
||||
logger.info("=" * 80)
|
||||
|
||||
domain = os.environ.get("CERTBOT_DOMAIN")
|
||||
token = os.environ.get("CERTBOT_VALIDATION")
|
||||
domain = os.environ.get("CERTBOT_DOMAIN")
|
||||
token = os.environ.get("CERTBOT_VALIDATION")
|
||||
|
||||
logger.info(f"CERTBOT_DOMAIN: {domain}")
|
||||
logger.info(f"CERTBOT_VALIDATION: {token[:20]}..." if token else "CERTBOT_VALIDATION: None")
|
||||
logger.info(f"CERTBOT_DOMAIN: {domain}")
|
||||
logger.info(f"CERTBOT_VALIDATION: {token[:20]}..." if token else "CERTBOT_VALIDATION: None")
|
||||
|
||||
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
|
||||
|
||||
if domain and token:
|
||||
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
|
||||
else:
|
||||
logger.error("CERTBOT_DOMAIN или CERTBOT_VALIDATION не установлены")
|
||||
return 1
|
||||
|
||||
if success:
|
||||
logger.info("✅ CLEANUP HOOK ЗАВЕРШЕН УСПЕШНО")
|
||||
return 0
|
||||
else:
|
||||
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)
|
||||
|
||||
Reference in New Issue
Block a user