Files
configure_nginx_manager/Makefile

769 lines
43 KiB
Makefile
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# ==============================================================================
# Makefile для установки и удаления скрипта управления SSL сертификатами
# Let's Encrypt с DNS-валидацией через API reg.ru
# ==============================================================================
# Переменные
INSTALL_DIR = /opt/letsencrypt-regru
SCRIPT_NAME = letsencrypt_regru_api.py
CONFIG_EXAMPLE = config.json.example
SERVICE_NAME = letsencrypt-regru
SERVICE_FILE = $(SERVICE_NAME).service
TIMER_FILE = $(SERVICE_NAME).timer
CONFIG_DIR = /etc/letsencrypt
CONFIG_FILE = $(CONFIG_DIR)/regru_config.json
LOG_DIR = /var/log
LOG_FILE = $(LOG_DIR)/letsencrypt_regru.log
CRON_LOG = $(LOG_DIR)/letsencrypt_cron.log
SYSTEMD_DIR = /etc/systemd/system
PYTHON = python3
# Цвета для вывода
RED = \033[0;31m
GREEN = \033[0;32m
YELLOW = \033[1;33m
BLUE = \033[0;34m
NC = \033[0m # No Color
.PHONY: help install uninstall status check-root setup-dirs install-script install-service install-cron clean build build-linux build-windows build-all package-linux package-windows release
# Переменные для сборки
PYINSTALLER = pyinstaller
APP_NAME = letsencrypt-regru
DIST_DIR = dist
BUILD_DIR_PY = build
SPEC_FILE = $(APP_NAME).spec
# ==============================================================================
# Помощь
# ==============================================================================
help:
@echo "$(BLUE)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(BLUE)║ Makefile для управления Let's Encrypt SSL сертификатами ║$(NC)"
@echo "$(BLUE)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
@echo "$(GREEN)Команды для установки:$(NC)"
@echo ""
@echo " $(YELLOW)make install$(NC) - Установить скрипт и настроить автоматизацию"
@echo " $(YELLOW)make uninstall$(NC) - Удалить скрипт и очистить систему"
@echo " $(YELLOW)make status$(NC) - Проверить статус установки"
@echo " $(YELLOW)make check-config$(NC) - Проверить конфигурацию"
@echo " $(YELLOW)make test-run$(NC) - Тестовый запуск скрипта"
@echo " $(YELLOW)make test-cert$(NC) - Создать тестовый самоподписанный сертификат"
@echo " $(YELLOW)make logs$(NC) - Показать логи"
@echo ""
@echo "$(GREEN)Команды для сборки (PyInstaller):$(NC)"
@echo ""
@echo " $(YELLOW)make build$(NC) - Собрать исполняемый файл для текущей ОС"
@echo " $(YELLOW)make build-linux$(NC) - Собрать исполняемый файл для Linux"
@echo " $(YELLOW)make build-windows$(NC) - Собрать исполняемый файл для Windows"
@echo " $(YELLOW)make build-all$(NC) - Собрать для всех платформ"
@echo " $(YELLOW)make package-linux$(NC) - Создать tar.gz пакет для Linux"
@echo " $(YELLOW)make package-windows$(NC) - Создать zip пакет для Windows"
@echo " $(YELLOW)make release$(NC) - Полный цикл релиза (build + package)"
@echo " $(YELLOW)make clean-build$(NC) - Очистить артефакты сборки"
@echo ""
@echo " $(YELLOW)make help$(NC) - Показать эту справку"
@echo ""
# ==============================================================================
# Проверка прав root
# ==============================================================================
check-root:
@if [ "$$(id -u)" != "0" ]; then \
echo "$(RED)✗ Ошибка: Требуются права root$(NC)"; \
echo "$(YELLOW)Запустите: sudo make install$(NC)"; \
exit 1; \
fi
# ==============================================================================
# Установка
# ==============================================================================
install: check-root
@echo "$(BLUE)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(BLUE)║ Установка Let's Encrypt SSL Manager ║$(NC)"
@echo "$(BLUE)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
@$(MAKE) setup-dirs
@$(MAKE) install-dependencies
@$(MAKE) install-script
@$(MAKE) install-service
@$(MAKE) install-cron
@echo ""
@echo "$(GREEN)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(GREEN)║ ✓ Установка завершена успешно! ║$(NC)"
@echo "$(GREEN)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
@echo "$(YELLOW)Следующие шаги:$(NC)"
@echo " 1. Отредактируйте конфигурацию:"
@echo " $(BLUE)sudo nano $(CONFIG_FILE)$(NC)"
@echo ""
@echo " 2. Проверьте конфигурацию:"
@echo " $(BLUE)make check-config$(NC)"
@echo ""
@echo " 3. Запустите тестовую проверку:"
@echo " $(BLUE)make test-run$(NC)"
@echo ""
@echo " 4. Проверьте статус службы:"
@echo " $(BLUE)make status$(NC)"
@echo ""
# Создание директорий
setup-dirs:
@echo "$(YELLOW)→ Создание директорий...$(NC)"
@mkdir -p $(INSTALL_DIR)
@mkdir -p $(CONFIG_DIR)
@mkdir -p $(LOG_DIR)
@echo "$(GREEN)✓ Директории созданы$(NC)"
# Установка зависимостей
install-dependencies:
@echo "$(YELLOW)→ Установка зависимостей Python...$(NC)"
@if command -v pip3 >/dev/null 2>&1; then \
pip3 install -q requests cryptography 2>/dev/null || pip3 install requests cryptography; \
elif command -v pip >/dev/null 2>&1; then \
pip install -q requests cryptography 2>/dev/null || pip install requests cryptography; \
elif command -v python3 >/dev/null 2>&1; then \
if python3 -m pip --version >/dev/null 2>&1; then \
python3 -m pip install -q requests cryptography 2>/dev/null || python3 -m pip install requests cryptography; \
else \
echo "$(RED)✗ pip не установлен. Выполните:$(NC)"; \
echo " $(CYAN)sudo apt-get update && sudo apt-get install -y python3-pip$(NC)"; \
echo " или"; \
echo " $(CYAN)curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py && python3 get-pip.py$(NC)"; \
exit 1; \
fi; \
elif command -v python >/dev/null 2>&1; then \
if python -m pip --version >/dev/null 2>&1; then \
python -m pip install -q requests cryptography 2>/dev/null || python -m pip install requests cryptography; \
else \
echo "$(RED)✗ pip не установлен. Выполните:$(NC)"; \
echo " $(CYAN)sudo apt-get update && sudo apt-get install -y python3-pip$(NC)"; \
exit 1; \
fi; \
else \
echo "$(RED)✗ Python не найден. Установите Python 3:$(NC)"; \
echo " $(CYAN)sudo apt-get update && sudo apt-get install -y python3 python3-pip$(NC)"; \
exit 1; \
fi
@echo "$(GREEN)✓ Зависимости установлены$(NC)"
# Копирование скрипта
install-script:
@echo "$(YELLOW)→ Установка скрипта...$(NC)"
@if [ ! -f "$(SCRIPT_NAME)" ]; then \
echo "$(RED)✗ Файл $(SCRIPT_NAME) не найден!$(NC)"; \
exit 1; \
fi
@cp $(SCRIPT_NAME) $(INSTALL_DIR)/
@chmod +x $(INSTALL_DIR)/$(SCRIPT_NAME)
@echo "$(GREEN)✓ Скрипт установлен в $(INSTALL_DIR)/$(NC)"
@echo ""
@echo "$(YELLOW)→ Создание конфигурации...$(NC)"
@if [ ! -f "$(CONFIG_FILE)" ]; then \
if [ -f "$(CONFIG_EXAMPLE)" ]; then \
cp $(CONFIG_EXAMPLE) $(CONFIG_FILE); \
chmod 600 $(CONFIG_FILE); \
echo "$(GREEN)✓ Создан файл конфигурации: $(CONFIG_FILE)$(NC)"; \
echo "$(YELLOW)⚠ ВНИМАНИЕ: Отредактируйте конфигурацию перед использованием!$(NC)"; \
else \
echo "$(YELLOW)⚠ Файл config.json.example не найден$(NC)"; \
$(PYTHON) $(INSTALL_DIR)/$(SCRIPT_NAME) --create-config $(CONFIG_FILE); \
chmod 600 $(CONFIG_FILE); \
echo "$(GREEN)✓ Создана конфигурация по умолчанию$(NC)"; \
fi \
else \
echo "$(GREEN)✓ Конфигурация уже существует: $(CONFIG_FILE)$(NC)"; \
fi
# Установка systemd service и timer
install-service:
@echo "$(YELLOW)→ Создание systemd service...$(NC)"
@echo "[Unit]" > $(SYSTEMD_DIR)/$(SERVICE_FILE)
@echo "Description=Let's Encrypt Certificate Manager with reg.ru DNS" >> $(SYSTEMD_DIR)/$(SERVICE_FILE)
@echo "After=network.target" >> $(SYSTEMD_DIR)/$(SERVICE_FILE)
@echo "" >> $(SYSTEMD_DIR)/$(SERVICE_FILE)
@echo "[Service]" >> $(SYSTEMD_DIR)/$(SERVICE_FILE)
@echo "Type=oneshot" >> $(SYSTEMD_DIR)/$(SERVICE_FILE)
@echo "ExecStart=$(PYTHON) $(INSTALL_DIR)/$(SCRIPT_NAME) -c $(CONFIG_FILE)" >> $(SYSTEMD_DIR)/$(SERVICE_FILE)
@echo "StandardOutput=journal" >> $(SYSTEMD_DIR)/$(SERVICE_FILE)
@echo "StandardError=journal" >> $(SYSTEMD_DIR)/$(SERVICE_FILE)
@echo "User=root" >> $(SYSTEMD_DIR)/$(SERVICE_FILE)
@echo "" >> $(SYSTEMD_DIR)/$(SERVICE_FILE)
@echo "[Install]" >> $(SYSTEMD_DIR)/$(SERVICE_FILE)
@echo "WantedBy=multi-user.target" >> $(SYSTEMD_DIR)/$(SERVICE_FILE)
@echo "$(GREEN)✓ Service файл создан$(NC)"
@echo ""
@echo "$(YELLOW)→ Создание systemd timer...$(NC)"
@echo "[Unit]" > $(SYSTEMD_DIR)/$(TIMER_FILE)
@echo "Description=Daily Let's Encrypt Certificate Check and Renewal" >> $(SYSTEMD_DIR)/$(TIMER_FILE)
@echo "Requires=$(SERVICE_FILE)" >> $(SYSTEMD_DIR)/$(TIMER_FILE)
@echo "" >> $(SYSTEMD_DIR)/$(TIMER_FILE)
@echo "[Timer]" >> $(SYSTEMD_DIR)/$(TIMER_FILE)
@echo "OnCalendar=daily" >> $(SYSTEMD_DIR)/$(TIMER_FILE)
@echo "Persistent=true" >> $(SYSTEMD_DIR)/$(TIMER_FILE)
@echo "RandomizedDelaySec=1h" >> $(SYSTEMD_DIR)/$(TIMER_FILE)
@echo "" >> $(SYSTEMD_DIR)/$(TIMER_FILE)
@echo "[Install]" >> $(SYSTEMD_DIR)/$(TIMER_FILE)
@echo "WantedBy=timers.target" >> $(SYSTEMD_DIR)/$(TIMER_FILE)
@echo "$(GREEN)✓ Timer файл создан$(NC)"
@echo ""
@echo "$(YELLOW)→ Активация systemd службы...$(NC)"
@systemctl daemon-reload
@systemctl enable $(SERVICE_FILE) 2>/dev/null || true
@systemctl enable $(TIMER_FILE) 2>/dev/null || true
@systemctl start $(TIMER_FILE) 2>/dev/null || true
@echo "$(GREEN)✓ Systemd служба активирована$(NC)"
# Установка cron задачи
install-cron:
@echo "$(YELLOW)→ Настройка cron задачи...$(NC)"
@CRON_CMD="0 3 * * * $(PYTHON) $(INSTALL_DIR)/$(SCRIPT_NAME) -c $(CONFIG_FILE) >> $(CRON_LOG) 2>&1"; \
(crontab -l 2>/dev/null | grep -v "$(SCRIPT_NAME)" ; echo "$$CRON_CMD") | crontab -
@echo "$(GREEN)✓ Cron задача добавлена (ежедневно в 3:00 AM)$(NC)"
# ==============================================================================
# Удаление
# ==============================================================================
uninstall: check-root
@echo "$(RED)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(RED)║ Удаление Let's Encrypt SSL Manager ║$(NC)"
@echo "$(RED)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
@printf "Вы уверены? Это удалит все файлы и настройки [y/N]: "; \
read REPLY; \
case "$$REPLY" in \
[Yy]* ) \
$(MAKE) remove-service; \
$(MAKE) remove-cron; \
$(MAKE) remove-files; \
echo ""; \
echo "$(GREEN)✓ Удаление завершено$(NC)"; \
;; \
* ) \
echo "$(YELLOW)Удаление отменено$(NC)"; \
;; \
esac
# Удаление systemd service
remove-service:
@echo "$(YELLOW)→ Остановка и удаление systemd служб...$(NC)"
@systemctl stop $(TIMER_FILE) 2>/dev/null || true
@systemctl stop $(SERVICE_FILE) 2>/dev/null || true
@systemctl disable $(TIMER_FILE) 2>/dev/null || true
@systemctl disable $(SERVICE_FILE) 2>/dev/null || true
@rm -f $(SYSTEMD_DIR)/$(SERVICE_FILE)
@rm -f $(SYSTEMD_DIR)/$(TIMER_FILE)
@systemctl daemon-reload
@echo "$(GREEN)✓ Systemd службы удалены$(NC)"
# Удаление cron задачи
remove-cron:
@echo "$(YELLOW)→ Удаление cron задачи...$(NC)"
@crontab -l 2>/dev/null | grep -v "$(SCRIPT_NAME)" | crontab - 2>/dev/null || true
@echo "$(GREEN)✓ Cron задача удалена$(NC)"
# Удаление файлов
remove-files:
@echo "$(YELLOW)→ Удаление файлов...$(NC)"
@rm -rf $(INSTALL_DIR)
@echo "$(GREEN)✓ Директория $(INSTALL_DIR) удалена$(NC)"
@echo ""
@printf "Удалить конфигурацию $(CONFIG_FILE)? [y/N]: "; \
read REPLY; \
case "$$REPLY" in \
[Yy]* ) \
rm -f $(CONFIG_FILE); \
echo "$(GREEN)✓ Конфигурация удалена$(NC)"; \
;; \
* ) \
echo "$(YELLOW)Конфигурация сохранена$(NC)"; \
;; \
esac
@echo ""
@printf "Удалить логи? [y/N]: "; \
read REPLY; \
case "$$REPLY" in \
[Yy]* ) \
rm -f $(LOG_FILE) $(CRON_LOG); \
echo "$(GREEN)✓ Логи удалены$(NC)"; \
;; \
* ) \
echo "$(YELLOW)Логи сохранены$(NC)"; \
;; \
esac
# ==============================================================================
# Утилиты
# ==============================================================================
# Проверка статуса
status:
@echo "$(BLUE)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(BLUE)║ Статус Let's Encrypt SSL Manager ║$(NC)"
@echo "$(BLUE)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
@echo "$(YELLOW)→ Установка:$(NC)"
@if [ -d "$(INSTALL_DIR)" ]; then \
echo " $(GREEN)✓ Директория: $(INSTALL_DIR)$(NC)"; \
else \
echo " $(RED)✗ Директория не найдена$(NC)"; \
fi
@if [ -f "$(INSTALL_DIR)/$(SCRIPT_NAME)" ]; then \
echo " $(GREEN)✓ Скрипт установлен$(NC)"; \
else \
echo " $(RED)✗ Скрипт не найден$(NC)"; \
fi
@if [ -f "$(CONFIG_FILE)" ]; then \
echo " $(GREEN)✓ Конфигурация: $(CONFIG_FILE)$(NC)"; \
else \
echo " $(YELLOW)⚠ Конфигурация не найдена$(NC)"; \
fi
@echo ""
@echo "$(YELLOW)→ Systemd служба:$(NC)"
@systemctl is-enabled $(SERVICE_FILE) 2>/dev/null && echo " $(GREEN)✓ Service включен$(NC)" || echo " $(RED)✗ Service отключен$(NC)"
@systemctl is-active $(SERVICE_FILE) 2>/dev/null && echo " $(GREEN)✓ Service активен$(NC)" || echo " $(YELLOW)⚠ Service неактивен (oneshot)$(NC)"
@echo ""
@echo "$(YELLOW)→ Systemd timer:$(NC)"
@systemctl is-enabled $(TIMER_FILE) 2>/dev/null && echo " $(GREEN)✓ Timer включен$(NC)" || echo " $(RED)✗ Timer отключен$(NC)"
@systemctl is-active $(TIMER_FILE) 2>/dev/null && echo " $(GREEN)✓ Timer активен$(NC)" || echo " $(RED)✗ Timer неактивен$(NC)"
@echo ""
@echo "$(YELLOW)→ Следующий запуск:$(NC)"
@systemctl list-timers $(TIMER_FILE) --no-pager 2>/dev/null || echo " $(RED)✗ Timer не найден$(NC)"
@echo ""
@echo "$(YELLOW)→ Cron задача:$(NC)"
@if crontab -l 2>/dev/null | grep -q "$(SCRIPT_NAME)"; then \
echo " $(GREEN)✓ Cron задача настроена$(NC)"; \
crontab -l 2>/dev/null | grep "$(SCRIPT_NAME)"; \
else \
echo " $(RED)✗ Cron задача не найдена$(NC)"; \
fi
# Проверка конфигурации
check-config:
@echo "$(BLUE)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(BLUE)║ Проверка конфигурации ║$(NC)"
@echo "$(BLUE)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
@if [ ! -f "$(CONFIG_FILE)" ]; then \
echo "$(RED)✗ Конфигурация не найдена: $(CONFIG_FILE)$(NC)"; \
echo "$(YELLOW)Совет: Скопируйте config.json.example в $(CONFIG_FILE)$(NC)"; \
echo " $(CYAN)sudo cp config.json.example $(CONFIG_FILE)$(NC)"; \
echo " $(CYAN)sudo chmod 644 $(CONFIG_FILE)$(NC)"; \
exit 1; \
fi
@echo "$(GREEN)✓ Конфигурация найдена$(NC)"
@if [ ! -r "$(CONFIG_FILE)" ]; then \
echo "$(RED)✗ Нет прав для чтения: $(CONFIG_FILE)$(NC)"; \
echo "$(YELLOW)Решение: Запустите команду с sudo:$(NC)"; \
echo " $(CYAN)sudo make check-config$(NC)"; \
exit 1; \
fi
@echo ""
@$(PYTHON) -c "import json; print(json.dumps(json.load(open('$(CONFIG_FILE)')), indent=2, ensure_ascii=False))" 2>&1 || \
(echo "$(RED)✗ Ошибка: Неверный формат JSON$(NC)"; \
echo "$(YELLOW)Подробности:$(NC)"; \
$(PYTHON) -c "import json; json.load(open('$(CONFIG_FILE)'))" 2>&1 | head -5; \
exit 1)
@echo ""
@echo "$(YELLOW)→ Проверка обязательных параметров:$(NC)"
@$(PYTHON) -c "import json; c=json.load(open('$(CONFIG_FILE)')); assert c.get('regru_username'), 'regru_username не задан'" && echo " $(GREEN)✓ regru_username$(NC)" || echo " $(RED)✗ regru_username$(NC)"
@$(PYTHON) -c "import json; c=json.load(open('$(CONFIG_FILE)')); assert c.get('regru_password'), 'regru_password не задан'" && echo " $(GREEN)✓ regru_password$(NC)" || echo " $(RED)✗ regru_password$(NC)"
@$(PYTHON) -c "import json; c=json.load(open('$(CONFIG_FILE)')); assert c.get('domain'), 'domain не задан'" && echo " $(GREEN)✓ domain$(NC)" || echo " $(RED)✗ domain$(NC)"
@$(PYTHON) -c "import json; c=json.load(open('$(CONFIG_FILE)')); assert c.get('email'), 'email не задан'" && echo " $(GREEN)✓ email$(NC)" || echo " $(RED)✗ email$(NC)"
# Тестовый запуск
test-run: check-root
@echo "$(BLUE)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(BLUE)║ Тестовый запуск скрипта ║$(NC)"
@echo "$(BLUE)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
@if [ ! -f "$(CONFIG_FILE)" ]; then \
echo "$(RED)✗ Конфигурация не найдена. Запустите: make install$(NC)"; \
exit 1; \
fi
@echo "$(YELLOW)→ Запуск проверки сертификата...$(NC)"
@echo ""
@$(PYTHON) $(INSTALL_DIR)/$(SCRIPT_NAME) -c $(CONFIG_FILE) --check -v
# Просмотр логов
logs:
@echo "$(BLUE)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(BLUE)║ Логи Let's Encrypt SSL Manager ║$(NC)"
@echo "$(BLUE)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
@echo "$(YELLOW)→ Основной лог скрипта:$(NC)"
@if [ -f "$(LOG_FILE)" ]; then \
tail -n 50 $(LOG_FILE); \
else \
echo "$(YELLOW)Лог файл не найден$(NC)"; \
fi
@echo ""
@echo "$(YELLOW)→ Лог cron задачи:$(NC)"
@if [ -f "$(CRON_LOG)" ]; then \
tail -n 50 $(CRON_LOG); \
else \
echo "$(YELLOW)Лог cron не найден$(NC)"; \
fi
@echo ""
@echo "$(YELLOW)→ Логи systemd:$(NC)"
@journalctl -u $(SERVICE_FILE) -n 50 --no-pager 2>/dev/null || echo "$(YELLOW)Логи systemd не найдены$(NC)"
# Ручной запуск обновления
run: check-root
@echo "$(YELLOW)→ Запуск обновления сертификата...$(NC)"
@$(PYTHON) $(INSTALL_DIR)/$(SCRIPT_NAME) -c $(CONFIG_FILE) -v
# Принудительное получение сертификата
obtain: check-root
@echo "$(YELLOW)→ Принудительное получение нового сертификата...$(NC)"
@$(PYTHON) $(INSTALL_DIR)/$(SCRIPT_NAME) -c $(CONFIG_FILE) --obtain -v
# Принудительное обновление сертификата
renew: check-root
@echo "$(YELLOW)→ Принудительное обновление сертификата...$(NC)"
@$(PYTHON) $(INSTALL_DIR)/$(SCRIPT_NAME) -c $(CONFIG_FILE) --renew -v
# Создание тестового самоподписанного сертификата
test-cert: check-root
@echo "$(BLUE)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(BLUE)║ Создание тестового самоподписанного сертификата ║$(NC)"
@echo "$(BLUE)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
@echo "$(YELLOW)⚠️ ВНИМАНИЕ: Это тестовый сертификат для разработки!$(NC)"
@echo "$(YELLOW) Браузеры будут показывать предупреждение безопасности.$(NC)"
@echo "$(YELLOW) Для production используйте Let's Encrypt сертификаты.$(NC)"
@echo ""
@if [ ! -f "$(CONFIG_FILE)" ]; then \
echo "$(RED)✗ Конфигурация не найдена. Запустите: make install$(NC)"; \
exit 1; \
fi
@echo "$(YELLOW)→ Генерация самоподписанного сертификата...$(NC)"
@echo ""
@$(PYTHON) $(INSTALL_DIR)/$(SCRIPT_NAME) -c $(CONFIG_FILE) --test-cert -v
@echo ""
@echo "$(GREEN)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(GREEN)║ ✓ Тестовый сертификат создан ║$(NC)"
@echo "$(GREEN)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
@echo "$(YELLOW)Преимущества тестового сертификата:$(NC)"
@echo " • Нет ограничений Let's Encrypt (5 сертификатов в неделю)"
@echo " • Мгновенное создание без DNS-валидации"
@echo " • Идеально для тестирования интеграции с NPM"
@echo " • Можно создавать неограниченное количество раз"
@echo ""
@echo "$(YELLOW)Примечание:$(NC)"
@echo " Тестовый сертификат НЕ доверяется браузерами."
@echo " Используйте только для локальной разработки и тестирования."
@echo ""
# Очистка временных файлов
clean:
@echo "$(YELLOW)→ Очистка временных файлов...$(NC)"
@find . -type f -name "*.pyc" -delete
@find . -type d -name "__pycache__" -delete
@echo "$(GREEN)✓ Очистка завершена$(NC)"
# ==============================================================================
# Сборка исполняемых файлов с PyInstaller
# ==============================================================================
# Установка PyInstaller
install-pyinstaller:
@echo "$(YELLOW)→ Установка PyInstaller...$(NC)"
@if command -v pip3 >/dev/null 2>&1; then \
pip3 install --upgrade pyinstaller; \
elif command -v pip >/dev/null 2>&1; then \
pip install --upgrade pyinstaller; \
else \
echo "$(RED)✗ pip не найден. Установите pip сначала.$(NC)"; \
exit 1; \
fi
@echo "$(GREEN)✓ PyInstaller установлен$(NC)"
# Сборка для текущей ОС
build:
@echo "$(BLUE)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(BLUE)║ Сборка исполняемого файла для текущей ОС$(NC)"
@echo "$(BLUE)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
@if ! command -v $(PYINSTALLER) >/dev/null 2>&1; then \
echo "$(YELLOW)PyInstaller не найден. Установка...$(NC)"; \
$(MAKE) install-pyinstaller; \
fi
@echo "$(YELLOW)→ Компиляция $(SCRIPT_NAME) в исполняемый файл...$(NC)"
@$(PYINSTALLER) --onefile \
--name $(APP_NAME) \
--add-data "README.md:." \
--hidden-import requests \
--hidden-import certbot \
--hidden-import cryptography \
--collect-all certbot \
--noconfirm \
$(SCRIPT_NAME)
@echo ""
@echo "$(GREEN)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(GREEN)║ ✓ Сборка завершена успешно! ║$(NC)"
@echo "$(GREEN)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
@echo "$(YELLOW)Исполняемый файл:$(NC)"
@ls -lh $(DIST_DIR)/$(APP_NAME) 2>/dev/null || dir $(DIST_DIR)\$(APP_NAME).exe 2>/dev/null || echo " $(DIST_DIR)/$(APP_NAME)"
@echo ""
@echo "$(YELLOW)Размер файла:$(NC)"
@du -h $(DIST_DIR)/$(APP_NAME) 2>/dev/null || echo " ~40-60 MB (включая Python runtime и все библиотеки)"
@echo ""
@echo "$(YELLOW)Примечание:$(NC)"
@echo " • Исполняемый файл содержит весь Python runtime"
@echo " • Certbot все равно должен быть установлен в системе"
@echo " • Запускайте с sudo для работы с сертификатами"
# Сборка для Linux
build-linux:
@echo "$(BLUE)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(BLUE)║ Сборка исполняемого файла для Linux ║$(NC)"
@echo "$(BLUE)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
@UNAME=$$(uname -s 2>/dev/null || echo "Unknown"); \
if [ "$$UNAME" != "Linux" ]; then \
echo "$(RED)ВНИМАНИЕ: Сборка на $$UNAME, но целевая ОС - Linux$(NC)"; \
echo "$(YELLOW)Рекомендуется собирать на Linux для лучшей совместимости$(NC)"; \
echo ""; \
fi
@if ! command -v $(PYINSTALLER) >/dev/null 2>&1; then \
echo "$(YELLOW)PyInstaller не найден. Установка...$(NC)"; \
$(MAKE) install-pyinstaller; \
fi
@echo "$(YELLOW)→ Компиляция для Linux (x86_64)...$(NC)"
@$(PYINSTALLER) --onefile \
--name $(APP_NAME) \
--add-data "README.md:." \
--hidden-import requests \
--hidden-import certbot \
--hidden-import cryptography \
--collect-all certbot \
--target-arch x86_64 \
--noconfirm \
$(SCRIPT_NAME)
@echo ""
@echo "$(GREEN)✓ Сборка для Linux завершена!$(NC)"
@echo ""
@echo "$(YELLOW)Исполняемый файл:$(NC) $(DIST_DIR)/$(APP_NAME)"
@file $(DIST_DIR)/$(APP_NAME) 2>/dev/null || echo " ELF 64-bit executable"
@ls -lh $(DIST_DIR)/$(APP_NAME) 2>/dev/null || echo ""
# Сборка для Windows
build-windows:
@echo "$(BLUE)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(BLUE)║ Сборка исполняемого файла для Windows ║$(NC)"
@echo "$(BLUE)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
@UNAME=$$(uname -s 2>/dev/null || echo "Windows"); \
SEPARATOR=";"; \
if [ "$$UNAME" = "Linux" ] || [ "$$UNAME" = "Darwin" ]; then \
echo "$(RED)ВНИМАНИЕ: Кросс-компиляция для Windows из $$UNAME$(NC)"; \
echo "$(YELLOW)Используем разделитель ':' вместо ';' для PyInstaller$(NC)"; \
echo "$(YELLOW)Рекомендуется: собирайте на нативной Windows для лучших результатов$(NC)"; \
echo ""; \
SEPARATOR=":"; \
fi; \
if ! command -v $(PYINSTALLER) >/dev/null 2>&1; then \
echo "$(YELLOW)PyInstaller не найден. Установка...$(NC)"; \
$(MAKE) install-pyinstaller; \
fi; \
echo "$(YELLOW)→ Компиляция для Windows (x86_64) с разделителем $$SEPARATOR...$(NC)"; \
$(PYINSTALLER) --onefile \
--name $(APP_NAME) \
--add-data "README.md$${SEPARATOR}." \
--hidden-import requests \
--hidden-import certbot \
--hidden-import cryptography \
--collect-all certbot \
--icon NONE \
--noconfirm \
$(SCRIPT_NAME)
@echo ""
@echo "$(GREEN)✓ Сборка для Windows завершена!$(NC)"
@echo ""
@echo "$(YELLOW)Исполняемый файл:$(NC) $(DIST_DIR)/$(APP_NAME).exe"
@ls -lh $(DIST_DIR)/$(APP_NAME).exe 2>/dev/null || dir $(DIST_DIR)\$(APP_NAME).exe 2>/dev/null || echo ""
# Сборка для всех платформ
build-all:
@echo "$(BLUE)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(BLUE)║ Сборка для всех платформ ║$(NC)"
@echo "$(BLUE)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
@echo "$(RED)⚠️ ВНИМАНИЕ: Кросс-компиляция Windows из Linux НЕ РАБОТАЕТ!$(NC)"
@echo "$(YELLOW)→ PyInstaller не может создать .exe файл на Linux/macOS$(NC)"
@echo "$(YELLOW)→ Для Windows сборки используйте нативную Windows систему$(NC)"
@echo ""
@echo "$(YELLOW)Рекомендации:$(NC)"
@echo " • Собирать Linux версию на Linux (работает ✓)"
@echo " • Собирать Windows версию на Windows (обязательно!)"
@echo " • Использовать GitHub Actions для автоматической сборки"
@echo ""
@$(MAKE) build-linux
@echo ""
@UNAME=$$(uname -s 2>/dev/null || echo "Windows"); \
if [ "$$UNAME" != "Windows" ] && [ "$$UNAME" != "MINGW"* ] && [ "$$UNAME" != "MSYS"* ]; then \
echo "$(YELLOW)Пропускаем Windows сборку (текущая ОС: $$UNAME)$(NC)"; \
echo "$(YELLOW)Используйте Windows для создания .exe файла$(NC)"; \
else \
$(MAKE) build-windows; \
fi
@echo ""
@echo "$(GREEN)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(GREEN)║ ✓ Сборка завершена! ║$(NC)"
@echo "$(GREEN)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
@echo "$(YELLOW)Файлы в директории $(DIST_DIR)/:$(NC)"
@ls -lh $(DIST_DIR)/ 2>/dev/null || dir $(DIST_DIR) 2>/dev/null || echo " Проверьте $(DIST_DIR)/"
# Создание пакета для Linux (tar.gz)
package-linux: build-linux
@echo "$(BLUE)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(BLUE)║ Создание пакета для Linux ║$(NC)"
@echo "$(BLUE)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
@echo "$(YELLOW)→ Подготовка файлов...$(NC)"
@mkdir -p $(DIST_DIR)/package
@cp $(DIST_DIR)/$(APP_NAME) $(DIST_DIR)/package/
@cp README.md $(DIST_DIR)/package/ 2>/dev/null || true
@cp -r systemd $(DIST_DIR)/package/ 2>/dev/null || true
@if [ -f "config.json.example" ]; then \
cp config.json.example $(DIST_DIR)/package/; \
fi
@echo "$(YELLOW)→ Создание архива...$(NC)"
@cd $(DIST_DIR)/package && tar -czf ../$(APP_NAME)-linux-x86_64.tar.gz *
@rm -rf $(DIST_DIR)/package
@echo ""
@echo "$(GREEN)✓ Пакет создан:$(NC) $(DIST_DIR)/$(APP_NAME)-linux-x86_64.tar.gz"
@ls -lh $(DIST_DIR)/$(APP_NAME)-linux-x86_64.tar.gz
@echo ""
@echo "$(YELLOW)Содержимое пакета:$(NC)"
@tar -tzf $(DIST_DIR)/$(APP_NAME)-linux-x86_64.tar.gz | head -10
# Создание пакета для Windows (zip)
package-windows: build-windows
@echo "$(BLUE)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(BLUE)║ Создание пакета для Windows ║$(NC)"
@echo "$(BLUE)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
@if [ ! -f "$(DIST_DIR)/$(APP_NAME).exe" ]; then \
echo "$(RED)✗ Ошибка: Файл $(APP_NAME).exe не найден$(NC)"; \
echo "$(YELLOW)⚠️ Кросс-компиляция для Windows из Linux/macOS не создает .exe файл!$(NC)"; \
echo "$(YELLOW)→ Используйте нативную Windows систему для сборки Windows версии$(NC)"; \
echo ""; \
exit 1; \
fi
@echo "$(YELLOW)→ Подготовка файлов...$(NC)"
@mkdir -p $(DIST_DIR)/package
@cp $(DIST_DIR)/$(APP_NAME).exe $(DIST_DIR)/package/
@cp README.md $(DIST_DIR)/package/ 2>/dev/null || true
@if [ -f "config.json.example" ]; then cp config.json.example $(DIST_DIR)/package/; fi
@echo "$(YELLOW)→ Создание архива (tar.gz)...$(NC)"
@cd $(DIST_DIR)/package && tar -czf ../$(APP_NAME)-windows-x86_64.tar.gz *
@rm -rf $(DIST_DIR)/package
@echo ""
@echo "$(GREEN)✓ Пакет создан:$(NC) $(DIST_DIR)/$(APP_NAME)-windows-x86_64.tar.gz"
@ls -lh $(DIST_DIR)/$(APP_NAME)-windows-x86_64.tar.gz
@echo ""
@echo "$(YELLOW)Содержимое пакета:$(NC)"
@tar -tzf $(DIST_DIR)/$(APP_NAME)-windows-x86_64.tar.gz | head -10
# Полный цикл релиза
release:
@echo "$(BLUE)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(BLUE)║ ПОЛНЫЙ ЦИКЛ РЕЛИЗА ║$(NC)"
@echo "$(BLUE)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
@$(MAKE) clean-build
@$(MAKE) install-pyinstaller
@$(MAKE) build-all
@$(MAKE) package-linux
@$(MAKE) package-windows
@echo ""
@echo "$(GREEN)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(GREEN)║ ✓ РЕЛИЗ ГОТОВ! ║$(NC)"
@echo "$(GREEN)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
@echo "$(YELLOW)Артефакты релиза:$(NC)"
@ls -lh $(DIST_DIR)/*.tar.gz $(DIST_DIR)/*.zip 2>/dev/null || dir $(DIST_DIR)\*.zip 2>/dev/null || echo " Проверьте $(DIST_DIR)/"
@echo ""
@echo "$(YELLOW)Контрольные суммы SHA256:$(NC)"
@cd $(DIST_DIR) && sha256sum *.tar.gz *.zip 2>/dev/null || \
cd $(DIST_DIR) && certutil -hashfile $(APP_NAME)-windows-x86_64.zip SHA256 2>/dev/null || \
echo " Используйте sha256sum или certutil для проверки контрольных сумм"
@echo ""
@echo "$(YELLOW)Следующие шаги:$(NC)"
@echo " 1. Протестируйте исполняемые файлы"
@echo " 2. Создайте GitHub Release"
@echo " 3. Загрузите пакеты как Assets"
# Тестирование собранного файла
test-build:
@echo "$(BLUE)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(BLUE)║ Тестирование собранного файла ║$(NC)"
@echo "$(BLUE)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
@if [ -f "$(DIST_DIR)/$(APP_NAME)" ]; then \
echo "$(YELLOW)→ Тестирование Linux версии...$(NC)"; \
chmod +x $(DIST_DIR)/$(APP_NAME); \
$(DIST_DIR)/$(APP_NAME) --help; \
echo ""; \
echo "$(GREEN)✓ Linux версия работает$(NC)"; \
elif [ -f "$(DIST_DIR)/$(APP_NAME).exe" ]; then \
echo "$(YELLOW)→ Тестирование Windows версии...$(NC)"; \
$(DIST_DIR)/$(APP_NAME).exe --help; \
echo ""; \
echo "$(GREEN)✓ Windows версия работает$(NC)"; \
else \
echo "$(RED)✗ Исполняемый файл не найден$(NC)"; \
echo "$(YELLOW)Запустите 'make build' сначала$(NC)"; \
exit 1; \
fi
# Очистка артефактов сборки
clean-build:
@echo "$(YELLOW)→ Очистка артефактов сборки...$(NC)"
@rm -rf $(BUILD_DIR_PY) $(DIST_DIR) $(SPEC_FILE) __pycache__ *.pyc
@echo "$(GREEN)✓ Артефакты сборки удалены$(NC)"
# Информация о среде сборки
build-info:
@echo "$(BLUE)╔════════════════════════════════════════════════════════════════╗$(NC)"
@echo "$(BLUE)║ Информация о среде сборки ║$(NC)"
@echo "$(BLUE)╚════════════════════════════════════════════════════════════════╝$(NC)"
@echo ""
@echo "$(YELLOW)Система:$(NC)"
@echo " ОС: $$(uname -s 2>/dev/null || echo 'Windows')"
@echo " Архитектура: $$(uname -m 2>/dev/null || echo 'x86_64')"
@echo " Ядро: $$(uname -r 2>/dev/null || echo 'N/A')"
@echo ""
@echo "$(YELLOW)Python:$(NC)"
@echo " Версия: $$($(PYTHON) --version 2>&1)"
@echo " Путь: $$(which $(PYTHON) 2>/dev/null || where $(PYTHON) 2>/dev/null || echo 'N/A')"
@echo ""
@echo "$(YELLOW)PyInstaller:$(NC)"
@if command -v $(PYINSTALLER) >/dev/null 2>&1; then \
echo " Версия: $$($(PYINSTALLER) --version 2>&1)"; \
echo " Путь: $$(which $(PYINSTALLER) 2>/dev/null || where $(PYINSTALLER) 2>/dev/null)"; \
echo " $(GREEN)✓ Установлен$(NC)"; \
else \
echo " $(RED)Не установлен$(NC)"; \
echo " Установите: make install-pyinstaller"; \
fi
@echo ""
@echo "$(YELLOW)Конфигурация сборки:$(NC)"
@echo " Исходный файл: $(SCRIPT_NAME)"
@echo " Название приложения: $(APP_NAME)"
@echo " Директория сборки: $(DIST_DIR)/"
@echo ""
# По умолчанию показываем помощь
.DEFAULT_GOAL := help