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

This commit is contained in:
Dmitriy Fofanov
2025-10-30 10:04:36 +03:00
parent 4777d832b7
commit 7834013cdb
2 changed files with 224 additions and 13 deletions

View File

@@ -150,6 +150,9 @@ letsencrypt-regru --help
letsencrypt-regru --obtain -v
letsencrypt-regru --check -v
letsencrypt-regru --staging -v
# Очистить lock-файлы Certbot (если процесс завис)
letsencrypt-regru --force-cleanup
```
#### ⚙️ Служебные команды (внутреннее использование)
@@ -1520,6 +1523,40 @@ nslookup -type=TXT _acme-challenge.example.com
dig TXT _acme-challenge.example.com
```
### Проблема: "Another instance of Certbot is already running"
**Причина:** Предыдущий процесс Certbot не завершился корректно или остались lock-файлы.
**Решение:**
```bash
# Вариант 1: Принудительная очистка lock-файлов (рекомендуется)
letsencrypt-regru --force-cleanup
# Вариант 2: Ручная очистка
# Проверьте запущенные процессы certbot
ps aux | grep certbot
# Остановите зависшие процессы
sudo pkill certbot
# Или принудительно
sudo pkill -9 certbot
# Удалите lock-файлы
sudo rm -f /var/lib/letsencrypt/.certbot.lock
sudo rm -f /etc/letsencrypt/.certbot.lock
# Попробуйте снова
letsencrypt-regru --obtain
```
**Вариант 3: Подождать автоматически**
Скрипт автоматически:
1. Обнаруживает запущенные процессы Certbot
2. Ждёт их завершения (60 секунд)
3. Пытается очистить lock-файлы
4. Выдаёт рекомендации по решению проблемы
### Проблема: Certbot не установлен
**Решение:**

View File

@@ -930,6 +930,94 @@ class LetsEncryptManager:
self.logger.error("Certbot не установлен!")
return False
def check_certbot_running(self) -> bool:
"""
Проверка наличия запущенных процессов certbot
Returns:
True если процесс certbot запущен
"""
try:
# Проверяем через ps
result = subprocess.run(
["ps", "aux"],
capture_output=True,
text=True
)
# Ищем процессы certbot (исключая текущий grep)
certbot_processes = [
line for line in result.stdout.split('\n')
if 'certbot' in line.lower() and 'grep' not in line.lower()
and str(os.getpid()) not in line # Исключаем текущий процесс
]
if certbot_processes:
self.logger.warning("Обнаружены запущенные процессы Certbot:")
for proc in certbot_processes:
self.logger.warning(f" {proc}")
return True
return False
except Exception as e:
self.logger.debug(f"Не удалось проверить запущенные процессы: {e}")
return False
def cleanup_certbot_locks(self) -> bool:
"""
Очистка lock-файлов certbot
Returns:
True если lock-файлы были удалены или их не было
"""
lock_files = [
"/var/lib/letsencrypt/.certbot.lock",
"/etc/letsencrypt/.certbot.lock",
]
removed = False
for lock_file in lock_files:
if os.path.exists(lock_file):
try:
os.remove(lock_file)
self.logger.info(f"Удалён lock-файл: {lock_file}")
removed = True
except Exception as e:
self.logger.warning(f"Не удалось удалить lock-файл {lock_file}: {e}")
if not removed:
self.logger.debug("Lock-файлы certbot не найдены")
return True
def wait_for_certbot(self, timeout: int = 300) -> bool:
"""
Ожидание завершения работы других процессов certbot
Args:
timeout: Максимальное время ожидания в секундах
Returns:
True если certbot больше не запущен
"""
self.logger.info("Ожидание завершения других процессов Certbot...")
start_time = time.time()
check_interval = 5 # Проверяем каждые 5 секунд
while time.time() - start_time < timeout:
if not self.check_certbot_running():
self.logger.info("Другие процессы Certbot завершены")
return True
elapsed = int(time.time() - start_time)
self.logger.info(f"Ожидание... ({elapsed}/{timeout} секунд)")
time.sleep(check_interval)
self.logger.error(f"Превышено время ожидания ({timeout} секунд)")
return False
def check_certificate_expiry(self) -> Optional[int]:
"""
Проверка срока действия сертификата
@@ -1115,6 +1203,26 @@ class LetsEncryptManager:
else:
self.logger.info("=== Запрос нового SSL сертификата ===")
# Проверяем, не запущен ли уже certbot
if self.check_certbot_running():
self.logger.warning("Обнаружен запущенный процесс Certbot")
self.logger.info("Варианты решения:")
self.logger.info(" 1. Дождитесь завершения текущего процесса")
self.logger.info(" 2. Остановите процесс вручную: sudo pkill certbot")
self.logger.info(" 3. Используйте --force-cleanup для очистки lock-файлов")
# Пытаемся подождать
if not self.wait_for_certbot(timeout=60):
self.logger.error("Не удалось дождаться завершения Certbot")
self.logger.info("Попытка очистки lock-файлов...")
self.cleanup_certbot_locks()
# Проверяем снова
if self.check_certbot_running():
self.logger.error("Certbot всё ещё запущен. Требуется ручное вмешательство.")
self.logger.error("Выполните: sudo pkill -9 certbot")
return False
# Формируем список доменов
domains = [self.domain]
if self.config.get("wildcard", False):
@@ -1396,33 +1504,34 @@ def main():
════════════════════════════════════════════════════════════════════════════════
Основные команды:
%(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)
letsencrypt-regru --check Проверить срок действия
letsencrypt-regru --obtain Получить production сертификат
letsencrypt-regru --renew Обновить сертификат
letsencrypt-regru --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 записи
letsencrypt-regru --staging Тестовый Let's Encrypt (БЕЗ лимитов!)
letsencrypt-regru --test-cert Самоподписанный (локально)
letsencrypt-regru --test-api Проверить API reg.ru
letsencrypt-regru --test-dns Проверить DNS записи
Отладка:
%(prog)s -c config.json --obtain -v Подробный вывод
letsencrypt-regru --obtain -v Подробный вывод
letsencrypt-regru --force-cleanup Очистить lock-файлы Certbot
════════════════════════════════════════════════════════════════════════════════
РЕКОМЕНДУЕМЫЙ WORKFLOW
════════════════════════════════════════════════════════════════════════════════
1. Проверка настройки:
%(prog)s -c config.json --test-api ✓ API доступен?
%(prog)s -c config.json --test-dns ✓ DNS работает?
letsencrypt-regru --test-api ✓ API доступен?
letsencrypt-regru --test-dns ✓ DNS работает?
2. Тестирование (неограниченно):
%(prog)s -c config.json --staging ✓ Полный процесс SSL
letsencrypt-regru --staging ✓ Полный процесс SSL
3. Production:
%(prog)s -c config.json --obtain ✓ Боевой сертификат
letsencrypt-regru --obtain ✓ Боевой сертификат
════════════════════════════════════════════════════════════════════════════════
СРАВНЕНИЕ РЕЖИМОВ ТЕСТИРОВАНИЯ
@@ -1518,6 +1627,11 @@ def main():
help="Подробный вывод для диагностики",
action="store_true"
)
parser.add_argument(
"--force-cleanup",
help="Принудительная очистка lock-файлов Certbot (если процесс завис)",
action="store_true"
)
args = parser.parse_args()
@@ -1526,6 +1640,66 @@ def main():
create_sample_config(args.create_config)
return 0
# Принудительная очистка lock-файлов
if args.force_cleanup:
print("=" * 80)
print("ПРИНУДИТЕЛЬНАЯ ОЧИСТКА LOCK-ФАЙЛОВ CERTBOT")
print("=" * 80)
lock_files = [
"/var/lib/letsencrypt/.certbot.lock",
"/etc/letsencrypt/.certbot.lock",
]
# Проверяем запущенные процессы
try:
result = subprocess.run(
["ps", "aux"],
capture_output=True,
text=True
)
certbot_processes = [
line for line in result.stdout.split('\n')
if 'certbot' in line.lower() and 'grep' not in line.lower()
]
if certbot_processes:
print("\n⚠️ ПРЕДУПРЕЖДЕНИЕ: Обнаружены запущенные процессы Certbot:")
for proc in certbot_processes:
print(f" {proc}")
print("\nРекомендуется сначала остановить процессы:")
print(" sudo pkill certbot")
print("\nПродолжить очистку lock-файлов? (y/N): ", end='')
response = input().strip().lower()
if response != 'y':
print("Отменено.")
return 0
except Exception as e:
print(f"Не удалось проверить процессы: {e}")
# Удаляем lock-файлы
removed_count = 0
for lock_file in lock_files:
if os.path.exists(lock_file):
try:
os.remove(lock_file)
print(f"✅ Удалён: {lock_file}")
removed_count += 1
except Exception as e:
print(f"❌ Ошибка при удалении {lock_file}: {e}")
else:
print(f" Не найден: {lock_file}")
print("\n" + "=" * 80)
if removed_count > 0:
print(f"✅ Удалено lock-файлов: {removed_count}")
print("Теперь можно попробовать запустить Certbot снова.")
else:
print(" Lock-файлы не найдены.")
print("=" * 80)
return 0
# Загрузка конфигурации
config = load_config(args.config)