diff --git a/.gitea/README.md b/.gitea/README.md new file mode 100644 index 0000000..95d5dd4 --- /dev/null +++ b/.gitea/README.md @@ -0,0 +1,330 @@ +# Настройка Gitea Actions для автоматической сборки + +## 📋 Предварительные требования + +### 1. Gitea с поддержкой Actions + +Убедитесь, что ваш Gitea имеет включенные Actions: + +```ini +# В app.ini Gitea +[actions] +ENABLED = true +DEFAULT_ACTIONS_URL = https://gitea.com +``` + +### 2. Gitea Runner + +Установите и настройте Gitea Act Runner: + +```bash +# Скачать runner +wget https://dl.gitea.com/act_runner/latest/act_runner-linux-amd64 -O act_runner +chmod +x act_runner + +# Зарегистрировать runner +./act_runner register --no-interactive \ + --instance https://your-gitea-instance.com \ + --token YOUR_RUNNER_TOKEN \ + --name my-runner + +# Запустить runner +./act_runner daemon +``` + +Или через Docker: + +```bash +docker run -d \ + --name gitea-runner \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -v $PWD/runner-data:/data \ + -e GITEA_INSTANCE_URL=https://your-gitea-instance.com \ + -e GITEA_RUNNER_REGISTRATION_TOKEN=YOUR_TOKEN \ + gitea/act_runner:latest +``` + +--- + +## 🚀 Использование + +### Создание релиза автоматически + +1. **Создайте и отправьте тег:** + +```bash +# Создать тег +git tag -a v1.0.0 -m "Release version 1.0.0" + +# Отправить тег на сервер +git push origin v1.0.0 +``` + +2. **Gitea автоматически:** + - Запустит workflow `.gitea/workflows/release.yml` + - Соберет Linux версию на Ubuntu runner + - Соберет Windows версию на Windows runner + - Создаст релиз с артефактами + - Добавит контрольные суммы SHA256 и MD5 + +### Ручной запуск workflow + +В веб-интерфейсе Gitea: + +1. Перейдите в **Repository → Actions** +2. Выберите workflow **Build and Release** +3. Нажмите **Run workflow** +4. Укажите версию (опционально) + +--- + +## 📂 Структура workflows + +``` +.gitea/ +└── workflows/ + ├── build-release.yml # Простой workflow (совместим с GitHub) + └── release.yml # Расширенный workflow с уведомлениями +``` + +### build-release.yml + +Базовый workflow, совместимый с GitHub Actions: +- Сборка для Linux и Windows +- Создание пакетов +- Генерация контрольных сумм +- Создание релиза + +**Использование:** +```bash +git tag v1.0.0 +git push origin v1.0.0 +``` + +### release.yml + +Расширенный workflow с дополнительными возможностями: +- Детальные release notes +- MD5 + SHA256 checksums +- Уведомления после релиза +- Поддержка ручного запуска + +**Использование:** +```bash +# Автоматически при теге +git tag v1.0.0 +git push origin v1.0.0 + +# Или вручную через веб-интерфейс +``` + +--- + +## 🔧 Настройка + +### Переменные окружения + +Workflow использует следующие переменные: + +| Переменная | Описание | Где установить | +|------------|----------|----------------| +| `GITEA_TOKEN` | Токен для создания релиза | Repository Secrets | +| `GITHUB_TOKEN` | Автоматически (fallback) | Встроенный | + +### Создание GITEA_TOKEN + +1. В Gitea: **Settings → Applications → Generate New Token** +2. Выберите права: `repo`, `write:packages` +3. Скопируйте токен +4. В репозитории: **Settings → Secrets → Add Secret** + - Name: `GITEA_TOKEN` + - Value: ваш токен + +--- + +## 📦 Артефакты релиза + +После успешной сборки в релизе будут доступны: + +``` +letsencrypt-regru-linux-x86_64.tar.gz +letsencrypt-regru-linux-x86_64.tar.gz.sha256 +letsencrypt-regru-linux-x86_64.tar.gz.md5 +letsencrypt-regru-windows-x86_64.zip +letsencrypt-regru-windows-x86_64.zip.sha256 +letsencrypt-regru-windows-x86_64.zip.md5 +``` + +--- + +## 🐛 Troubleshooting + +### Workflow не запускается + +**Проблема:** После push тега workflow не запускается + +**Решение:** +1. Проверьте, что Actions включены в настройках репозитория +2. Проверьте `.gitea/workflows/*.yml` на синтаксические ошибки +3. Убедитесь, что runner зарегистрирован и запущен + +```bash +# Проверить статус runner +./act_runner status + +# Посмотреть логи runner +./act_runner daemon --debug +``` + +--- + +### Ошибка при сборке Windows + +**Проблема:** `make: command not found` на Windows + +**Решение:** + +Установите Make для Windows или используйте альтернативный workflow: + +```yaml +- name: Build Windows executable (без make) + run: | + pyinstaller --onefile --name letsencrypt-regru letsencrypt_regru_api.py +``` + +--- + +### Релиз создается без файлов + +**Проблема:** Релиз создан, но артефакты отсутствуют + +**Решение:** + +Проверьте логи job `create-release`: + +1. Перейдите в **Actions → Build and Release → create-release** +2. Проверьте шаг "Download artifacts" +3. Убедитесь, что предыдущие jobs (`build-linux`, `build-windows`) завершились успешно + +--- + +### Permission denied при создании релиза + +**Проблема:** `Error: Resource not accessible by integration` + +**Решение:** + +1. Проверьте права токена: + - `GITEA_TOKEN` должен иметь права `repo` и `write:packages` + +2. Или используйте встроенный `GITHUB_TOKEN`: + - Убедитесь, что в настройках репозитория включены Actions + +--- + +## 📊 Мониторинг сборок + +### Просмотр логов + +1. **Web UI:** + - Repository → Actions + - Выберите workflow run + - Кликните на job для просмотра логов + +2. **API:** + ```bash + curl -H "Authorization: token YOUR_TOKEN" \ + https://your-gitea.com/api/v1/repos/USER/REPO/actions/runs + ``` + +### Статус badges + +Добавьте в README.md: + +```markdown +[![Build Status](https://your-gitea.com/USER/REPO/actions/workflows/release.yml/badge.svg)](https://your-gitea.com/USER/REPO/actions) +``` + +--- + +## 🔄 Автоматизация релизов + +### Semantic Versioning + +Используйте теги с семантическим версионированием: + +```bash +# Major release (несовместимые изменения) +git tag v2.0.0 + +# Minor release (новые функции) +git tag v1.1.0 + +# Patch release (исправления) +git tag v1.0.1 +``` + +### Pre-release + +Для тестовых релизов используйте suffix: + +```bash +git tag v1.0.0-beta.1 +git tag v1.0.0-rc.1 +``` + +В workflow автоматически будет установлен `prerelease: true` для таких тегов. + +--- + +## 📝 Changelog автоматизация + +### Использование conventional commits + +```bash +git commit -m "feat: добавлена поддержка wildcard сертификатов" +git commit -m "fix: исправлена ошибка загрузки в NPM" +git commit -m "docs: обновлена документация" +``` + +### Генерация CHANGELOG.md + +Добавьте в workflow: + +```yaml +- name: Generate Changelog + run: | + git log $(git describe --tags --abbrev=0)..HEAD --pretty=format:"- %s" > CHANGELOG.md +``` + +--- + +## 🎯 Рекомендации + +1. **Используйте теги только для стабильных релизов** + - Тестируйте перед созданием тега + - Проверяйте сборку локально: `make release` + +2. **Проверяйте контрольные суммы** + - Всегда включайте SHA256 и MD5 + - Документируйте процесс проверки для пользователей + +3. **Версионирование** + - Следуйте семантическому версионированию + - Документируйте breaking changes + +4. **Тестирование** + - Запускайте workflow вручную перед тегированием + - Проверяйте артефакты после сборки + +--- + +## 🔗 Полезные ссылки + +- [Gitea Actions Documentation](https://docs.gitea.com/next/usage/actions/overview) +- [Act Runner GitHub](https://github.com/nektos/act) +- [Workflow Syntax](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions) + +--- + +**Примечание:** Эти workflows совместимы с GitHub Actions и могут использоваться на обеих платформах. diff --git a/.gitea/workflows/build-release.yml b/.gitea/workflows/build-release.yml new file mode 100644 index 0000000..49a75c4 --- /dev/null +++ b/.gitea/workflows/build-release.yml @@ -0,0 +1,211 @@ +name: Build Releases + +on: + push: + tags: + - 'v*' # Срабатывает на теги вида v1.0, v2.0.1 и т.д. + workflow_dispatch: # Возможность запустить вручную + +jobs: + build-linux: + name: Build Linux Executable + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.9' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install pyinstaller + pip install -r requirements.txt + + - name: Build Linux executable + run: | + make build-linux + + - name: Test Linux executable + run: | + chmod +x dist/letsencrypt-regru + dist/letsencrypt-regru --help + + - name: Create Linux package + run: | + make package-linux + + - name: Upload Linux artifact + uses: actions/upload-artifact@v3 + with: + name: linux-executable + path: dist/letsencrypt-regru-linux-x86_64.tar.gz + + - name: Generate SHA256 checksum + run: | + cd dist + sha256sum letsencrypt-regru-linux-x86_64.tar.gz > letsencrypt-regru-linux-x86_64.tar.gz.sha256 + + - name: Upload checksum + uses: actions/upload-artifact@v3 + with: + name: linux-checksum + path: dist/letsencrypt-regru-linux-x86_64.tar.gz.sha256 + + build-windows: + name: Build Windows Executable + runs-on: windows-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.9' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install pyinstaller + pip install -r requirements.txt + + - name: Build Windows executable + run: | + make build-windows + + - name: Test Windows executable + run: | + dist\letsencrypt-regru.exe --help + + - name: Create Windows package + run: | + make package-windows + + - name: Upload Windows artifact + uses: actions/upload-artifact@v3 + with: + name: windows-executable + path: dist/letsencrypt-regru-windows-x86_64.zip + + - name: Generate SHA256 checksum + run: | + cd dist + certutil -hashfile letsencrypt-regru-windows-x86_64.zip SHA256 > letsencrypt-regru-windows-x86_64.zip.sha256 + + - name: Upload checksum + uses: actions/upload-artifact@v3 + with: + name: windows-checksum + path: dist/letsencrypt-regru-windows-x86_64.zip.sha256 + + create-release: + name: Create Gitea Release + needs: [build-linux, build-windows] + runs-on: ubuntu-latest + if: startsWith(github.ref, 'refs/tags/') + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Download Linux artifact + uses: actions/download-artifact@v3 + with: + name: linux-executable + path: ./artifacts + + - name: Download Linux checksum + uses: actions/download-artifact@v3 + with: + name: linux-checksum + path: ./artifacts + + - name: Download Windows artifact + uses: actions/download-artifact@v3 + with: + name: windows-executable + path: ./artifacts + + - name: Download Windows checksum + uses: actions/download-artifact@v3 + with: + name: windows-checksum + path: ./artifacts + + - name: Get tag name + id: get_version + run: echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT + + - name: Create Release + uses: actions/gitea-release@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + tag_name: ${{ steps.get_version.outputs.VERSION }} + name: Let's Encrypt RegRu Manager ${{ steps.get_version.outputs.VERSION }} + body: | + ## Let's Encrypt RegRu Manager ${{ steps.get_version.outputs.VERSION }} + + ### 📦 Релизные пакеты + + **Linux (Ubuntu/Debian/CentOS):** + - `letsencrypt-regru-linux-x86_64.tar.gz` - Исполняемый файл + файлы + - `letsencrypt-regru-linux-x86_64.tar.gz.sha256` - Контрольная сумма + + **Windows:** + - `letsencrypt-regru-windows-x86_64.zip` - Исполняемый файл + файлы + - `letsencrypt-regru-windows-x86_64.zip.sha256` - Контрольная сумма + + ### 🚀 Быстрая установка + + **Linux:** + ```bash + wget https://your-gitea-instance.com/${{ github.repository }}/releases/download/${{ steps.get_version.outputs.VERSION }}/letsencrypt-regru-linux-x86_64.tar.gz + tar -xzf letsencrypt-regru-linux-x86_64.tar.gz + sudo mv letsencrypt-regru /usr/local/bin/ + sudo chmod +x /usr/local/bin/letsencrypt-regru + ``` + + **Windows:** + Скачайте `letsencrypt-regru-windows-x86_64.zip` и распакуйте. + + ### 📖 Документация + + - [README.md](README.md) + - [BUILD_GUIDE.md](BUILD_GUIDE.md) + - [INSTALL_GUIDE.md](docs/INSTALL_GUIDE.md) + + ### ⚠️ Важно + + - Исполняемые файлы требуют установленного `certbot` в системе + - Linux версия требует права root (sudo) + - Windows версия не поддерживает certbot напрямую (используйте WSL) + + ### 🔐 Проверка контрольных сумм + + **Linux:** + ```bash + sha256sum -c letsencrypt-regru-linux-x86_64.tar.gz.sha256 + ``` + + **Windows:** + ```powershell + certutil -hashfile letsencrypt-regru-windows-x86_64.zip SHA256 + ``` + + ### 📝 Changelog + + - Автоматическая сборка релиза ${{ steps.get_version.outputs.VERSION }} + - См. коммиты для деталей изменений + files: | + ./artifacts/letsencrypt-regru-linux-x86_64.tar.gz + ./artifacts/letsencrypt-regru-linux-x86_64.tar.gz.sha256 + ./artifacts/letsencrypt-regru-windows-x86_64.zip + ./artifacts/letsencrypt-regru-windows-x86_64.zip.sha256 + draft: false + prerelease: false diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml new file mode 100644 index 0000000..a5256af --- /dev/null +++ b/.gitea/workflows/release.yml @@ -0,0 +1,387 @@ +name: Build and Release (Gitea Native) + +# Этот workflow оптимизирован для Gitea +# Использует нативные возможности Gitea Actions + +on: + push: + tags: + - 'v*' + - 'release-*' + workflow_dispatch: + inputs: + version: + description: 'Version tag (e.g., v1.0.0)' + required: false + default: 'dev' + +env: + APP_NAME: letsencrypt-regru + PYTHON_VERSION: '3.9' + +jobs: + # ============================================================================ + # Сборка для Linux + # ============================================================================ + build-linux: + name: 🐧 Build Linux + runs-on: ubuntu-latest + + steps: + - name: 📥 Checkout repository + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: 🐍 Set up Python ${{ env.PYTHON_VERSION }} + uses: actions/setup-python@v4 + with: + python-version: ${{ env.PYTHON_VERSION }} + cache: 'pip' + + - name: 📦 Install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y build-essential + + - name: 📚 Install Python dependencies + run: | + python -m pip install --upgrade pip setuptools wheel + pip install pyinstaller + if [ -f requirements.txt ]; then + pip install -r requirements.txt + else + pip install requests certbot cryptography + fi + + - name: ℹ️ Build info + run: | + make build-info + + - name: 🔨 Build Linux executable + run: | + make build-linux + + - name: ✅ Test executable + run: | + chmod +x dist/${{ env.APP_NAME }} + ./dist/${{ env.APP_NAME }} --help + ./dist/${{ env.APP_NAME }} --create-config /tmp/test_config.json + + - name: 📦 Create distribution package + run: | + make package-linux + + - name: 🔐 Generate checksums + run: | + cd dist + sha256sum ${{ env.APP_NAME }}-linux-x86_64.tar.gz > ${{ env.APP_NAME }}-linux-x86_64.tar.gz.sha256 + md5sum ${{ env.APP_NAME }}-linux-x86_64.tar.gz > ${{ env.APP_NAME }}-linux-x86_64.tar.gz.md5 + cat ${{ env.APP_NAME }}-linux-x86_64.tar.gz.sha256 + + - name: 📤 Upload Linux package + uses: actions/upload-artifact@v3 + with: + name: linux-package + path: | + dist/${{ env.APP_NAME }}-linux-x86_64.tar.gz + dist/${{ env.APP_NAME }}-linux-x86_64.tar.gz.sha256 + dist/${{ env.APP_NAME }}-linux-x86_64.tar.gz.md5 + retention-days: 7 + + # ============================================================================ + # Сборка для Windows + # ============================================================================ + build-windows: + name: 🪟 Build Windows + runs-on: windows-latest + + steps: + - name: 📥 Checkout repository + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: 🐍 Set up Python ${{ env.PYTHON_VERSION }} + uses: actions/setup-python@v4 + with: + python-version: ${{ env.PYTHON_VERSION }} + cache: 'pip' + + - name: 📚 Install Python dependencies + run: | + python -m pip install --upgrade pip setuptools wheel + pip install pyinstaller + if (Test-Path requirements.txt) { + pip install -r requirements.txt + } else { + pip install requests certbot cryptography + } + + - name: 🔨 Build Windows executable + run: | + make build-windows + + - name: ✅ Test executable + run: | + dist\${{ env.APP_NAME }}.exe --help + dist\${{ env.APP_NAME }}.exe --create-config test_config.json + + - name: 📦 Create distribution package + run: | + make package-windows + + - name: 🔐 Generate checksums + run: | + cd dist + certutil -hashfile ${{ env.APP_NAME }}-windows-x86_64.zip SHA256 > ${{ env.APP_NAME }}-windows-x86_64.zip.sha256 + certutil -hashfile ${{ env.APP_NAME }}-windows-x86_64.zip MD5 > ${{ env.APP_NAME }}-windows-x86_64.zip.md5 + type ${{ env.APP_NAME }}-windows-x86_64.zip.sha256 + + - name: 📤 Upload Windows package + uses: actions/upload-artifact@v3 + with: + name: windows-package + path: | + dist/${{ env.APP_NAME }}-windows-x86_64.zip + dist/${{ env.APP_NAME }}-windows-x86_64.zip.sha256 + dist/${{ env.APP_NAME }}-windows-x86_64.zip.md5 + retention-days: 7 + + # ============================================================================ + # Создание релиза в Gitea + # ============================================================================ + create-release: + name: 📦 Create Release + needs: [build-linux, build-windows] + runs-on: ubuntu-latest + if: startsWith(github.ref, 'refs/tags/') + + steps: + - name: 📥 Checkout repository + uses: actions/checkout@v3 + + - name: 📥 Download Linux artifacts + uses: actions/download-artifact@v3 + with: + name: linux-package + path: ./release + + - name: 📥 Download Windows artifacts + uses: actions/download-artifact@v3 + with: + name: windows-package + path: ./release + + - name: 📋 List release files + run: | + echo "Release files:" + ls -lh ./release/ + + - name: 🏷️ Get version info + id: version + run: | + if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + VERSION="${{ github.event.inputs.version }}" + else + VERSION="${GITHUB_REF#refs/tags/}" + fi + echo "VERSION=$VERSION" >> $GITHUB_OUTPUT + echo "Release version: $VERSION" + + - name: 📝 Generate release notes + id: release_notes + run: | + cat > release_notes.md << 'EOF' + ## 🎉 Let's Encrypt RegRu Manager ${{ steps.version.outputs.VERSION }} + + Автоматическое управление SSL сертификатами Let's Encrypt для доменов на reg.ru с интеграцией в Nginx Proxy Manager. + + ### 📦 Файлы релиза + + #### Linux (Ubuntu 20.04+, Debian 10+, CentOS 8+) + - **letsencrypt-regru-linux-x86_64.tar.gz** - Исполняемый файл (ELF 64-bit) + - **letsencrypt-regru-linux-x86_64.tar.gz.sha256** - SHA256 контрольная сумма + - **letsencrypt-regru-linux-x86_64.tar.gz.md5** - MD5 контрольная сумма + + #### Windows (10/11, Server 2019+) + - **letsencrypt-regru-windows-x86_64.zip** - Исполняемый файл (PE32+) + - **letsencrypt-regru-windows-x86_64.zip.sha256** - SHA256 контрольная сумма + - **letsencrypt-regru-windows-x86_64.zip.md5** - MD5 контрольная сумма + + --- + + ### 🚀 Быстрая установка + + #### Linux (одна команда): + ```bash + curl -fsSL https://your-gitea.com/api/v1/repos/${{ github.repository }}/releases/tags/${{ steps.version.outputs.VERSION }} | \ + jq -r '.assets[] | select(.name | contains("linux")) | .browser_download_url' | \ + xargs wget -O letsencrypt-regru.tar.gz && \ + tar -xzf letsencrypt-regru.tar.gz && \ + sudo mv letsencrypt-regru /usr/local/bin/ && \ + sudo chmod +x /usr/local/bin/letsencrypt-regru + ``` + + #### Или вручную: + ```bash + # 1. Скачать + wget https://your-gitea.com/${{ github.repository }}/releases/download/${{ steps.version.outputs.VERSION }}/letsencrypt-regru-linux-x86_64.tar.gz + + # 2. Проверить контрольную сумму + wget https://your-gitea.com/${{ github.repository }}/releases/download/${{ steps.version.outputs.VERSION }}/letsencrypt-regru-linux-x86_64.tar.gz.sha256 + sha256sum -c letsencrypt-regru-linux-x86_64.tar.gz.sha256 + + # 3. Распаковать и установить + tar -xzf letsencrypt-regru-linux-x86_64.tar.gz + sudo mv letsencrypt-regru /usr/local/bin/ + sudo chmod +x /usr/local/bin/letsencrypt-regru + + # 4. Проверить + letsencrypt-regru --help + ``` + + #### Windows: + ```powershell + # Скачать и распаковать + Invoke-WebRequest -Uri "https://your-gitea.com/${{ github.repository }}/releases/download/${{ steps.version.outputs.VERSION }}/letsencrypt-regru-windows-x86_64.zip" -OutFile "letsencrypt-regru.zip" + Expand-Archive -Path letsencrypt-regru.zip -DestinationPath "C:\Program Files\LetsEncrypt-RegRu" + + # Проверить + & "C:\Program Files\LetsEncrypt-RegRu\letsencrypt-regru.exe" --help + ``` + + --- + + ### ✨ Основные возможности + + - ✅ Автоматическое получение Let's Encrypt сертификатов + - ✅ DNS-валидация через API reg.ru + - ✅ Поддержка wildcard сертификатов (*.domain.com) + - ✅ Автоматическая загрузка в Nginx Proxy Manager + - ✅ Автоматическое обновление сертификатов + - ✅ Systemd интеграция для автоматизации + - ✅ Подробное логирование + - ✅ Генерация тестовых самоподписанных сертификатов + + --- + + ### 📋 Системные требования + + #### Linux: + - Ubuntu 20.04+ / Debian 10+ / CentOS 8+ / RHEL 8+ + - certbot (устанавливается автоматически через `letsencrypt_regru.sh`) + - 50 MB свободного места + - Права root (sudo) + + #### Windows: + - Windows 10/11 или Server 2019+ + - **Важно:** certbot не поддерживается напрямую на Windows + - Рекомендуется использовать WSL (Windows Subsystem for Linux) + + --- + + ### 📖 Документация + + - **[README.md](README.md)** - Полное руководство пользователя + - **[BUILD_GUIDE.md](BUILD_GUIDE.md)** - Руководство по сборке из исходников + - **[INSTALL_GUIDE.md](docs/INSTALL_GUIDE.md)** - Детальная инструкция по установке + - **[MAKEFILE_COMMANDS.md](MAKEFILE_COMMANDS.md)** - Справка по командам Makefile + + --- + + ### ⚠️ Важная информация + + 1. **Certbot зависимость:** + - Исполняемый файл НЕ включает certbot + - certbot должен быть установлен в системе + - Используется через subprocess + + 2. **Размер файла:** + - Linux: ~45-55 MB (включая Python runtime) + - Windows: ~40-50 MB (включая Python runtime) + + 3. **Первый запуск:** + - Может занять 5-10 секунд (распаковка) + - Последующие запуски быстрее (~1-2 сек) + + 4. **Безопасность:** + - Файлы подписаны контрольными суммами SHA256 и MD5 + - Всегда проверяйте контрольные суммы перед использованием + + --- + + ### 🔐 Проверка контрольных сумм + + #### Linux: + ```bash + # SHA256 + sha256sum -c letsencrypt-regru-linux-x86_64.tar.gz.sha256 + + # MD5 + md5sum -c letsencrypt-regru-linux-x86_64.tar.gz.md5 + ``` + + #### Windows: + ```powershell + # SHA256 + certutil -hashfile letsencrypt-regru-windows-x86_64.zip SHA256 + + # MD5 + certutil -hashfile letsencrypt-regru-windows-x86_64.zip MD5 + ``` + + --- + + ### 🐛 Проблемы и поддержка + + Если у вас возникли проблемы: + + 1. Проверьте [Issues](../../issues) + 2. Создайте новый [Issue](../../issues/new) + 3. См. раздел [Troubleshooting](BUILD_GUIDE.md#troubleshooting) в BUILD_GUIDE.md + + --- + + ### 📝 Changelog + + См. [коммиты](${{ github.server_url }}/${{ github.repository }}/commits/${{ steps.version.outputs.VERSION }}) для деталей изменений. + + --- + + **Автор:** Фофанов Дмитрий + **Дата релиза:** $(date -u +"%Y-%m-%d %H:%M:%S UTC") + **Версия:** ${{ steps.version.outputs.VERSION }} + EOF + + cat release_notes.md + + - name: 🚀 Create Gitea Release + uses: actions/gitea-release@v1 + env: + GITEA_TOKEN: ${{ secrets.GITEA_TOKEN || secrets.GITHUB_TOKEN }} + with: + files: | + release/* + tag_name: ${{ steps.version.outputs.VERSION }} + name: "Let's Encrypt RegRu Manager ${{ steps.version.outputs.VERSION }}" + body_path: release_notes.md + draft: false + prerelease: false + + # ============================================================================ + # Уведомление о релизе (опционально) + # ============================================================================ + notify: + name: 📢 Notify + needs: [create-release] + runs-on: ubuntu-latest + if: startsWith(github.ref, 'refs/tags/') + + steps: + - name: 📧 Send notification + run: | + echo "Release created successfully!" + echo "Tag: ${{ github.ref_name }}" + echo "Repository: ${{ github.repository }}" + # Здесь можно добавить отправку уведомлений через webhook, email и т.д. diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml new file mode 100644 index 0000000..66ec619 --- /dev/null +++ b/.github/workflows/build-release.yml @@ -0,0 +1,201 @@ +name: Build Releases + +on: + push: + tags: + - 'v*' # Срабатывает на теги вида v1.0, v2.0.1 и т.д. + workflow_dispatch: # Возможность запустить вручную + +jobs: + build-linux: + name: Build Linux Executable + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.9' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install pyinstaller + pip install -r requirements.txt + + - name: Build Linux executable + run: | + make build-linux + + - name: Test Linux executable + run: | + chmod +x dist/letsencrypt-regru + dist/letsencrypt-regru --help + + - name: Create Linux package + run: | + make package-linux + + - name: Upload Linux artifact + uses: actions/upload-artifact@v3 + with: + name: linux-executable + path: dist/letsencrypt-regru-linux-x86_64.tar.gz + + - name: Generate SHA256 checksum + run: | + cd dist + sha256sum letsencrypt-regru-linux-x86_64.tar.gz > letsencrypt-regru-linux-x86_64.tar.gz.sha256 + + - name: Upload checksum + uses: actions/upload-artifact@v3 + with: + name: linux-checksum + path: dist/letsencrypt-regru-linux-x86_64.tar.gz.sha256 + + build-windows: + name: Build Windows Executable + runs-on: windows-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.9' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install pyinstaller + pip install -r requirements.txt + + - name: Build Windows executable + run: | + make build-windows + + - name: Test Windows executable + run: | + dist\letsencrypt-regru.exe --help + + - name: Create Windows package + run: | + make package-windows + + - name: Upload Windows artifact + uses: actions/upload-artifact@v3 + with: + name: windows-executable + path: dist/letsencrypt-regru-windows-x86_64.zip + + - name: Generate SHA256 checksum + run: | + cd dist + certutil -hashfile letsencrypt-regru-windows-x86_64.zip SHA256 > letsencrypt-regru-windows-x86_64.zip.sha256 + + - name: Upload checksum + uses: actions/upload-artifact@v3 + with: + name: windows-checksum + path: dist/letsencrypt-regru-windows-x86_64.zip.sha256 + + create-release: + name: Create GitHub Release + needs: [build-linux, build-windows] + runs-on: ubuntu-latest + if: startsWith(github.ref, 'refs/tags/') + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Download Linux artifact + uses: actions/download-artifact@v3 + with: + name: linux-executable + path: ./artifacts + + - name: Download Linux checksum + uses: actions/download-artifact@v3 + with: + name: linux-checksum + path: ./artifacts + + - name: Download Windows artifact + uses: actions/download-artifact@v3 + with: + name: windows-executable + path: ./artifacts + + - name: Download Windows checksum + uses: actions/download-artifact@v3 + with: + name: windows-checksum + path: ./artifacts + + - name: Create Release + uses: softprops/action-gh-release@v1 + with: + files: | + ./artifacts/letsencrypt-regru-linux-x86_64.tar.gz + ./artifacts/letsencrypt-regru-linux-x86_64.tar.gz.sha256 + ./artifacts/letsencrypt-regru-windows-x86_64.zip + ./artifacts/letsencrypt-regru-windows-x86_64.zip.sha256 + body: | + ## Let's Encrypt RegRu Manager ${{ github.ref_name }} + + ### 📦 Релизные пакеты + + **Linux (Ubuntu/Debian/CentOS):** + - `letsencrypt-regru-linux-x86_64.tar.gz` - Исполняемый файл + файлы + - `letsencrypt-regru-linux-x86_64.tar.gz.sha256` - Контрольная сумма + + **Windows:** + - `letsencrypt-regru-windows-x86_64.zip` - Исполняемый файл + файлы + - `letsencrypt-regru-windows-x86_64.zip.sha256` - Контрольная сумма + + ### 🚀 Быстрая установка + + **Linux:** + ```bash + wget https://github.com/${{ github.repository }}/releases/download/${{ github.ref_name }}/letsencrypt-regru-linux-x86_64.tar.gz + tar -xzf letsencrypt-regru-linux-x86_64.tar.gz + sudo mv letsencrypt-regru /usr/local/bin/ + sudo chmod +x /usr/local/bin/letsencrypt-regru + ``` + + **Windows:** + Скачайте `letsencrypt-regru-windows-x86_64.zip` и распакуйте. + + ### 📖 Документация + + - [README.md](https://github.com/${{ github.repository }}/blob/${{ github.ref_name }}/README.md) + - [BUILD_GUIDE.md](https://github.com/${{ github.repository }}/blob/${{ github.ref_name }}/BUILD_GUIDE.md) + - [INSTALL_GUIDE.md](https://github.com/${{ github.repository }}/blob/${{ github.ref_name }}/docs/INSTALL_GUIDE.md) + + ### ⚠️ Важно + + - Исполняемые файлы требуют установленного `certbot` в системе + - Linux версия требует права root (sudo) + - Windows версия не поддерживает certbot напрямую (используйте WSL) + + ### 🔐 Проверка контрольных сумм + + **Linux:** + ```bash + sha256sum -c letsencrypt-regru-linux-x86_64.tar.gz.sha256 + ``` + + **Windows:** + ```powershell + certutil -hashfile letsencrypt-regru-windows-x86_64.zip SHA256 + ``` + draft: false + prerelease: false + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/sync-from-gitea.yml b/.github/workflows/sync-from-gitea.yml new file mode 100644 index 0000000..9a0866b --- /dev/null +++ b/.github/workflows/sync-from-gitea.yml @@ -0,0 +1,100 @@ +name: Sync from Gitea + +# Запускается вручную или по webhook от Gitea +on: + workflow_dispatch: + repository_dispatch: + types: [gitea-push] + schedule: + # Проверка каждый час + - cron: '0 * * * *' + +jobs: + sync: + runs-on: ubuntu-latest + + steps: + - name: Checkout GitHub repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Configure Git + run: | + git config --global user.name "Sync Bot" + git config --global user.email "bot@example.com" + + - name: Add Gitea remote + env: + GITEA_URL: ${{ secrets.GITEA_URL }} + GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} + run: | + if [ -z "$GITEA_URL" ]; then + echo "⚠️ GITEA_URL не настроен, пропускаем синхронизацию" + exit 0 + fi + + # Добавляем Gitea remote с токеном + git remote add gitea "https://oauth2:${GITEA_TOKEN}@${GITEA_URL#https://}" + git remote -v + + - name: Fetch from Gitea + run: | + if git remote | grep -q gitea; then + echo "🔄 Получение изменений из Gitea..." + git fetch gitea --tags + else + echo "⚠️ Gitea remote не настроен" + exit 0 + fi + + - name: Check for new commits + id: check + run: | + # Проверяем есть ли новые коммиты в Gitea + LOCAL=$(git rev-parse HEAD) + REMOTE=$(git rev-parse gitea/main 2>/dev/null || git rev-parse gitea/master 2>/dev/null || echo $LOCAL) + + if [ "$LOCAL" != "$REMOTE" ]; then + echo "new_commits=true" >> $GITHUB_OUTPUT + echo "✅ Обнаружены новые изменения в Gitea" + else + echo "new_commits=false" >> $GITHUB_OUTPUT + echo "ℹ️ Нет новых изменений" + fi + + - name: Merge changes from Gitea + if: steps.check.outputs.new_commits == 'true' + run: | + # Определяем главную ветку + if git show-ref --verify --quiet refs/remotes/gitea/main; then + BRANCH="main" + else + BRANCH="master" + fi + + echo "🔀 Слияние изменений из gitea/${BRANCH}..." + git merge "gitea/${BRANCH}" --allow-unrelated-histories -m "Sync from Gitea: $(date)" + + - name: Push to GitHub + if: steps.check.outputs.new_commits == 'true' + run: | + echo "⬆️ Отправка изменений в GitHub..." + git push origin HEAD:main --force-with-lease + git push origin --tags + echo "✅ Синхронизация завершена" + + - name: Summary + if: always() + run: | + echo "## 🔄 Отчет о синхронизации" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + if [ "${{ steps.check.outputs.new_commits }}" == "true" ]; then + echo "✅ **Статус**: Синхронизировано успешно" >> $GITHUB_STEP_SUMMARY + echo "📦 **Коммиты**: Новые изменения получены и объединены" >> $GITHUB_STEP_SUMMARY + else + echo "ℹ️ **Статус**: Нет новых изменений" >> $GITHUB_STEP_SUMMARY + fi + echo "" >> $GITHUB_STEP_SUMMARY + echo "🕐 **Время**: $(date)" >> $GITHUB_STEP_SUMMARY diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..506cf93 --- /dev/null +++ b/.gitignore @@ -0,0 +1,193 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +PIPE_MANIFEST + +# PyInstaller +*.manifest +*.spec + +# PyInstaller build artifacts +build/ +dist/ +*.tar.gz +*.zip +*.sha256 + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +Pipfile.lock + +# poetry +poetry.lock + +# pdm +.pdm.toml + +# PEP 582 +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# IDE +.idea/ +.vscode/ +*.swp +*.swo +*~ + +# SSL Certificates and Keys (CRITICAL - DO NOT COMMIT!) +*.pem +*.key +*.crt +*.csr +*.pfx +*.p12 +/ssl/ +/certs/ + +# Configuration files with credentials +config.yml +config.json +.regru_credentials +credentials.txt +*.secret +config.json + +# Logs +*.log +logs/ +/var/log/ + +# OS-specific +.DS_Store +Thumbs.db +desktop.ini + +# Test certificates +test_certs/ +*.test.pem +*.test.key + +# Backup files +*.bak +*.backup +*~ + +# Temporary files +tmp/ +temp/ +*.tmp diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..5b07aa5 --- /dev/null +++ b/Makefile @@ -0,0 +1,768 @@ +# ============================================================================== +# 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 diff --git a/README.md b/README.md index e5cc795..5bc671a 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,2107 @@ -# configure_nginx_manager +# Руководство по использованию скриптов для управления SSL сертификатами Let's Encrypt с DNS-валидацией через API reg.ru +## 🆕 Новое в версии 2.0 + +**Автоматическая интеграция с Nginx Proxy Manager!** + +Python скрипт теперь автоматически загружает созданные сертификаты в Nginx Proxy Manager. + +- ✅ Автоматическая загрузка сертификатов в NPM +- ✅ Автоматическое обновление существующих сертификатов +- ✅ Полная интеграция через API NPM +- ✅ Поддержка wildcard сертификатов + +--- + +## Содержание +1. [Введение](#введение) +2. [⚡ Быстрая установка (letsencrypt_regru.sh)](#-быстрая-установка-letsencrypt_regrush) +3. [🔨 Сборка исполняемых файлов](#-сборка-исполняемых-файлов) +4. [Быстрый старт](#-быстрый-старт) +5. [Установка через Makefile](#-установка-через-makefile) +6. [Создание тестовых сертификатов](#-создание-тестового-самоподписанного-сертификата) +7. [Требования](#требования) +8. [Установка зависимостей](#установка-зависимостей) +9. [Настройка](#настройка) +10. [Использование Bash скрипта](#использование-bash-скрипта) +11. [Использование Python скрипта](#использование-python-скрипта) +12. [Интеграция с Nginx Proxy Manager](#интеграция-с-nginx-proxy-manager) +13. [Автоматическая проверка и обновление сертификатов](#автоматическая-проверка-и-обновление-сертификатов) +14. [Автоматизация обновления](#автоматизация-обновления) +15. [Устранение неполадок](#устранение-неполадок) + +--- + +## Введение + +В проекте представлены два скрипта для автоматического создания и обновления SSL сертификатов Let's Encrypt с использованием DNS-валидации через API reg.ru: + +1. **letsencrypt_regru_dns.sh** - Bash скрипт с использованием плагина certbot-dns-regru +2. **letsencrypt_regru_api.py** - Python скрипт с прямым взаимодействием с API reg.ru и интеграцией с NPM + +Оба скрипта поддерживают: +- Создание wildcard сертификатов (*.domain.com) +- Автоматическое обновление сертификатов +- DNS-валидацию через API reg.ru +- Логирование всех операций +- Перезагрузку веб-сервера после обновления + +**Дополнительно Python скрипт поддерживает:** +- ✨ Автоматическую загрузку в Nginx Proxy Manager +- ✨ Автоматическое обновление сертификатов в NPM +- ✨ API интеграцию с NPM + +--- + +## ⚡ Быстрая установка (letsencrypt_regru.sh) + +**Автоматическая установка всего приложения одной командой!** + +Скрипт `letsencrypt_regru.sh` автоматизирует весь процесс развертывания: +- ✅ Установка всех зависимостей (Python, certbot, библиотеки) +- ✅ Создание виртуального окружения Python +- ✅ Интерактивная настройка конфигурации +- ✅ Настройка systemd для автоматического обновления +- ✅ Создание удобных команд + +### Установка + +**Вариант 1: Автоматическая установка одной командой** + +```bash +# Метод 1: Через pipe (рекомендуется) +curl -fsSL https://github.com/DFofanov/configure_nginx_manager/raw/refs/heads/master/letsencrypt_regru.sh | sudo bash + +# Метод 2: Через bash -c +sudo bash -c "$(curl -fsSL https://github.com/DFofanov/configure_nginx_manager/raw/refs/heads/master/letsencrypt_regru.sh)" +``` + +**Вариант 2: Клонирование репозитория** + +```bash +# 1. Клонируйте репозиторий +git clone https://github.com/DFofanov/configure_nginx_manager.git +cd configure_nginx_manager + +# 2. Запустите установку +sudo bash letsencrypt_regru.sh +``` + +**Интерактивная настройка:** + +Скрипт спросит: +- Домен (например, example.com) +- Email для Let's Encrypt +- Учетные данные reg.ru +- Настройки NPM (опционально) + + +### Использование после установки + +После установки доступна глобальная команда `letsencrypt-regru`: + +#### 🔧 Основные команды + +```bash +# Проверить срок действия сертификата +letsencrypt-regru --check + +# Получить новый сертификат Let's Encrypt +letsencrypt-regru --obtain + +# Обновить существующий сертификат +letsencrypt-regru --renew + +# Создать тестовый самоподписанный сертификат +letsencrypt-regru --test-cert + +# Автоматическая проверка и обновление при необходимости +letsencrypt-regru --auto +``` + +#### 🧪 Команды диагностики и тестирования + +```bash +# Получить тестовый сертификат Let's Encrypt (staging) +# - Полностью идентичный процесс с production +# - БЕЗ лимитов на количество запросов (неограниченно!) +# - Идеально для тестирования автоматизации и DNS +# - Браузеры не доверяют (staging CA) +# - НЕ загружается в Nginx Proxy Manager +letsencrypt-regru --staging + +# Проверить доступ к API reg.ru +# - Тестирует подключение к API +# - Показывает текущий IP адрес +# - Отображает баланс аккаунта reg.ru +letsencrypt-regru --test-api + +# Тестовое создание DNS записи TXT +# - Полная симуляция процесса SSL сертификации +# - Создает временную TXT запись _acme-challenge +# - Проверяет распространение DNS (60 секунд) +# - Автоматически удаляет тестовую запись +letsencrypt-regru --test-dns + +# Показать справку по всем доступным командам +letsencrypt-regru --help + +# Включить подробный вывод (verbose mode) +letsencrypt-regru --obtain -v +letsencrypt-regru --check -v +letsencrypt-regru --staging -v + +# Очистить lock-файлы Certbot (если процесс завис) +letsencrypt-regru --force-cleanup + +# Показать полную информацию о сертификате +letsencrypt-regru --info +``` + +#### 🔄 Работа с Nginx Proxy Manager + +```bash +# Загрузить существующий сертификат в NPM (вручную) +# Указываете домен, для которого хотите загрузить сертификат +letsencrypt-regru --upload-npm example.com + +# Загрузить wildcard сертификат +letsencrypt-regru --upload-npm example.com # для *.example.com + +# Команда автоматически: +# - Найдет сертификат в /etc/letsencrypt/live/DOMAIN/ +# - Проверит тип (staging/production) +# - Загрузит или обновит в NPM +# - Покажет ID сертификата в NPM +``` + +**Примечание:** При использовании `--obtain` или `--renew` сертификат **автоматически** загружается в NPM (если npm_enabled=true в конфигурации). Команда `--upload-npm` нужна для ручной загрузки существующих сертификатов. + +#### ⚙️ Служебные команды (внутреннее использование) + +```bash +# Certbot authentication hook (используется certbot) +letsencrypt-regru --auth-hook + +# Certbot cleanup hook (используется certbot) +letsencrypt-regru --cleanup-hook +``` + +### Автоматическое обновление + +Скрипт установки настраивает автоматическую проверку сертификатов каждые 12 часов: + +```bash +# Проверить статус автообновления +systemctl status letsencrypt-regru.timer + +# Посмотреть логи +journalctl -u letsencrypt-regru -f + +# Или в файле +tail -f /var/log/letsencrypt-regru/letsencrypt_regru.log +``` + +### Управление установкой + +#### Обновление + +```bash +# Способ 1: Из локального репозитория (если клонировали) +cd configure_nginx_manager +git pull # Получить последние изменения +sudo bash letsencrypt_regru.sh update + +# Способ 2: Обновление одной командой с GitHub (рекомендуется) +curl -fsSL https://github.com/DFofanov/configure_nginx_manager/raw/refs/heads/master/letsencrypt_regru.sh | sudo bash -s update + +# ❌ НЕ РАБОТАЕТ (неправильный синтаксис): +# sudo bash -c "$(curl -fsSL ...) update" # Аргументы не передаются! +``` + +#### Удаление + +```bash +# Способ 1: Из локального репозитория +sudo bash letsencrypt_regru.sh uninstall + +# Способ 2: Удаление одной командой с GitHub +curl -fsSL https://github.com/DFofanov/configure_nginx_manager/raw/refs/heads/master/letsencrypt_regru.sh | sudo bash -s uninstall +``` + +**💡 Совет:** При обновлении/удалении через curl скрипт автоматически скачивает необходимые файлы с GitHub. + +#### 📚 Техническая справка: Синтаксис команд + +
+Почему используется | sudo bash -s update вместо bash -c "$(curl ...) update"? + +**Правильный способ (с аргументами):** +```bash +curl -fsSL https://url/script.sh | sudo bash -s update +# ↑ +# -s передает аргументы скрипту +``` + +**Неправильный способ (аргументы игнорируются):** +```bash +sudo bash -c "$(curl -fsSL https://url/script.sh) update" +# ↑ +# Это НЕ аргумент для скрипта! +# Это аргумент для bash -c +``` + +**Объяснение:** +- `bash -c "command"` - выполняет команду как строку, дополнительные аргументы становятся позиционными параметрами для bash, а не для скрипта +- `bash -s arg1 arg2` - читает скрипт из stdin и передает arg1, arg2 как аргументы скрипту ($1, $2) + +**Альтернативные способы:** +```bash +# Вариант 1: Через pipe (рекомендуется) +curl -fsSL https://url/script.sh | sudo bash -s update + +# Вариант 2: Через временный файл +curl -fsSL https://url/script.sh -o /tmp/install.sh +sudo bash /tmp/install.sh update +rm /tmp/install.sh + +# Вариант 3: Через wget +wget -qO- https://url/script.sh | sudo bash -s update +``` + +
+ +### Расположение файлов + +После установки файлы находятся: + +| Тип | Путь | +|-----|------| +| Приложение | `/opt/letsencrypt-regru/` | +| Конфигурация | `/etc/letsencrypt-regru/config.json` | +| Логи | `/var/log/letsencrypt-regru/` | +| Сертификаты | `/etc/letsencrypt/live/` | +| Systemd сервис | `/etc/systemd/system/letsencrypt-regru.service` | +| Systemd таймер | `/etc/systemd/system/letsencrypt-regru.timer` | + +### Редактирование конфигурации + +```bash +# Отредактировать настройки +sudo nano /etc/letsencrypt-regru/config.json + +# Перезапустить таймер после изменений +sudo systemctl restart letsencrypt-regru.timer +``` + +--- + +## 🚀 Установка через Makefile + +**Самый быстрый способ установки на Linux!** + +Makefile автоматизирует весь процесс установки, настройки systemd-сервисов и cron-заданий. + +### Быстрая установка + +```bash +# 1. Установка (требует root) +sudo make install + +# 2. Редактирование конфигурации +sudo nano /etc/letsencrypt/regru_config.json + +# 3. Проверка конфигурации +sudo make check-config + +# 4. Тестовый запуск +sudo make test-run +``` + +### Доступные команды Makefile + +#### Основные команды + +```bash +# Установка всего: создание директорий, копирование скрипта, настройка systemd и cron +sudo make install + +# Полное удаление: удаление службы, cron-задания, файлов +sudo make uninstall + +# Показать статус установки, systemd и cron +sudo make status + +# Справка по всем командам +make help +``` + +#### Утилиты + +```bash +# Проверка JSON конфигурации на валидность +sudo make check-config + +# Тестовый запуск без обновления cron/systemd +sudo make test-run + +# Просмотр логов +sudo make logs + +# Запуск скрипта напрямую +sudo make run + +# Получение нового сертификата +sudo make obtain + +# Обновление существующего сертификата +sudo make renew + +# Создание тестового самоподписанного сертификата +sudo make test-cert + +# Очистка логов +sudo make clean +``` + +### Что делает `make install` + +1. **Создает директории** + - `/opt/letsencrypt-regru/` - директория установки + - `/var/log/letsencrypt/` - директория логов + +2. **Устанавливает зависимости** + ```bash + pip3 install certbot requests cryptography + ``` + +3. **Копирует скрипт** + - Копирует `letsencrypt_regru_api.py` в `/opt/letsencrypt-regru/` + - Устанавливает права на выполнение + +4. **Создает конфигурацию** + - Создает `/etc/letsencrypt/regru_config.json` (если не существует) + - Устанавливает права 600 для безопасности + +5. **Настраивает systemd** + - Создает `letsencrypt-regru.service` - разовый запуск + - Создает `letsencrypt-regru.timer` - таймер для ежедневного запуска + - Включает и запускает таймер + +6. **Настраивает cron** + - Добавляет задание для запуска каждый день в 3:00 AM + ``` + 0 3 * * * /opt/letsencrypt-regru/letsencrypt_regru_api.py --config /etc/letsencrypt/regru_config.json --auto >> /var/log/letsencrypt/letsencrypt_regru.log 2>&1 + ``` + +### Что делает `make uninstall` + +1. **Останавливает и удаляет службы** + - Останавливает systemd timer и service + - Удаляет файлы служб из `/etc/systemd/system/` + - Перезагружает конфигурацию systemd + +2. **Удаляет cron-задание** + - Удаляет запись из crontab + +3. **Удаляет файлы** (с подтверждением) + - Удаляет `/opt/letsencrypt-regru/` + - Опционально удаляет конфигурацию и логи + +### Пример: Полная установка от А до Я + +```bash +# 1. Клонируем или скачиваем проект +cd /tmp +git clone +cd configure_nginx_manager + +# 2. Устанавливаем через Makefile +sudo make install + +# 3. Редактируем конфигурацию +sudo nano /etc/letsencrypt/regru_config.json + +# Вставляем реальные данные: +{ + "regru_username": "myuser", + "regru_password": "mypassword", + "domain": "example.com", + "wildcard": true, + "email": "admin@example.com", + "renewal_days": 30, + "npm_enabled": true, + "npm_host": "https://npm.example.com", + "npm_email": "admin@example.com", + "npm_password": "npm_password" +} + +# 4. Проверяем конфигурацию +sudo make check-config + +# 5. Тестируем +sudo make test-run + +# 6. Проверяем статус +sudo make status + +# 7. Смотрим логи +sudo make logs +``` + +### Структура после установки + +``` +/opt/letsencrypt-regru/ +├── letsencrypt_regru_api.py # Основной скрипт + +/etc/letsencrypt/ +├── regru_config.json # Конфигурация (600) +└── live/ # Сертификаты Let's Encrypt + └── example.com/ + ├── fullchain.pem + └── privkey.pem + +/var/log/letsencrypt/ +└── letsencrypt_regru.log # Логи + +/etc/systemd/system/ +├── letsencrypt-regru.service # Systemd сервис +└── letsencrypt-regru.timer # Systemd таймер (ежедневно) +``` + +### Проверка работы автоматизации + +```bash +# Статус systemd таймера +sudo systemctl status letsencrypt-regru.timer + +# Когда будет следующий запуск +sudo systemctl list-timers letsencrypt-regru.timer + +# Проверка cron +sudo crontab -l | grep letsencrypt + +# Ручной запуск службы (для теста) +sudo systemctl start letsencrypt-regru.service + +# Просмотр логов службы +sudo journalctl -u letsencrypt-regru.service -f +``` + +### Удаление + +```bash +# Полное удаление +sudo make uninstall + +# Система спросит подтверждение перед удалением конфигурации и логов +``` + +### 🧪 Создание тестового самоподписанного сертификата + +**Идеально для тестирования без ограничений Let's Encrypt!** + +Let's Encrypt имеет ограничения на количество сертификатов (5 в неделю на домен). Для тестирования и разработки можно использовать самоподписанные сертификаты. + +#### Преимущества тестовых сертификатов + +✅ **Нет ограничений** - создавайте сколько угодно сертификатов +✅ **Мгновенное создание** - без DNS-валидации и ожидания +✅ **Тестирование NPM** - проверка интеграции с Nginx Proxy Manager +✅ **Офлайн работа** - не требуется интернет и API reg.ru +✅ **Идентичная структура** - те же файлы, что и Let's Encrypt + +⚠️ **Ограничения**: Браузеры не доверяют самоподписанным сертификатам + +#### Быстрое создание + +```bash +# Создать тестовый сертификат +sudo make test-cert +``` + +Команда автоматически: +1. Генерирует RSA ключ 2048 бит +2. Создает самоподписанный сертификат на 90 дней +3. Поддерживает wildcard домены (если настроено) +4. Создает все необходимые файлы (privkey.pem, cert.pem, fullchain.pem, chain.pem) +5. Опционально загружает в Nginx Proxy Manager + +#### Использование Python скрипта напрямую + +```bash +# Создать тестовый сертификат с подробным выводом +sudo python3 /opt/letsencrypt-regru/letsencrypt_regru_api.py \ + --config /etc/letsencrypt/regru_config.json \ + --test-cert -v +``` + +#### Что создается + +После выполнения команды будут созданы файлы: + +``` +/etc/letsencrypt/live/example.com/ +├── privkey.pem # Приватный ключ RSA 2048 бит +├── cert.pem # Сертификат +├── fullchain.pem # Полная цепочка (для nginx) +└── chain.pem # Цепочка CA (пустой для самоподписанного) +``` + +#### Интеграция с NPM + +Если в конфигурации включена интеграция с NPM (`npm_enabled: true`), тестовый сертификат автоматически загрузится в Nginx Proxy Manager: + +```json +{ + "npm_enabled": true, + "npm_host": "https://npm.example.com", + "npm_email": "admin@example.com", + "npm_password": "password" +} +``` + +#### Пример вывода + +``` +═══════════════════════════════════════════════════════════════ +ГЕНЕРАЦИЯ ТЕСТОВОГО САМОПОДПИСАННОГО СЕРТИФИКАТА +═══════════════════════════════════════════════════════════════ +Домен: example.com +Wildcard: True +Срок действия: 90 дней +⚠️ ВНИМАНИЕ: Это тестовый сертификат, не для production! + +✓ Приватный ключ сохранен: /etc/letsencrypt/live/example.com/privkey.pem +✓ Сертификат сохранен: /etc/letsencrypt/live/example.com/cert.pem +✓ Fullchain сохранен: /etc/letsencrypt/live/example.com/fullchain.pem +✓ Chain файл создан: /etc/letsencrypt/live/example.com/chain.pem + +═══════════════════════════════════════════════════════════════ +ИНФОРМАЦИЯ О СЕРТИФИКАТЕ +═══════════════════════════════════════════════════════════════ +Домен: example.com +Wildcard: *.example.com +Действителен с: 2025-10-27 12:00:00 +Действителен до: 2026-01-25 12:00:00 +``` + +#### Когда использовать тестовые сертификаты + +**✅ Используйте для:** +- Локальной разработки и тестирования +- Проверки интеграции с Nginx Proxy Manager +- Тестирования автоматизации +- Разработки без доступа к интернету +- Избежания лимитов Let's Encrypt при частом тестировании + +**❌ НЕ используйте для:** +- Production окружения +- Публичных веб-сайтов +- Любых случаев, где требуется доверие браузеров + +#### Переход с тестового на production + +После успешного тестирования легко переключиться на настоящий Let's Encrypt сертификат: + +```bash +# 1. Удалить тестовый сертификат +sudo rm -rf /etc/letsencrypt/live/example.com/ + +# 2. Получить настоящий сертификат +sudo make obtain + +# Или автоматически +sudo make run +``` + +--- + +## Требования + +### Общие требования +- Операционная система: Linux (Ubuntu/Debian/CentOS) +- Права: root или sudo +- Домен зарегистрирован на reg.ru +- Доступ к API reg.ru (имя пользователя и пароль) + +### Для Bash скрипта +- certbot +- certbot-dns-regru (плагин) +- curl +- jq +- openssl + +### Для Python скрипта +- Python 3.6+ +- certbot +- pip3 +- Модули Python: requests, cryptography + +--- + +## Установка зависимостей + +### Ubuntu/Debian + +```bash +# Обновление пакетов +sudo apt-get update + +# Установка базовых зависимостей +sudo apt-get install -y certbot curl jq openssl python3 python3-pip + +# Для Python скрипта +sudo pip3 install certbot-dns-regru requests cryptography + +# Для Bash скрипта (если используете) +sudo pip3 install certbot-dns-regru +``` + +### CentOS/RHEL + +```bash +# Обновление пакетов +sudo yum update -y + +# Установка EPEL репозитория +sudo yum install -y epel-release + +# Установка базовых зависимостей +sudo yum install -y certbot curl jq openssl python3 python3-pip + +# Установка плагина +sudo pip3 install certbot-dns-regru requests cryptography +``` + +--- + +## Настройка + +### 1. Получение учетных данных API reg.ru + +1. Войдите в личный кабинет на сайте [reg.ru](https://www.reg.ru) +2. Перейдите в раздел "Управление API" +3. Используйте ваше имя пользователя и пароль для доступа к API +4. Убедитесь, что у вас есть права на управление DNS-записями + +### 2. Настройка конфигурации + +#### Для Python скрипта + +Создайте файл конфигурации на основе примера: + +```bash +# Создание примера конфигурации +sudo python3 letsencrypt_regru_api.py --create-config /etc/letsencrypt/regru_config.json + +# Редактирование конфигурации +sudo nano /etc/letsencrypt/regru_config.json +``` + +Отредактируйте параметры: + +```json +{ + "regru_username": "your_actual_username", + "regru_password": "your_actual_password", + "domain": "example.com", + "wildcard": true, + "email": "admin@example.com", + "cert_dir": "/etc/letsencrypt/live", + "log_file": "/var/log/letsencrypt_regru.log", + "dns_propagation_wait": 60, + "dns_check_attempts": 10, + "dns_check_interval": 10 +} +``` + +#### Для Bash скрипта + +Отредактируйте переменные в начале скрипта: + +```bash +sudo nano letsencrypt_regru_dns.sh +``` + +Измените следующие параметры: + +```bash +REGRU_USERNAME="your_actual_username" +REGRU_PASSWORD="your_actual_password" +DOMAIN="example.com" +WILDCARD_DOMAIN="*.example.com" +EMAIL="admin@example.com" +``` + +### 3. Установка прав доступа + +```bash +# Для Bash скрипта +sudo chmod +x letsencrypt_regru_dns.sh + +# Для Python скрипта +sudo chmod +x letsencrypt_regru_api.py + +# Защита файла конфигурации +sudo chmod 600 /etc/letsencrypt/regru_config.json +``` + +--- + +## Использование Bash скрипта + +### Первый запуск (получение сертификата) + +```bash +sudo ./letsencrypt_regru_dns.sh +``` + +Скрипт автоматически: +1. Проверит зависимости +2. Создаст файл с учетными данными +3. Установит плагин certbot-dns-regru (если не установлен) +4. Проверит наличие существующего сертификата +5. Получит новый сертификат или обновит существующий +6. Перезагрузит веб-сервер + +### Просмотр логов + +```bash +sudo tail -f /var/log/letsencrypt_regru.log +``` + +### Ручная проверка сертификата + +```bash +sudo certbot certificates +``` + +--- + +## Использование Python скрипта + +### Создание примера конфигурации + +```bash +sudo python3 letsencrypt_regru_api.py --create-config /etc/letsencrypt/regru_config.json +``` + +### Получение нового сертификата + +```bash +# С использованием конфигурационного файла +sudo python3 letsencrypt_regru_api.py -c /etc/letsencrypt/regru_config.json --obtain + +# С подробным выводом +sudo python3 letsencrypt_regru_api.py -c /etc/letsencrypt/regru_config.json --obtain -v +``` + +### Обновление существующего сертификата + +```bash +sudo python3 letsencrypt_regru_api.py -c /etc/letsencrypt/regru_config.json --renew +``` + +### Проверка срока действия сертификата + +```bash +sudo python3 letsencrypt_regru_api.py -c /etc/letsencrypt/regru_config.json --check +``` + +### Автоматический режим (проверка и обновление) + +```bash +# Скрипт сам определит, нужно ли обновление +sudo python3 letsencrypt_regru_api.py -c /etc/letsencrypt/regru_config.json +``` + +### Опции командной строки + +``` +-c, --config FILE Путь к файлу конфигурации (JSON) +--create-config FILE Создать пример файла конфигурации +--obtain Получить новый сертификат +--renew Обновить существующий сертификат +--check Проверить срок действия сертификата +-v, --verbose Подробный вывод +``` + +--- + +## � Сборка исполняемых файлов + +### PyInstaller - компиляция в исполняемые файлы + +Скрипт можно скомпилировать в исполняемый файл для Linux и Windows с помощью PyInstaller. + +**Преимущества:** +- ✅ Не требуется установленный Python на целевой системе +- ✅ Все зависимости включены в один файл +- ✅ Простота распространения и развертывания + +**Недостатки:** +- ❌ Большой размер (~40-60 MB) +- ❌ Certbot всё равно должен быть установлен в системе +- ❌ Медленный первый запуск + +### Быстрая сборка + +#### Для Linux: +```bash +make build-linux +``` + +#### Для Windows: +```bash +make build-windows +``` + +#### Для всех платформ: +```bash +make build-all +``` + +### Полный релиз с пакетами + +```bash +# Создаст tar.gz для Linux и zip для Windows +make release +``` + +**Результат:** +- `dist/letsencrypt-regru` - Linux executable +- `dist/letsencrypt-regru.exe` - Windows executable +- `dist/letsencrypt-regru-linux-x86_64.tar.gz` +- `dist/letsencrypt-regru-windows-x86_64.zip` + +### Использование собранного файла + +**Linux:** +```bash +# Установка +sudo cp dist/letsencrypt-regru /usr/local/bin/ +sudo chmod +x /usr/local/bin/letsencrypt-regru + +# Использование +sudo letsencrypt-regru --help +sudo letsencrypt-regru --check -c /etc/letsencrypt-regru/config.json +``` + +**Windows:** +```powershell +# Просто запустить +.\dist\letsencrypt-regru.exe --help +``` + +📖 **Подробнее:** См. [BUILD_GUIDE.md](BUILD_GUIDE.md) для детальных инструкций по сборке. + +--- + +## �🚀 Быстрый старт + +### За 3 простых шага получите SSL сертификат в Nginx Proxy Manager! + +#### Шаг 1: Создайте конфигурацию + +```bash +sudo python3 letsencrypt_regru_api.py --create-config /etc/letsencrypt/regru_config.json +``` + +#### Шаг 2: Отредактируйте параметры + +```bash +sudo nano /etc/letsencrypt/regru_config.json +``` + +Заполните: + +```json +{ + "regru_username": "ваш_логин_regru", + "regru_password": "ваш_пароль_regru", + "domain": "example.com", + "wildcard": true, + "email": "admin@example.com", + + "npm_enabled": true, + "npm_host": "http://10.10.10.14:81", + "npm_email": "admin@example.com", + "npm_password": "changeme" +} +``` + +#### Шаг 3: Получите сертификат + +```bash +sudo python3 letsencrypt_regru_api.py -c /etc/letsencrypt/regru_config.json --obtain +``` + +### ✅ Готово! + +Откройте Nginx Proxy Manager → SSL Certificates + +Ваш сертификат `*.example.com` готов к использованию! 🎉 + +**Что произошло:** +1. ✅ Создан wildcard сертификат через Let's Encrypt +2. ✅ Выполнена DNS-валидация через API reg.ru +3. ✅ Сертификат автоматически загружен в Nginx Proxy Manager +4. ✅ Веб-сервер перезагружен + +--- + +## Интеграция с Nginx Proxy Manager + +### Обзор возможностей + +Скрипт `letsencrypt_regru_api.py` поддерживает автоматическое добавление и обновление SSL сертификатов в Nginx Proxy Manager через его API. + +**Возможности:** +- ✅ Автоматическое добавление новых сертификатов в NPM +- ✅ Обновление существующих сертификатов в NPM +- ✅ Поиск сертификатов по доменному имени +- ✅ Поддержка wildcard сертификатов +- ✅ Полная синхронизация после создания/обновления + +### Настройка интеграции + +#### 1. Параметры конфигурации NPM + +| Параметр | Описание | Пример | +|----------|----------|--------| +| `npm_enabled` | Включить интеграцию с NPM | `true` или `false` | +| `npm_host` | URL адрес NPM | `http://10.10.10.14:81` | +| `npm_email` | Email для входа в NPM | `admin@example.com` | +| `npm_password` | Пароль администратора NPM | `changeme` | + +#### 2. Получение учетных данных NPM + +1. Войдите в Nginx Proxy Manager: `http://10.10.10.14:81` +2. Используйте email и пароль администратора +3. По умолчанию: + - Email: `admin@example.com` + - Password: `changeme` +4. **ВАЖНО:** Измените пароль по умолчанию! + +### Использование + +#### Автоматическая синхронизация + +После создания или обновления сертификата скрипт автоматически: +1. Авторизуется в Nginx Proxy Manager +2. Проверит, существует ли сертификат для домена +3. Создаст новый сертификат или обновит существующий +4. Загрузит файлы сертификата в NPM + +#### Создание нового сертификата с автоматической загрузкой в NPM + +```bash +sudo python3 letsencrypt_regru_api.py -c /etc/letsencrypt/regru_config.json --obtain +``` + +**Скрипт выполнит:** +- ✅ Создание сертификата через Let's Encrypt +- ✅ DNS-валидация через reg.ru API +- ✅ Автоматическая загрузка в NPM +- ✅ Перезагрузка веб-сервера + +#### Обновление существующего сертификата + +```bash +sudo python3 letsencrypt_regru_api.py -c /etc/letsencrypt/regru_config.json --renew +``` + +**Скрипт выполнит:** +- ✅ Обновление сертификата через certbot +- ✅ Автоматическое обновление в NPM +- ✅ Перезагрузка веб-сервера + +#### Автоматический режим + +```bash +sudo python3 letsencrypt_regru_api.py -c /etc/letsencrypt/regru_config.json +``` + +Скрипт автоматически определит: +- Нужно ли создать новый сертификат +- Требуется ли обновление (если осталось < 30 дней) +- Выполнит синхронизацию с NPM + +### Работа с API Nginx Proxy Manager + +#### Класс NginxProxyManagerAPI + +Скрипт использует класс `NginxProxyManagerAPI` для работы с NPM: + +```python +from letsencrypt_regru_api import NginxProxyManagerAPI + +# Инициализация +npm_api = NginxProxyManagerAPI( + host="http://10.10.10.14:81", + email="admin@example.com", + password="changeme", + logger=logger +) + +# Авторизация +npm_api.login() + +# Получение списка сертификатов +certificates = npm_api.get_certificates() + +# Поиск сертификата по домену +cert = npm_api.find_certificate_by_domain("example.com") + +# Синхронизация сертификата +npm_api.sync_certificate("example.com", "/etc/letsencrypt/live/example.com") +``` + +#### API Endpoints + +Скрипт использует следующие endpoints NPM API: + +| Endpoint | Метод | Описание | +|----------|-------|----------| +| `/api/tokens` | POST | Авторизация | +| `/api/nginx/certificates` | GET | Список сертификатов | +| `/api/nginx/certificates` | POST | Создание сертификата | +| `/api/nginx/certificates/{id}` | PUT | Обновление сертификата | + +### Логи и отладка + +#### Просмотр логов + +```bash +# Основной лог скрипта +sudo tail -f /var/log/letsencrypt_regru.log + +# Подробный режим +sudo python3 letsencrypt_regru_api.py -c config.json --obtain -v +``` + +#### Примеры логов при успешной синхронизации + +``` +2025-10-27 10:30:15 - INFO - === Синхронизация сертификата с Nginx Proxy Manager === +2025-10-27 10:30:15 - INFO - Авторизация в Nginx Proxy Manager... +2025-10-27 10:30:16 - INFO - Авторизация в NPM успешна +2025-10-27 10:30:16 - DEBUG - Получение списка сертификатов из NPM... +2025-10-27 10:30:16 - DEBUG - Получено 3 сертификатов +2025-10-27 10:30:16 - INFO - Создание нового сертификата в NPM +2025-10-27 10:30:16 - INFO - Загрузка сертификата для example.com в NPM... +2025-10-27 10:30:17 - INFO - Сертификат успешно загружен в NPM (ID: 4) +2025-10-27 10:30:17 - INFO - Сертификат успешно добавлен в Nginx Proxy Manager +``` + +### Устранение неполадок NPM + +#### Ошибка: Не удалось авторизоваться в NPM + +**Причины:** +- Неверный email или пароль +- NPM недоступен по указанному адресу +- Сетевые проблемы + +**Решение:** +```bash +# Проверьте доступность NPM +curl http://10.10.10.14:81/api/ + +# Проверьте учетные данные +# Войдите в NPM через браузер с теми же учетными данными +``` + +#### Ошибка: Сертификат не загружен в NPM + +**Причины:** +- Файлы сертификата не найдены +- Неправильный формат сертификата +- Проблемы с API NPM + +**Решение:** +```bash +# Проверьте наличие файлов сертификата +ls -la /etc/letsencrypt/live/example.com/ + +# Проверьте права доступа +sudo chmod 644 /etc/letsencrypt/live/example.com/*.pem + +# Попробуйте вручную +sudo python3 -c " +from letsencrypt_regru_api import NginxProxyManagerAPI +import logging +logger = logging.getLogger() +npm = NginxProxyManagerAPI('http://10.10.10.14:81', 'admin@example.com', 'changeme', logger) +npm.login() +print(npm.get_certificates()) +" +``` + +#### Ошибка: API NPM возвращает 401 (Unauthorized) + +**Решение:** +- Проверьте учетные данные в конфигурации +- Убедитесь, что пароль был изменен с дефолтного +- Попробуйте войти через веб-интерфейс + +#### Ошибка: Сертификат создан, но не обновляется в NPM + +**Причина:** Скрипт не может найти существующий сертификат + +**Решение:** +```bash +# Просмотрите список сертификатов в NPM +# SSL Certificates → найдите сертификат для вашего домена + +# Удалите старый сертификат вручную через UI +# Запустите скрипт снова - будет создан новый +``` + +### Безопасность NPM + +#### Защита учетных данных + +```bash +# Установите правильные права на конфигурацию +sudo chmod 600 /etc/letsencrypt/regru_config.json +sudo chown root:root /etc/letsencrypt/regru_config.json +``` + +#### Рекомендации + +1. **Измените пароль NPM по умолчанию** + ``` + Старый пароль: changeme + Новый пароль: надежный_пароль + ``` + +2. **Используйте HTTPS для NPM** (если доступно) + ```json + "npm_host": "https://10.10.10.14:443" + ``` + +3. **Ограничьте доступ к API NPM** + - Настройте firewall + - Используйте VPN для удаленного доступа + +### Проверка результата + +#### В логах скрипта + +```bash +sudo tail -n 50 /var/log/letsencrypt_regru.log | grep -i npm +``` + +#### В веб-интерфейсе NPM + +1. Откройте NPM: `http://10.10.10.14:81` +2. Войдите в систему +3. Перейдите в **SSL Certificates** +4. Проверьте наличие сертификата для вашего домена +5. Проверьте дату истечения + +#### В командной строке + +```bash +# Список сертификатов в NPM через API +curl -X POST http://10.10.10.14:81/api/tokens \ + -H "Content-Type: application/json" \ + -d '{"identity":"admin@example.com","secret":"changeme"}' \ + | jq -r '.token' > /tmp/npm_token + +curl -H "Authorization: Bearer $(cat /tmp/npm_token)" \ + http://10.10.10.14:81/api/nginx/certificates \ + | jq '.' +``` + +### Дополнительные возможности + +#### Отключение синхронизации с NPM + +Если нужно временно отключить синхронизацию: + +```json +{ + "npm_enabled": false +} +``` + +#### Использование с несколькими доменами + +Создайте отдельные конфигурационные файлы: + +```bash +# Для домена 1 +sudo python3 letsencrypt_regru_api.py -c /etc/letsencrypt/domain1_config.json + +# Для домена 2 +sudo python3 letsencrypt_regru_api.py -c /etc/letsencrypt/domain2_config.json +``` + +--- + +## Автоматическая проверка и обновление сертификатов + +### Как это работает + +Скрипт в автоматическом режиме (без флагов `--obtain` или `--renew`) выполняет интеллектуальную проверку: + +#### 1. Проверка наличия сертификата + +```bash +sudo python3 letsencrypt_regru_api.py -c /etc/letsencrypt/regru_config.json +``` + +**Если сертификата нет:** +- ✅ Создает новый сертификат через Let's Encrypt +- ✅ Выполняет DNS-валидацию через reg.ru +- ✅ Загружает сертификат в Nginx Proxy Manager (если включено) +- ✅ Перезагружает веб-сервер + +#### 2. Проверка срока действия + +**Если сертификат существует:** +- 🔍 Проверяет сколько дней осталось до истечения +- 📅 Сравнивает с порогом обновления (по умолчанию 30 дней) + +**Если осталось меньше 30 дней:** +- 🔄 Автоматически обновляет сертификат +- ✅ Синхронизирует с Nginx Proxy Manager +- ✅ Перезагружает веб-сервер + +**Если сертификат действителен (более 30 дней):** +- ℹ️ Выводит информацию о сертификате +- ✅ Проверяет наличие в NPM и синхронизирует при необходимости +- ⏭️ Завершает работу (обновление не требуется) + +### Настройка порога обновления + +В конфигурации можно изменить порог обновления: + +```json +{ + "renewal_days": 30, # За сколько дней до истечения обновлять +} +``` + +**Рекомендуемые значения:** +- `30` - по умолчанию (рекомендуется) +- `14` - для более консервативного подхода +- `60` - для раннего обновления + +### Примеры работы скрипта + +#### Сценарий 1: Сертификата нет + +```bash +$ sudo python3 letsencrypt_regru_api.py -c config.json + +============================================================ +АВТОМАТИЧЕСКАЯ ПРОВЕРКА И ОБНОВЛЕНИЕ СЕРТИФИКАТА +============================================================ +Порог обновления: 30 дней до истечения +Сертификат не найден +============================================================ +СТАТУС: Сертификат не найден +ДЕЙСТВИЕ: Создание нового сертификата +============================================================ +=== Запрос нового SSL сертификата === +... +Сертификат успешно получен! +============================================================ +СИНХРОНИЗАЦИЯ С NGINX PROXY MANAGER +============================================================ +✅ Сертификат успешно создан в Nginx Proxy Manager +============================================================ +ОПЕРАЦИЯ ЗАВЕРШЕНА УСПЕШНО +============================================================ +``` + +#### Сценарий 2: Сертификат истекает через 20 дней + +```bash +$ sudo python3 letsencrypt_regru_api.py -c config.json + +============================================================ +АВТОМАТИЧЕСКАЯ ПРОВЕРКА И ОБНОВЛЕНИЕ СЕРТИФИКАТА +============================================================ +Порог обновления: 30 дней до истечения +Сертификат истекает: 2025-11-16 +Осталось дней: 20 +============================================================ +СТАТУС: Сертификат истекает через 20 дней +ДЕЙСТВИЕ: Обновление сертификата (порог: 30 дней) +============================================================ +=== Обновление SSL сертификата === +... +Проверка обновления завершена +============================================================ +РЕЗУЛЬТАТ: Сертификат успешно обновлен +============================================================ +✅ Сертификат успешно обновлен в Nginx Proxy Manager +``` + +#### Сценарий 3: Сертификат действителен (60 дней) + +```bash +$ sudo python3 letsencrypt_regru_api.py -c config.json + +============================================================ +АВТОМАТИЧЕСКАЯ ПРОВЕРКА И ОБНОВЛЕНИЕ СЕРТИФИКАТА +============================================================ +Порог обновления: 30 дней до истечения +Сертификат истекает: 2025-12-26 +Осталось дней: 60 +============================================================ +СТАТУС: Сертификат действителен (60 дней) +ДЕЙСТВИЕ: Обновление не требуется +============================================================ +Проверка синхронизации с Nginx Proxy Manager... +Сертификат найден в NPM (ID: 4) +``` + +### Ежедневная автоматическая проверка + +Для ежедневной проверки и автоматического обновления настройте cron: + +```bash +# Редактируем crontab +sudo crontab -e + +# Добавляем задачу - проверка каждый день в 3:00 утра +0 3 * * * /usr/bin/python3 /path/to/letsencrypt_regru_api.py -c /etc/letsencrypt/regru_config.json >> /var/log/letsencrypt_cron.log 2>&1 +``` + +**Что будет происходить каждый день:** +1. 🕒 В 3:00 утра запускается скрипт +2. 🔍 Проверяет наличие и срок действия сертификата +3. 📊 Записывает результат в лог +4. 🔄 Обновляет сертификат только если нужно (< 30 дней) +5. ✅ Синхронизирует с NPM при обновлении + +### Мониторинг работы + +#### Просмотр логов ежедневной проверки + +```bash +# Последние проверки +sudo tail -n 100 /var/log/letsencrypt_cron.log + +# Фильтр по статусу +sudo grep "СТАТУС:" /var/log/letsencrypt_cron.log + +# Фильтр по действиям +sudo grep "ДЕЙСТВИЕ:" /var/log/letsencrypt_cron.log + +# Только успешные операции +sudo grep "ОПЕРАЦИЯ ЗАВЕРШЕНА УСПЕШНО" /var/log/letsencrypt_cron.log +``` + +#### Проверка следующего запуска cron + +```bash +# Список задач cron +sudo crontab -l + +# Статус cron службы +sudo systemctl status cron +``` + +### Уведомления при обновлении + +Добавьте email уведомления в cron: + +```bash +# В начале crontab добавьте +MAILTO=admin@example.com + +# Задача с уведомлениями +0 3 * * * /usr/bin/python3 /path/to/letsencrypt_regru_api.py -c /etc/letsencrypt/regru_config.json 2>&1 | mail -s "SSL Certificate Check - $(date)" admin@example.com +``` + +--- + +## Автоматизация обновления + +Let's Encrypt сертификаты действительны 90 дней. Рекомендуется настроить автоматическое обновление. + +### Использование cron (для обоих скриптов) + +#### Для Python скрипта + +```bash +# Открыть crontab +sudo crontab -e + +# Добавить задачу (проверка каждый день в 3:00 AM) +0 3 * * * /usr/bin/python3 /path/to/letsencrypt_regru_api.py -c /etc/letsencrypt/regru_config.json >> /var/log/letsencrypt_cron.log 2>&1 +``` + +#### Для Bash скрипта + +```bash +# Открыть crontab +sudo crontab -e + +# Добавить задачу (проверка каждый день в 3:00 AM) +0 3 * * * /path/to/letsencrypt_regru_dns.sh >> /var/log/letsencrypt_cron.log 2>&1 +``` + +### Использование systemd timer + +Создайте systemd service и timer для более гибкого управления: + +#### Создание service файла + +```bash +sudo nano /etc/systemd/system/letsencrypt-regru.service +``` + +Содержимое: + +```ini +[Unit] +Description=Let's Encrypt Certificate Renewal with reg.ru DNS +After=network.target + +[Service] +Type=oneshot +ExecStart=/usr/bin/python3 /path/to/letsencrypt_regru_api.py -c /etc/letsencrypt/regru_config.json +StandardOutput=journal +StandardError=journal + +[Install] +WantedBy=multi-user.target +``` + +#### Создание timer файла + +```bash +sudo nano /etc/systemd/system/letsencrypt-regru.timer +``` + +Содержимое: + +```ini +[Unit] +Description=Daily Let's Encrypt Certificate Check and Renewal +Requires=letsencrypt-regru.service + +[Timer] +OnCalendar=daily +Persistent=true +RandomizedDelaySec=1h + +[Install] +WantedBy=timers.target +``` + +#### Активация timer + +```bash +# Перезагрузка systemd +sudo systemctl daemon-reload + +# Включение и запуск timer +sudo systemctl enable letsencrypt-regru.timer +sudo systemctl start letsencrypt-regru.timer + +# Проверка статуса +sudo systemctl status letsencrypt-regru.timer +sudo systemctl list-timers +``` + +--- + +## Устранение неполадок + +### Проблема: Ошибка аутентификации API reg.ru + +**Решение:** +- Проверьте правильность имени пользователя и пароля +- Убедитесь, что у вашего аккаунта есть доступ к API +- Проверьте, что домен находится под управлением вашего аккаунта + +```bash +# Проверка доступа к API +curl -X POST "https://api.reg.ru/api/regru2/user/get_balance" \ + -d "username=YOUR_USERNAME" \ + -d "password=YOUR_PASSWORD" \ + -d "output_format=json" +``` + +### Проблема: DNS запись не распространяется + +**Решение:** +- Увеличьте параметр `dns_propagation_wait` в конфигурации (например, до 120 секунд) +- Проверьте DNS записи вручную: + +```bash +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 не установлен + +**Решение:** + +```bash +# Ubuntu/Debian +sudo apt-get install certbot + +# CentOS/RHEL +sudo yum install certbot + +# Или через snap +sudo snap install --classic certbot +``` + +### Проблема: Плагин certbot-dns-regru не найден + +**Решение:** + +```bash +# Установка через pip +sudo pip3 install certbot-dns-regru + +# Или через pip3 с обновлением +sudo pip3 install --upgrade certbot-dns-regru +``` + +### Проблема: Недостаточно прав + +**Решение:** +- Убедитесь, что запускаете скрипт от имени root или с sudo +- Проверьте права доступа к директории `/etc/letsencrypt/` + +```bash +sudo chmod 755 /etc/letsencrypt/ +sudo chown -R root:root /etc/letsencrypt/ +``` + +### Проблема: Ошибка при перезагрузке веб-сервера + +**Решение:** +- Проверьте, какой веб-сервер используется: + +```bash +systemctl status nginx +systemctl status apache2 +``` + +- Вручную перезагрузите веб-сервер: + +```bash +# Для Nginx +sudo systemctl reload nginx + +# Для Apache +sudo systemctl reload apache2 +``` + +### Просмотр подробных логов certbot + +```bash +# Логи certbot +sudo tail -f /var/log/letsencrypt/letsencrypt.log + +# Логи скрипта +sudo tail -f /var/log/letsencrypt_regru.log +``` + +### Тестовый режим (staging) + +Для тестирования используйте staging окружение Let's Encrypt: + +```bash +# Добавьте опцию --staging к команде certbot +certbot certonly --staging --dns-regru ... +``` + +--- + +## Проверка полученного сертификата + +### Просмотр информации о сертификате + +```bash +# Просмотр всех сертификатов +sudo certbot certificates + +# Просмотр конкретного сертификата +sudo openssl x509 -in /etc/letsencrypt/live/example.com/cert.pem -text -noout + +# Проверка даты истечения +sudo openssl x509 -enddate -noout -in /etc/letsencrypt/live/example.com/cert.pem +``` + +### Проверка сертификата в браузере + +1. Откройте ваш сайт в браузере: `https://example.com` +2. Нажмите на иконку замка в адресной строке +3. Проверьте информацию о сертификате +4. Убедитесь, что сертификат выдан Let's Encrypt и покрывает wildcard домен + +### Онлайн проверка SSL + +- [SSL Labs](https://www.ssllabs.com/ssltest/) +- [SSL Shopper](https://www.sslshopper.com/ssl-checker.html) + +--- + +## Использование сертификата в Nginx Proxy Manager + +После получения сертификата вы можете использовать его в Nginx Proxy Manager: + +### Вариант 1: Импорт существующего сертификата + +1. Войдите в Nginx Proxy Manager: http://10.10.10.14:81/ +2. Перейдите в **SSL Certificates** → **Add SSL Certificate** +3. Выберите **Custom** +4. Вставьте содержимое файлов: + - Certificate Key: `/etc/letsencrypt/live/dfv24.com/privkey.pem` + - Certificate: `/etc/letsencrypt/live/dfv24.com/fullchain.pem` +5. Сохраните сертификат + +### Вариант 2: Прямая настройка Nginx + +Если вы используете Nginx напрямую, добавьте в конфигурацию: + +```nginx +server { + listen 443 ssl http2; + server_name dfv24.com *.dfv24.com; + + ssl_certificate /etc/letsencrypt/live/dfv24.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/dfv24.com/privkey.pem; + + # Дополнительные SSL настройки + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers HIGH:!aNULL:!MD5; + ssl_prefer_server_ciphers on; + + # ... остальная конфигурация +} +``` + +--- + +## 📚 Полное описание всех команд + +### Команда `--check` + +**Назначение**: Проверяет срок действия текущего SSL сертификата. + +**Что делает:** +- Проверяет наличие сертификата в `/etc/letsencrypt/live/[домен]/` +- Читает дату истечения из `cert.pem` +- Показывает сколько дней осталось до истечения +- Рекомендует обновление если осталось < 30 дней + +**Пример использования:** +```bash +letsencrypt-regru --check +# Выход: "Certificate expires in 45 days" или "Certificate needs renewal (15 days left)" +``` + +--- + +### Команда `--obtain` + +**Назначение**: Получает новый SSL сертификат от Let's Encrypt. + +**Что делает:** +1. Проверяет доступ к API reg.ru +2. Запускает certbot с DNS-01 challenge +3. Автоматически создает TXT запись `_acme-challenge` через API reg.ru +4. Ожидает распространения DNS (60 секунд) +5. Let's Encrypt проверяет DNS запись +6. Получает сертификат и сохраняет в `/etc/letsencrypt/live/` +7. Автоматически удаляет временную TXT запись +8. (Опционально) Загружает сертификат в Nginx Proxy Manager + +**Пример использования:** +```bash +letsencrypt-regru --obtain +letsencrypt-regru --obtain -v # с подробным выводом +``` + +**Поддержка wildcard:** +- Для `*.example.com` создается одна TXT запись для основного домена +- Сертификат покрывает все поддомены + +--- + +### Команда `--renew` + +**Назначение**: Обновляет существующий SSL сертификат. + +**Что делает:** +1. Проверяет наличие существующего сертификата +2. Использует `certbot renew` для обновления +3. Автоматически создает новые TXT записи через API +4. Получает обновленный сертификат +5. (Опционально) Обновляет сертификат в Nginx Proxy Manager + +**Пример использования:** +```bash +letsencrypt-regru --renew +``` + +**Когда использовать:** +- Сертификат скоро истекает (< 30 дней) +- Автоматически запускается systemd timer + +--- + +### Команда `--auto` + +**Назначение**: Автоматическая проверка и обновление при необходимости. + +**Что делает:** +1. Запускает `--check` для проверки срока действия +2. Если осталось < 30 дней - запускает `--renew` +3. Если сертификата нет - запускает `--obtain` +4. Логирует все действия + +**Пример использования:** +```bash +letsencrypt-regru --auto +``` + +**Идеально для:** +- Запуска через cron или systemd timer +- Полностью автоматического управления сертификатами + +--- + +### Команда `--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` + +**Назначение**: Создает тестовый самоподписанный сертификат. + +**Что делает:** +1. Генерирует приватный ключ RSA 2048 бит +2. Создает самоподписанный сертификат на 365 дней +3. Сохраняет в `/etc/letsencrypt/live/[домен]/` +4. (Опционально) Загружает в Nginx Proxy Manager + +**Пример использования:** +```bash +letsencrypt-regru --test-cert +``` + +**Преимущества:** +- ✅ Не требует интернет соединения +- ✅ Мгновенное создание (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` + +**Назначение**: Проверяет доступ к API reg.ru. + +**Что делает:** +1. Определяет текущий публичный IP адрес (через ipinfo.io) +2. Выполняет тестовый запрос к API reg.ru +3. Показывает баланс аккаунта +4. Проверяет авторизацию + +**Пример использования:** +```bash +letsencrypt-regru --test-api + +# Вывод: +# ✓ Ваш текущий IP: 178.218.115.80 +# ✓ API reg.ru доступен +# ✓ Баланс аккаунта: 1234.56 руб. +``` + +**Используйте когда:** +- Первая настройка (проверка учетных данных) +- Ошибки "Access to API from this IP denied" +- Нужно узнать текущий IP для whitelist + +--- + +### Команда `--test-dns` + +**Назначение**: Полная симуляция процесса SSL сертификации с тестовой DNS записью. + +**Что делает:** +1. **Шаг 1**: Проверяет доступ к API reg.ru (`--test-api`) +2. **Шаг 2**: Создает временную TXT запись `_acme-challenge.[домен]` со случайным значением +3. **Шаг 3**: Ожидает распространения DNS (60 секунд с прогресс-баром) +4. **Шаг 4**: Проверяет DNS запись через публичные DNS серверы (8.8.8.8, 1.1.1.1) +5. **Шаг 5**: Автоматически удаляет тестовую запись + +**Пример использования:** +```bash +letsencrypt-regru --test-dns + +# Вывод: +# ✓ API reg.ru доступен +# ✓ TXT запись создана: _acme-challenge.example.com +# ⏳ Ожидание распространения DNS: [===> ] 30/60 секунд +# ✓ DNS запись обнаружена через Google DNS +# ✓ DNS запись обнаружена через Cloudflare DNS +# ✓ Тестовая запись удалена +``` + +**Используйте для:** +- Проверки что API reg.ru работает корректно +- Проверки что DNS записи распространяются +- Тестирования перед реальным получением сертификата +- Диагностики проблем с DNS + +**Преимущества:** +- Не влияет на лимиты Let's Encrypt +- Безопасное тестирование (создает временную запись) +- Показывает весь процесс пошагово + +--- + +### Команда `--auth-hook` (служебная) + +**Назначение**: Используется certbot для создания DNS записи во время валидации. + +**Что делает:** +1. Читает переменные окружения certbot (`CERTBOT_DOMAIN`, `CERTBOT_VALIDATION`) +2. Создает TXT запись `_acme-challenge.[домен]` через API reg.ru +3. Ожидает распространения DNS (60 секунд) +4. Возвращает управление certbot + +**Используется автоматически:** Certbot вызывает этот hook при запуске `--obtain` или `--renew` + +--- + +### Команда `--cleanup-hook` (служебная) + +**Назначение**: Используется certbot для удаления DNS записи после валидации. + +**Что делает:** +1. Читает переменные окружения certbot +2. Удаляет TXT запись `_acme-challenge.[домен]` через API reg.ru +3. Очищает временные данные + +**Используется автоматически:** Certbot вызывает этот hook после завершения валидации + +--- + +### Команда `--help` + +**Назначение**: Показывает справку по всем доступным командам. + +**Пример использования:** +```bash +letsencrypt-regru --help +``` + +--- + +### Флаг `-v` (verbose) + +**Назначение**: Включает подробный вывод для диагностики. + +**Что показывает:** +- Все HTTP запросы к API reg.ru +- Ответы API (JSON) +- Шаги выполнения certbot +- Детали проверки DNS +- Подробные ошибки + +**Пример использования:** +```bash +letsencrypt-regru --obtain -v +letsencrypt-regru --test-dns -v +letsencrypt-regru --check -v +``` + +--- + +## Дополнительная документация + +- 📘 **[TESTING_GUIDE.md](docs/ru/TESTING_GUIDE.md)** - Полное руководство по созданию и использованию тестовых сертификатов +- 🔄 **[GITEA_SYNC.md](docs/ru/GITEA_SYNC.md)** - Настройка автоматической синхронизации Gitea → GitHub +- 📘 **[CHEATSHEET.md](docs/ru/CHEATSHEET.md)** - Быстрая шпаргалка по командам +- � **[API_TROUBLESHOOTING.md](docs/ru/API_TROUBLESHOOTING.md)** - Устранение проблем с API reg.ru +- �🚀 **[BUILD_GUIDE.md](docs/ru/BUILD_GUIDE.md)** - Сборка исполняемых файлов с PyInstaller +- 📦 **[INSTALL_GUIDE.md](docs/ru/INSTALL_GUIDE.md)** - Подробное руководство по установке +- 🛠️ **[MAKEFILE_COMMANDS.md](docs/ru/MAKEFILE_COMMANDS.md)** - Все команды Makefile +- 🏗️ **[PROJECT_STRUCTURE.md](docs/ru/PROJECT_STRUCTURE.md)** - Структура проекта +- 📝 **[config.json.example](config.json.example)** - Пример конфигурации + +--- + +## Поддержка и вопросы + +При возникновении проблем: + +1. **Проверьте логи**: + ```bash + journalctl -u letsencrypt-regru -f + tail -f /var/log/letsencrypt-regru/letsencrypt_regru.log + ``` + +2. **Используйте команды диагностики**: + ```bash + letsencrypt-regru --test-api # Проверка API + letsencrypt-regru --test-dns # Проверка DNS + letsencrypt-regru --check -v # Проверка сертификата + ``` + +3. **Проверьте документацию**: + - [API_TROUBLESHOOTING.md](docs/ru/API_TROUBLESHOOTING.md) - Решение проблем с API + - [TESTING_GUIDE.md](docs/ru/TESTING_GUIDE.md) - Руководство по тестированию + - Документация reg.ru API: https://www.reg.ru/support/api + - Документация Let's Encrypt: https://letsencrypt.org/docs/ + +--- + +## Заключение + +Оба скрипта предоставляют надежное решение для автоматического управления SSL сертификатами Let's Encrypt с использованием DNS-валидации через API reg.ru. + +**Рекомендации:** +- Используйте Python скрипт для более гибкой настройки и интеграции +- Используйте Bash скрипт для простоты и минимальных зависимостей +- **Используйте тестовые сертификаты для разработки** (без лимитов Let's Encrypt) +- Настройте автоматическое обновление через cron или systemd timer +- Регулярно проверяйте логи и статус сертификатов +- Храните учетные данные в безопасности (chmod 600) + +**Быстрый старт для тестирования:** +```bash +sudo make install # Установка +sudo make test-cert # Создать тестовый сертификат +sudo make obtain # Получить production сертификат +``` + +Успешной автоматизации! 🔒 + +--- + +## 🔄 Синхронизация Gitea → GitHub + +Проект поддерживает автоматическую синхронизацию из Gitea в GitHub. + +### Быстрая настройка + +**Метод 1: Git Hook (мгновенно)** +```bash +# На сервере Gitea скопируйте hook +cp gitea-hooks/post-receive /path/to/repo.git/hooks/ +chmod +x /path/to/repo.git/hooks/post-receive +``` + +**Метод 2: GitHub Actions (каждый час)** +- Workflow уже настроен в `.github/workflows/sync-from-gitea.yml` +- Добавьте секреты `GITEA_URL` и `GITEA_TOKEN` в GitHub + +**Подробная документация**: См. [GITEA_SYNC.md](GITEA_SYNC.md) + +--- diff --git a/config.json.example b/config.json.example new file mode 100644 index 0000000..f8f563e --- /dev/null +++ b/config.json.example @@ -0,0 +1,21 @@ +{ + "regru_username": "your_username", + "regru_password": "your_password", + "domain": "dfv24.com", + "domains": [ + "dfv24.com", + "pages.github.dfv24.com" + ], + "wildcard": true, + "email": "admin@dfv24.com", + "cert_dir": "/etc/letsencrypt/live", + "log_file": "/var/log/letsencrypt_regru.log", + "dns_propagation_wait": 60, + "dns_check_attempts": 10, + "dns_check_interval": 10, + "renewal_days": 30, + "npm_enabled": true, + "npm_host": "http://192.168.10.14:81", + "npm_email": "admin@example.com", + "npm_password": "changeme" +} diff --git a/docs/en/API_TROUBLESHOOTING_EN.md b/docs/en/API_TROUBLESHOOTING_EN.md new file mode 100644 index 0000000..b87d334 --- /dev/null +++ b/docs/en/API_TROUBLESHOOTING_EN.md @@ -0,0 +1,206 @@ +# 🔧 reg.ru API Troubleshooting Guide + +## ❌ Issue: "Access to API from this IP denied" + +This error occurs when reg.ru API is blocked for your IP address due to security settings. + +### 🔍 Diagnostics + +First, determine your current IP address: + +```bash +# Method 1: Using script's built-in function +sudo letsencrypt-regru --test-api + +# Method 2: Using curl +curl -s https://ipinfo.io/ip + +# Method 3: Using website +# Open https://whatismyipaddress.com/ +``` + +### ✅ Solution + +#### Method 1: Add IP to whitelist (recommended) + +1. **Login to reg.ru control panel** + - Open https://www.reg.ru/ + - Login to your account + +2. **Navigate to API settings** + - Menu → "Settings" (Настройки) + - Section "Security" (Безопасность) + - Subsection "API" + +3. **Configure IP access** + - Find "IP Restrictions" section + - Click "Add IP address" + - Enter your current IP address + - Save settings + +4. **Test settings** + ```bash + sudo letsencrypt-regru --test-api + ``` + +#### Method 2: Disable IP restrictions (less secure) + +⚠️ **WARNING**: This reduces your account security! + +1. In reg.ru API settings find "IP Restrictions" +2. Disable "Allow access only from specified IPs" option +3. Save settings + +### 🔒 Security Recommendations + +1. **Use static IP** + - If you have dynamic IP, consider purchasing static IP + - Or regularly update allowed IP list + +2. **Limit API access** + - Add only necessary IP addresses + - Regularly review and clean up the list + +3. **Use strong passwords** + - Complex password for reg.ru account + - Two-factor authentication if available + +## ❌ Issue: "Invalid username or password" + +### ✅ Solution + +1. **Check credentials** + ```bash + sudo nano /etc/letsencrypt-regru/config.json + ``` + + Make sure you have correct: + - `regru_username` - reg.ru login + - `regru_password` - reg.ru password + +2. **Check file permissions** + ```bash + sudo chmod 600 /etc/letsencrypt-regru/config.json + sudo chown root:root /etc/letsencrypt-regru/config.json + ``` + +3. **Test connection** + ```bash + sudo letsencrypt-regru --test-api + ``` + +## ❌ Issue: "IP exceeded allowed connection rate" + +### Cause +Reg.ru API limits request frequency from single IP (typically 10-20 requests per minute). + +### ✅ Solution + +1. **Wait 5-10 minutes** + ```bash + # Wait before next attempt + sleep 600 # 10 minutes + sudo letsencrypt-regru --obtain + ``` + +2. **Configure automation properly** + ```bash + # Check certificates once per day + sudo systemctl enable letsencrypt-regru.timer + sudo systemctl start letsencrypt-regru.timer + + # Check schedule + sudo systemctl cat letsencrypt-regru.timer + ``` + +3. **Request frequency recommendations** + - ✅ Automatic check: **once per day** + - ✅ Manual check: **no more than once per hour** + - ❌ Avoid frequent `--test-api` tests + - ❌ Don't create frequent cron jobs + +4. **Use --check instead of --obtain** + ```bash + # Check without creating certificate + sudo letsencrypt-regru --check + ``` + +## ❌ Issue: Connection timeout + +### ✅ Solution + +1. **Check internet connection** + ```bash + ping -c 4 api.reg.ru + curl -I https://api.reg.ru/api/regru2 + ``` + +2. **Check firewall** + ```bash + # Temporarily disable firewall for testing + sudo ufw status + sudo iptables -L + ``` + +3. **Check proxy settings** + - Ensure `HTTP_PROXY`, `HTTPS_PROXY` environment variables don't interfere + +## 🧪 API Testing + +Always test API before use: + +```bash +# Full API test +sudo letsencrypt-regru --test-api + +# Test with verbose output +sudo letsencrypt-regru --test-api -v + +# Check configuration +sudo letsencrypt-regru --check +``` + +## 📞 Getting Help + +### reg.ru Technical Support + +- **Email**: support@reg.ru +- **Phone**: 8 (495) 580-11-11 +- **Online chat**: on reg.ru website + +### Documentation + +- **reg.ru API**: https://www.reg.ru/support/api +- **Usage examples**: https://www.reg.ru/support/api/examples +- **API FAQ**: https://www.reg.ru/support/api/faq + +### Diagnostic Logs + +Always include logs when contacting support: + +```bash +# Enable verbose logs +sudo letsencrypt-regru --test-api -v + +# View recent logs +sudo tail -n 50 /var/log/letsencrypt-regru/letsencrypt_regru.log + +# Certbot logs +sudo tail -n 50 /var/log/letsencrypt/letsencrypt.log +``` + +## 🔄 Alternative DNS Providers + +If reg.ru API issues are critical, consider alternatives: + +1. **Cloudflare** - excellent API, free DNS +2. **Route53** (AWS) - powerful but paid +3. **DigitalOcean DNS** - simple and reliable +4. **Google Cloud DNS** - GCP integration + +These require script modification or other certbot plugins. + +--- + +**Last Updated**: October 29, 2025 +**Document Version**: 1.0 \ No newline at end of file diff --git a/docs/en/Add_Lets_Encrypt_Certificate_for_regru_Provider_EN.md b/docs/en/Add_Lets_Encrypt_Certificate_for_regru_Provider_EN.md new file mode 100644 index 0000000..2e88fa9 --- /dev/null +++ b/docs/en/Add_Lets_Encrypt_Certificate_for_regru_Provider_EN.md @@ -0,0 +1,56 @@ +# Guide to Creating Let's Encrypt Certificate with DNS Challenge for reg.ru Provider in Nginx Proxy Manager + +--- + +## Prerequisites +- Access to Nginx Proxy Manager (NPM) +- Access to reg.ru account with DNS management permissions +- API key for DNS management in reg.ru (if automatic integration is available) +- Need to obtain certificate for `*.dfv24.com` (wildcard certificate) + +--- + +## Step 1. Getting API Key for reg.ru + +1. Log in to reg.ru control panel +2. Navigate to API management section (if supported) +3. Create or find API key with DNS records editing permissions +4. Save API key and secret (Client ID and API Token) + +--- + +## Step 2. Configuring Nginx Proxy Manager to Use DNS Challenge reg.ru + +1. In NPM admin panel, go to **SSL Certificates → Add SSL Certificate** +2. Select **Let's Encrypt** -> **DNS Challenge** +3. In **Provider** field, select `reg_ru` or `custom` (if provider not available, script will be needed) +4. Fill in API fields with required parameters: + - Client ID + - API Token +5. In **Domain Names** field, specify: + `*.dfv24.com` (for wildcard certificate) + and main domain `dfv24.com` +6. Enable other options (Terms of Service, Email) +7. Click **Save** to request certificate +8. NPM will automatically add DNS TXT records for domain ownership verification through reg.ru API + +--- + +## Step 3. Verification and Automatic Renewal + +- After successful certificate creation, NPM will automatically renew it through DNS Challenge. +- For successful renewal, it's important that API key remains valid and NPM has access to DNS management. + +--- + +## If NPM Doesn't Have Ready Integration with reg.ru + +- Use external script to update DNS TXT records in reg.ru, configured in NPM through **Custom DNS Provider**. +- Configure curl requests to reg.ru API for adding/removing TXT records. + +--- + +# Summary + +For Let's Encrypt wildcard certificates with reg.ru, DNS Challenge must be used with provider's API for automatic DNS record management. +In Nginx Proxy Manager, configure DNS Challenge considering reg.ru specifics for seamless certificate obtaining and renewal. diff --git a/docs/en/BUILD_GUIDE_EN.md b/docs/en/BUILD_GUIDE_EN.md new file mode 100644 index 0000000..7fdf1b8 --- /dev/null +++ b/docs/en/BUILD_GUIDE_EN.md @@ -0,0 +1,455 @@ +# 🔨 Executable Build Guide + +This guide describes the process of compiling the `letsencrypt_regru_api.py` Python script into executable files for Linux and Windows using PyInstaller. + +## 📋 Table of Contents + +- [Advantages of Executable Files](#advantages-of-executable-files) +- [Quick Start](#quick-start) +- [Detailed Instructions](#detailed-instructions) +- [Cross-Compilation](#cross-compilation) +- [Troubleshooting](#troubleshooting) + +--- + +## ✅ Advantages of Executable Files + +### Pros: +- ✅ **Single file** - easy to distribute and deploy +- ✅ **Standalone** - no Python installation required on target system +- ✅ **All dependencies included** - requests, cryptography, and certbot modules are bundled +- ✅ **Simple execution** - just download and run + +### Cons: +- ❌ **Large size** - ~40-60 MB (including Python runtime and libraries) +- ❌ **Certbot dependency** - system certbot is still required +- ❌ **Slow first launch** - unpacking takes a few seconds +- ❌ **Rebuild required** - code changes require recompilation + +--- + +## 🚀 Quick Start + +### Build for current OS: +```bash +make build +``` + +### Build for all platforms: +```bash +make build-all +``` + +### Full release (build + packages): +```bash +make release +``` + +--- + +## 📖 Detailed Instructions + +### 1. Install Dependencies + +#### Option A: Automatic Installation +```bash +make install-pyinstaller +``` + +#### Option B: Manual Installation +```bash +pip install pyinstaller +pip install -r requirements.txt +``` + +### 2. Build for Linux + +**On Linux system:** +```bash +make build-linux +``` + +**Result:** +- File: `dist/letsencrypt-regru` +- Size: ~45-55 MB +- Format: ELF 64-bit executable + +**Testing:** +```bash +./dist/letsencrypt-regru --help +sudo ./dist/letsencrypt-regru --check -c /etc/letsencrypt-regru/config.json +``` + +### 3. Build for Windows + +**On Windows system (PowerShell/CMD):** +```bash +make build-windows +``` + +**Result:** +- File: `dist/letsencrypt-regru.exe` +- Size: ~40-50 MB +- Format: PE32+ executable (Windows) + +**Testing:** +```powershell +.\dist\letsencrypt-regru.exe --help +``` + +### 4. Create Distribution Packages + +#### Linux package (tar.gz): +```bash +make package-linux +``` + +**Package contents:** +- `letsencrypt-regru` - executable file +- `README.md` - documentation +- `systemd/` - systemd unit files +- `config.json.example` - configuration example + +**Result:** `dist/letsencrypt-regru-linux-x86_64.tar.gz` + +#### Windows package (zip): +```bash +make package-windows +``` + +**Result:** `dist/letsencrypt-regru-windows-x86_64.zip` + +### 5. Full Release Cycle + +Create release with all artifacts: + +```bash +make release +``` + +**What happens:** +1. Clean old artifacts (`clean-build`) +2. Install/update PyInstaller +3. Build for Linux (`build-linux`) +4. Build for Windows (`build-windows`) +5. Create Linux package (`package-linux`) +6. Create Windows package (`package-windows`) +7. Generate SHA256 checksums + +**Result in `dist/`:** +``` +letsencrypt-regru # Linux executable +letsencrypt-regru.exe # Windows executable +letsencrypt-regru-linux-x86_64.tar.gz +letsencrypt-regru-windows-x86_64.zip +``` + +--- + +## 🔄 Cross-Compilation + +### ⚠️ Important Notes + +**Not recommended:** +- Building Linux version on Windows +- Building Windows version on Linux +- Building macOS version on other OSes + +**Reasons:** +- System library incompatibility +- Different executable formats +- Path and separator issues + +### Recommendations + +#### For Linux builds: +1. Use Ubuntu 20.04+ or Debian 10+ +2. Install build-essential +3. Use Python virtual environment + +```bash +sudo apt-get update +sudo apt-get install -y python3 python3-pip build-essential +make build-linux +``` + +#### For Windows builds: +1. Use Windows 10/11 +2. Install Python 3.8+ +3. Use PowerShell or CMD + +```powershell +python -m pip install --upgrade pip +make build-windows +``` + +#### For both platforms: +Use CI/CD (GitHub Actions, GitLab CI): + +```yaml +# .github/workflows/build.yml +name: Build Releases + +on: + push: + tags: + - 'v*' + +jobs: + build-linux: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Build Linux + run: make build-linux + + build-windows: + runs-on: windows-latest + steps: + - uses: actions/checkout@v3 + - name: Build Windows + run: make build-windows +``` + +--- + +## 🛠️ All Makefile Commands + +### Main Commands: + +| Command | Description | +|---------|-------------| +| `make build` | Build for current OS | +| `make build-linux` | Build for Linux | +| `make build-windows` | Build for Windows | +| `make build-all` | Build for all platforms | +| `make package-linux` | Create tar.gz package | +| `make package-windows` | Create zip package | +| `make release` | Full release cycle | + +### Supporting Commands: + +| Command | Description | +|---------|-------------| +| `make install-pyinstaller` | Install PyInstaller | +| `make test-build` | Test built file | +| `make clean-build` | Clean build artifacts | +| `make build-info` | Show environment info | + +--- + +## 🐛 Troubleshooting + +### Issue: PyInstaller not found + +**Error:** +``` +make: pyinstaller: Command not found +``` + +**Solution:** +```bash +make install-pyinstaller +# or +pip install pyinstaller +``` + +--- + +### Issue: Module imports not working + +**Error:** +``` +ModuleNotFoundError: No module named 'requests' +``` + +**Solution:** +```bash +pip install -r requirements.txt +# or add to PyInstaller command: +--hidden-import requests +--hidden-import certbot +--hidden-import cryptography +``` + +--- + +### Issue: Large file size + +**Size ~100+ MB instead of 40-60 MB** + +**Causes:** +- Extra modules included +- Not using `--onefile` +- Debug symbols included + +**Solution:** +```bash +# Use optimization flags: +pyinstaller --onefile \ + --strip \ + --exclude-module tkinter \ + --exclude-module matplotlib \ + letsencrypt_regru_api.py +``` + +--- + +### Issue: Certbot not working in executable + +**Error:** +``` +certbot: command not found +``` + +**Solution:** + +Certbot is called via `subprocess` and must be installed on the system: + +**Linux:** +```bash +sudo apt-get install certbot +``` + +**Windows:** +- Not directly supported +- Use WSL or Docker + +--- + +### Issue: File permission errors + +**Error:** +``` +Permission denied: /etc/letsencrypt/ +``` + +**Solution:** +```bash +# Linux/macOS +sudo ./dist/letsencrypt-regru --check + +# Or set proper permissions: +sudo chmod +x ./dist/letsencrypt-regru +sudo chown root:root ./dist/letsencrypt-regru +``` + +--- + +### Issue: Slow startup + +**First launch takes 5-10 seconds** + +**Reason:** +PyInstaller unpacks files to temporary directory on each run. + +**Solution:** +- This is normal behavior for `--onefile` +- Use `--onedir` for faster startup (but many files) +- Temporary directory is cached automatically + +--- + +### Issue: Antivirus blocking file + +**Windows Defender marks .exe as virus** + +**Reasons:** +- Self-extracting archive looks like malware +- No digital signature +- Unknown executable file + +**Solution:** +1. **Add to exclusions:** + - Windows Defender → Settings → Exclusions + +2. **Sign file with digital signature:** + ```bash + # Requires Code Signing certificate + signtool sign /f cert.pfx /p password dist/letsencrypt-regru.exe + ``` + +3. **Check on VirusTotal:** + - Upload file to virustotal.com + - Add results to README + +--- + +## 📊 Comparison: Python vs Executable + +| Feature | Python Script | Executable File | +|---------|---------------|-----------------| +| Size | ~50 KB | ~40-60 MB | +| Dependencies | Requires Python + pip | Standalone | +| Startup Speed | Fast (~1 sec) | Slow (~5-10 sec) | +| Updates | Just replace .py | Requires rebuild | +| Compatibility | Any OS with Python | Only target OS | +| Installation | Requires venv setup | Download and run | +| Certbot | Via subprocess | Via subprocess | + +--- + +## 🎯 Recommendations + +### Use Python script if: +- ✅ Python already installed on system +- ✅ Frequent code updates needed +- ✅ Using virtual environment +- ✅ Working on servers (production) + +### Use executable file if: +- ✅ Python not installed +- ✅ Simple deployment needed +- ✅ Distributing to end users +- ✅ Testing on clean systems + +--- + +## 📦 Using Built File Examples + +### Linux: + +```bash +# Download and extract +wget https://github.com/user/repo/releases/download/v1.0/letsencrypt-regru-linux-x86_64.tar.gz +tar -xzf letsencrypt-regru-linux-x86_64.tar.gz + +# Install +sudo mv letsencrypt-regru /usr/local/bin/ +sudo chmod +x /usr/local/bin/letsencrypt-regru + +# Use +sudo letsencrypt-regru --help +sudo letsencrypt-regru --check -c /etc/letsencrypt-regru/config.json +``` + +### Windows: + +```powershell +# Download and extract +Invoke-WebRequest -Uri "https://github.com/user/repo/releases/download/v1.0/letsencrypt-regru-windows-x86_64.zip" -OutFile "letsencrypt-regru.zip" +Expand-Archive -Path letsencrypt-regru.zip -DestinationPath "C:\Program Files\LetsEncrypt-RegRu" + +# Use +cd "C:\Program Files\LetsEncrypt-RegRu" +.\letsencrypt-regru.exe --help +``` + +--- + +## 📝 Additional Resources + +- [PyInstaller Documentation](https://pyinstaller.org/en/stable/) +- [PyInstaller FAQ](https://pyinstaller.org/en/stable/FAQ.html) +- [Building Cross-Platform Applications](https://pyinstaller.org/en/stable/operating-mode.html) + +--- + +## 📄 License + +This project uses the license as specified in the main README.md. + +--- + +**Author:** Dmitry Fofanov +**Last Updated:** October 28, 2025 diff --git a/docs/en/CHANGELOG_EN.md b/docs/en/CHANGELOG_EN.md new file mode 100644 index 0000000..12b1a1c --- /dev/null +++ b/docs/en/CHANGELOG_EN.md @@ -0,0 +1,187 @@ +# 📋 Changelog + +## [2.1.0] - 2025-10-27 + +### 🆕 Added + +#### Test SSL Certificate Generation +- ✨ **New `TestCertificateGenerator` class** - self-signed certificate generation +- ✨ **`--test-cert` command** in Python script for test certificate creation +- ✨ **`test_certificate.sh` script** - standalone creation via OpenSSL +- ✨ **`make test-cert` command** in Makefile for quick testing + +#### Documentation +- 📘 **TESTING_GUIDE.md** (370+ lines) - complete testing guide + - Bypass Let's Encrypt limits (5 certificates per week) + - Certificate creation method comparison + - CI/CD and Docker examples + - Transition from test to production + - FAQ and solutions + +- 📘 **TESTING_GUIDE_EN.md** - English version of testing guide + +- 📘 **PROJECT_STRUCTURE.md** - project structure + - All files description + - Features list + - Technologies + +- 📘 **PROJECT_STRUCTURE_EN.md** - English version + +- 📘 **CHEATSHEET.md** - quick reference + - Main commands + - Use case scenarios + - Common errors and solutions + - Development workflow + +- 📘 **CHEATSHEET_EN.md** - English version + +- 📘 **DESCRIPTION.md** - project description in Russian and English + +- 📘 **CHANGELOG_EN.md** - English changelog + +- 📘 **GITEA_SYNC.md** - Gitea → GitHub synchronization + - 4 sync methods + - Step-by-step setup + - Troubleshooting + +- 📘 **GITEA_SYNC_EN.md** - English version + +- 📘 **README_EN.md** - Complete English main guide + +#### Functionality +- ✨ Support for **unlimited** test certificates +- ✨ **Instant creation** (1-2 seconds) without DNS validation +- ✨ **Automatic upload** of test certificates to NPM +- ✨ **Full compatibility** of structure with Let's Encrypt +- ✨ **Wildcard support** for test certificates + +#### Repository Synchronization +- ✨ **Automatic Gitea → GitHub sync** via Git Hooks +- ✨ **GitHub Actions workflow** for hourly sync check +- ✨ **Webhook integration** between Gitea and GitHub +- ✨ **Multiple sync methods** (Hooks, Actions, Mirror, Double Remote) + +### 🔧 Improved + +#### Python Script +- Added `cryptography` library import with installation check +- New command-line parameters: + - `--test-cert` - create test certificate + - `--auto` - explicit automatic mode +- Improved test certificate handling in NPM +- Detailed logging of generation process + +#### Makefile +- Added `make test-cert` command with beautiful output +- Information messages about test certificate benefits +- Security warnings + +#### README.md +- "Test Self-Signed Certificate Creation" section +- Updated table of contents with test certificates link +- Test certificate usage examples +- NPM integration for test certificates +- Links to additional documentation +- Gitea → GitHub sync section + +### 🎯 Benefits + +#### For Developers +- ✅ **No limits** - unlimited certificates +- ✅ **Fast** - creation in 1-2 seconds +- ✅ **Offline** - works without internet +- ✅ **Identical structure** - same files as Let's Encrypt + +#### For Testing +- ✅ **CI/CD friendly** - quick creation in pipeline +- ✅ **Docker ready** - easily embeds in containers +- ✅ **Staging environments** - perfect for test servers +- ✅ **Local development** - HTTPS on localhost + +#### For DevOps +- ✅ **Repository sync** - automatic Gitea → GitHub +- ✅ **Multiple methods** - choose what fits +- ✅ **Instant sync** - Git Hooks < 1 second +- ✅ **Reliable backup** - GitHub Actions hourly check + +### 📊 Statistics + +- **Lines of code**: 1,411 (Python script) +- **Makefile lines**: 415 +- **Documentation lines**: 3,500+ +- **Makefile commands**: 13 +- **Operating modes**: 4 (obtain, renew, auto, test-cert) +- **Sync methods**: 4 (Hooks, Actions, Mirror, Remote) +- **Languages**: 2 (Russian, English) + +--- + +## [2.0.0] - 2025-10-27 + +### 🆕 Added +- ✨ Nginx Proxy Manager (NPM) integration +- ✨ `NginxProxyManagerAPI` class for certificate management via API +- ✨ Automatic certificate upload to NPM +- ✨ Automatic certificate update in NPM +- ✨ Automatic expiration check +- ✨ Configurable renewal threshold (`renewal_days`) +- ✨ Makefile for installation/removal automation +- ✨ Systemd service + timer +- ✨ Cron automation + +### 🔧 Improved +- Documentation consolidation into single README.md +- Detailed logging with operation statuses +- Configuration validation +- Improved error handling + +### 📘 Documentation +- Complete NPM integration guide +- Quick start in 3 commands +- Automation examples + +--- + +## [1.0.0] - 2025-10-26 + +### 🆕 First Release +- Python script for Let's Encrypt via reg.ru API +- Bash script with certbot-dns-regru +- PowerShell version for Windows +- DNS-01 validation +- Wildcard certificates +- Basic documentation + +--- + +## Roadmap + +### [2.2.0] - Planned +- [ ] Web interface for management +- [ ] Multiple domain support +- [ ] Notifications (email, telegram) +- [ ] Grafana dashboard for monitoring +- [ ] Certificate backups + +### [3.0.0] - Future +- [ ] Other DNS provider support +- [ ] Cloudflare API +- [ ] Route53 (AWS) +- [ ] Google Cloud DNS + +--- + +## Change Types +- `🆕 Added` - new functionality +- `🔧 Improved` - improvements to existing functionality +- `🐛 Fixed` - bug fixes +- `🗑️ Removed` - removed functionality +- `🔒 Security` - security changes +- `📘 Documentation` - documentation changes + +--- + +**Versioning**: Semantic Versioning (MAJOR.MINOR.PATCH) +- **MAJOR**: Incompatible API changes +- **MINOR**: New functionality with backward compatibility +- **PATCH**: Bug fixes diff --git a/docs/en/CHEATSHEET_EN.md b/docs/en/CHEATSHEET_EN.md new file mode 100644 index 0000000..44277ff --- /dev/null +++ b/docs/en/CHEATSHEET_EN.md @@ -0,0 +1,287 @@ +# ⚡ SSL Certificate Cheatsheet + +## 🚀 Quick Start + +### Installation in 3 Commands +```bash +sudo make install +sudo nano /etc/letsencrypt/regru_config.json # Fill in data +sudo make test-cert # Test +``` + +--- + +## 🧪 Testing (NO Let's Encrypt Limits) + +```bash +# Create test certificate (unlimited) +sudo make test-cert + +# Check status +sudo make status + +# View logs +sudo make logs +``` + +**When to use:** +- ⚠️ Let's Encrypt: max 5 certificates/week +- ✅ Test: UNLIMITED +- ⚡ Creation: 1-2 seconds vs 2-5 minutes + +--- + +## 🔒 Production (Let's Encrypt) + +```bash +# Get real certificate +sudo make obtain + +# Automatic mode (check + renewal) +sudo make run + +# Force renewal +sudo make renew +``` + +--- + +## 📋 Main Commands + +### letsencrypt-regru Commands + +| Command | Description | Limits | Use Case | +|---------|-------------|--------|----------| +| `--check` | Check certificate expiration | - | Monitoring | +| `--obtain` | Obtain new certificate | ⚠️ 5/week | Initial creation | +| `--renew` | Renew existing certificate | ⚠️ 5/week | Renewal | +| `--auto` | Auto-check and renewal | ⚠️ 5/week | Cron/systemd | +| `--test-cert` | Test certificate | ✅ None | Development | +| `--test-api` | Check API reg.ru access | - | Diagnostics | +| `--test-dns` | Test DNS record creation | - | Pre-SSL check | +| `--help` | Show help | - | Help | +| `-v` | Verbose output | - | Debugging | + +### Makefile Commands + +| Command | Description | Equivalent | +|---------|-------------|------------| +| `make test-cert` | Test certificate | `letsencrypt-regru --test-cert` | +| `make obtain` | New Let's Encrypt | `letsencrypt-regru --obtain` | +| `make renew` | Renew existing | `letsencrypt-regru --renew` | +| `make run` | Auto mode | `letsencrypt-regru --auto` | +| `make status` | System status | - | +| `make logs` | Show logs | `journalctl -u letsencrypt-regru` | +| `make check-config` | Check configuration | - | + +### letsencrypt_regru.sh Commands + +| Command | Description | +|---------|-------------| +| `sudo bash letsencrypt_regru.sh install` | Install application | +| `sudo bash letsencrypt_regru.sh update` | Update application | +| `sudo bash letsencrypt_regru.sh uninstall` | Uninstall application | + +--- + +## 📝 Configuration + +### Minimal (testing) +```json +{ + "domain": "test.example.com", + "wildcard": true, + "cert_dir": "/etc/letsencrypt/live" +} +``` + +### Full (production + NPM) +```json +{ + "regru_username": "myuser", + "regru_password": "mypassword", + "domain": "example.com", + "wildcard": true, + "email": "admin@example.com", + "renewal_days": 30, + "npm_enabled": true, + "npm_host": "https://npm.example.com", + "npm_email": "admin@example.com", + "npm_password": "npm_password" +} +``` + +--- + +## 🔄 Workflow + +### Development → Production + +```bash +# 1. Development (test certificates) +sudo make test-cert # Create test +# Test application... + +# 2. Production (Let's Encrypt) +sudo rm -rf /etc/letsencrypt/live/example.com/ # Remove test +sudo make obtain # Create production +``` + +--- + +## 📁 Important Paths + +```bash +# Configuration +/etc/letsencrypt/regru_config.json + +# Certificates +/etc/letsencrypt/live/example.com/ +├── privkey.pem # Private key +├── cert.pem # Certificate +├── fullchain.pem # Full chain (for nginx) +└── chain.pem # CA chain + +# Scripts +/opt/letsencrypt-regru/letsencrypt_regru_api.py + +# Logs +/var/log/letsencrypt_regru.log +``` + +--- + +## 🔍 Verification + +```bash +# Check configuration +sudo make check-config + +# Check certificate +openssl x509 -in /etc/letsencrypt/live/example.com/cert.pem -text -noout + +# Check expiration date +openssl x509 -in /etc/letsencrypt/live/example.com/cert.pem -noout -dates + +# Check systemd +sudo systemctl status letsencrypt-regru.timer +sudo systemctl list-timers letsencrypt-regru.timer + +# Check cron +sudo crontab -l | grep letsencrypt +``` + +--- + +## 🐛 Debugging + +```bash +# Detailed logs +sudo make logs + +# Test run with details +sudo python3 /opt/letsencrypt-regru/letsencrypt_regru_api.py \ + -c /etc/letsencrypt/regru_config.json --check -v + +# Certbot logs +sudo tail -f /var/log/letsencrypt/letsencrypt.log + +# Systemd logs +sudo journalctl -u letsencrypt-regru.service -f +``` + +--- + +## ⚠️ Common Errors + +### Let's Encrypt: Rate limit exceeded +```bash +# SOLUTION: Use test certificates +sudo make test-cert +``` + +### NPM: Certificate not found +```bash +# SOLUTION: Check NPM settings +sudo make check-config + +# Check connection +curl -k https://npm.example.com +``` + +### Permission denied +```bash +# SOLUTION: Run with sudo +sudo make test-cert +``` + +--- + +## 🎯 Use Case Scenarios + +### Local Development +```bash +sudo make test-cert +# Open https://localhost (ignore warning) +``` + +### CI/CD Testing +```bash +# In pipeline +sudo make test-cert +# Run tests... +sudo make status +``` + +### Staging Environment +```bash +sudo make test-cert # Or +sudo make obtain # If domain available +``` + +### Production Environment +```bash +sudo make install +sudo make obtain +# Automatic renewal via cron/systemd +``` + +--- + +## 📚 Documentation + +- **README.md** - Complete guide (1420+ lines) +- **TESTING_GUIDE.md** - Testing guide (370+ lines) +- **PROJECT_STRUCTURE.md** - Project structure +- **CHEATSHEET.md** - This cheatsheet + +--- + +## 🆘 Quick Help + +```bash +# Show all commands +make help + +# Check installation +sudo make status + +# Complete reinstall +sudo make uninstall +sudo make install +``` + +--- + +## 💡 Tips + +1. **Always start with test certificates** - avoid limits +2. **Check configuration** - `make check-config` +3. **Monitor logs** - `make logs` +4. **Automate** - systemd/cron already configured +5. **Keep backups** of configuration + +--- + +**Version**: 2.1 +**Updated**: 27.10.2025 diff --git a/docs/en/DESCRIPTION_EN.md b/docs/en/DESCRIPTION_EN.md new file mode 100644 index 0000000..85c219e --- /dev/null +++ b/docs/en/DESCRIPTION_EN.md @@ -0,0 +1,143 @@ +# 🔒 SSL Certificate Manager for Let's Encrypt + reg.ru + +**Automated Let's Encrypt SSL certificate management with DNS validation via reg.ru API and Nginx Proxy Manager integration** + +## 📖 Description + +Comprehensive solution for automating the creation, renewal, and management of Let's Encrypt SSL certificates for domains registered with reg.ru. Supports DNS-01 validation, wildcard certificates, automatic upload to Nginx Proxy Manager, and test certificate generation for development. + +### ✨ Key Features + +- 🔐 **Automatic SSL certificate issuance** via Let's Encrypt +- 🌐 **DNS-01 validation** via reg.ru API (wildcard domain support) +- 🔄 **Automatic renewal** with configurable threshold +- 📦 **Nginx Proxy Manager integration** - automatic upload and update +- 🧪 **Test certificates** - bypass Let's Encrypt rate limits (5 per week) +- ⚙️ **Full automation** via systemd/cron +- 🔀 **Repository synchronization** - automatic Gitea → GitHub sync + +### 🚀 Quick Start + +```bash +# Install via Makefile +sudo make install + +# Configure +sudo nano /etc/letsencrypt/regru_config.json + +# Create test certificate (no rate limits) +sudo make test-cert + +# Get production certificate +sudo make obtain +``` + +### 📋 Requirements + +- **OS**: Linux (Ubuntu/Debian/CentOS) +- **Python**: 3.6+ +- **Dependencies**: certbot, requests, cryptography +- **API**: reg.ru (DNS management access) +- **Optional**: Nginx Proxy Manager + +### 🎯 Use Cases + +- ✅ SSL certificate automation for web servers +- ✅ Centralized management via Nginx Proxy Manager +- ✅ Development and testing with self-signed certificates +- ✅ CI/CD integration +- ✅ Multi-domain configurations with wildcards + +### 📚 Documentation + +#### English Documentation +- [BUILD_GUIDE_EN.md](../en/BUILD_GUIDE_EN.md) - Complete build guide +- [QUICKSTART_BUILD_EN.md](../en/QUICKSTART_BUILD_EN.md) - Quick build start +- [RELEASE_GUIDE_EN.md](../en/RELEASE_GUIDE_EN.md) - Release creation guide +- [MAKEFILE_COMMANDS_EN.md](../en/MAKEFILE_COMMANDS_EN.md) - Makefile commands reference +- [TESTING_GUIDE_EN.md](../en/TESTING_GUIDE_EN.md) - Testing guide +- [CHEATSHEET_EN.md](../en/CHEATSHEET_EN.md) - Quick reference +- [GITEA_SYNC_EN.md](../en/GITEA_SYNC_EN.md) - Gitea → GitHub sync +- [PROJECT_STRUCTURE_EN.md](../en/PROJECT_STRUCTURE_EN.md) - Project structure + +#### Russian Documentation / Русская документация +- [BUILD_GUIDE.md](../ru/BUILD_GUIDE.md) - Полное руководство по сборке +- [QUICKSTART_BUILD.md](../ru/QUICKSTART_BUILD.md) - Быстрый старт сборки +- [RELEASE_GUIDE.md](../ru/RELEASE_GUIDE.md) - Руководство по созданию релизов +- [MAKEFILE_COMMANDS.md](../ru/MAKEFILE_COMMANDS.md) - Справочник команд Makefile +- [TESTING_GUIDE.md](../ru/TESTING_GUIDE.md) - Руководство по тестированию +- [CHEATSHEET.md](../ru/CHEATSHEET.md) - Быстрая шпаргалка +- [GITEA_SYNC.md](../ru/GITEA_SYNC.md) - Синхронизация Gitea → GitHub +- [PROJECT_STRUCTURE.md](../ru/PROJECT_STRUCTURE.md) - Структура проекта + +--- + +## 🔨 Building Executables + +The project supports building standalone executables for Linux and Windows: + +```bash +# Build for current OS +make build + +# Build for all platforms +make build-all + +# Create full release +make release +``` + +**Result:** +- Linux: `letsencrypt-regru` (~45-55 MB) +- Windows: `letsencrypt-regru.exe` (~40-50 MB) + +See [BUILD_GUIDE_EN.md](../en/BUILD_GUIDE_EN.md) for details. + +--- + +## 🎯 Automated Releases + +### GitHub Actions + +Create a tag to trigger automatic build and release: + +```bash +git tag -a v1.0.0 -m "Release 1.0.0" +git push origin v1.0.0 +``` + +### Gitea Actions + +Same workflow available for self-hosted Gitea: + +```bash +git tag -a v1.0.0 -m "Release 1.0.0" +git push origin v1.0.0 +``` + +See [RELEASE_GUIDE_EN.md](../en/RELEASE_GUIDE_EN.md) for details. + +--- + +## 👤 Author + +**Dmitry Fofanov** @ 2025 + +## 📄 License + +Open Source - Free to use + +## 🤝 Contributing + +Pull requests are welcome! + +## 🔗 Links + +- **reg.ru API Documentation**: https://www.reg.ru/support/api +- **Let's Encrypt**: https://letsencrypt.org/ +- **Nginx Proxy Manager**: https://nginxproxymanager.com/ +- **PyInstaller**: https://pyinstaller.org/ + +--- + +**Last Updated:** October 28, 2025 diff --git a/docs/en/DOCS_INDEX_EN.md b/docs/en/DOCS_INDEX_EN.md new file mode 100644 index 0000000..a3dc590 --- /dev/null +++ b/docs/en/DOCS_INDEX_EN.md @@ -0,0 +1,174 @@ +# 📚 Documentation Index + +## 🇬🇧 English Documentation + +### Main Guides +- **[DESCRIPTION_EN.md](DESCRIPTION_EN.md)** - Project Description & Overview +- **[BUILD_GUIDE_EN.md](BUILD_GUIDE_EN.md)** - Complete Build Guide +- **[QUICKSTART_BUILD_EN.md](QUICKSTART_BUILD_EN.md)** - Quick Build Start (5 minutes) +- **[RELEASE_GUIDE_EN.md](RELEASE_GUIDE_EN.md)** - Automated Release Guide +- **[INSTALL_GUIDE_EN.md](INSTALL_GUIDE_EN.md)** - Installation Guide +- **[TESTING_GUIDE_EN.md](TESTING_GUIDE_EN.md)** - Testing Guide + +### Reference Materials +- **[MAKEFILE_COMMANDS_EN.md](MAKEFILE_COMMANDS_EN.md)** - Makefile Commands Reference +- **[CHEATSHEET_EN.md](CHEATSHEET_EN.md)** - Quick Reference +- **[CHANGELOG_EN.md](CHANGELOG_EN.md)** - Change History + +### Developer Guides +- **[PROJECT_STRUCTURE_EN.md](PROJECT_STRUCTURE_EN.md)** - Project Structure +- **[GITEA_SYNC_EN.md](GITEA_SYNC_EN.md)** - Gitea → GitHub Synchronization + +### SSL & Certificates +- **[SSL_SCRIPTS_README_EN.md](SSL_SCRIPTS_README_EN.md)** - SSL Scripts Documentation +- **[SSL_Certificate_Creation_and_Renewal_EN.md](SSL_Certificate_Creation_and_Renewal_EN.md)** - SSL Certificate Guide +- **[Add_Lets_Encrypt_Certificate_for_regru_Provider_EN.md](Add_Lets_Encrypt_Certificate_for_regru_Provider_EN.md)** - Let's Encrypt + reg.ru + +### Nginx Integration +- **[Nginx_Manager_SSL_Configuration_EN.md](Nginx_Manager_SSL_Configuration_EN.md)** - Nginx Manager SSL Setup + +--- + +## 🇷🇺 Russian Documentation / Русская документация + +### Основные руководства / Main Guides +- **[DESCRIPTION.md](../ru/DESCRIPTION.md)** - Описание проекта +- **[BUILD_GUIDE.md](../ru/BUILD_GUIDE.md)** - Полное руководство по сборке +- **[QUICKSTART_BUILD.md](../ru/QUICKSTART_BUILD.md)** - Быстрый старт сборки (5 минут) +- **[RELEASE_GUIDE.md](../ru/RELEASE_GUIDE.md)** - Руководство по автоматическим релизам +- **[INSTALL_GUIDE.md](../ru/INSTALL_GUIDE.md)** - Руководство по установке +- **[TESTING_GUIDE.md](../ru/TESTING_GUIDE.md)** - Руководство по тестированию + +### Справочная информация / Reference Materials +- **[MAKEFILE_COMMANDS.md](../ru/MAKEFILE_COMMANDS.md)** - Справочник команд Makefile +- **[CHEATSHEET.md](../ru/CHEATSHEET.md)** - Быстрая шпаргалка +- **[CHANGELOG.md](../ru/CHANGELOG.md)** - История изменений + +### Руководства для разработчиков / Developer Guides +- **[PROJECT_STRUCTURE.md](../ru/PROJECT_STRUCTURE.md)** - Структура проекта +- **[GITEA_SYNC.md](../ru/GITEA_SYNC.md)** - Синхронизация Gitea → GitHub + +--- + +## 🚀 Quick Start / Быстрый старт + +### For End Users / Для конечных пользователей + +**English:** +1. Start here: [DESCRIPTION_EN.md](DESCRIPTION_EN.md) +2. Install: [INSTALL_GUIDE_EN.md](INSTALL_GUIDE_EN.md) +3. Test: [TESTING_GUIDE_EN.md](TESTING_GUIDE_EN.md) +4. Quick reference: [CHEATSHEET_EN.md](CHEATSHEET_EN.md) + +**Russian / Русский:** +1. Начните здесь: [DESCRIPTION.md](../ru/DESCRIPTION.md) +2. Установка: [INSTALL_GUIDE.md](../ru/INSTALL_GUIDE.md) +3. Тестирование: [TESTING_GUIDE.md](../ru/TESTING_GUIDE.md) +4. Шпаргалка: [CHEATSHEET.md](../ru/CHEATSHEET.md) + +### For Developers / Для разработчиков + +**English:** +1. Build guide: [BUILD_GUIDE_EN.md](BUILD_GUIDE_EN.md) +2. Quick build: [QUICKSTART_BUILD_EN.md](QUICKSTART_BUILD_EN.md) +3. Create release: [RELEASE_GUIDE_EN.md](RELEASE_GUIDE_EN.md) +4. Commands: [MAKEFILE_COMMANDS_EN.md](MAKEFILE_COMMANDS_EN.md) + +**Russian / Русский:** +1. Руководство по сборке: [BUILD_GUIDE.md](../ru/BUILD_GUIDE.md) +2. Быстрая сборка: [QUICKSTART_BUILD.md](../ru/QUICKSTART_BUILD.md) +3. Создание релиза: [RELEASE_GUIDE.md](../ru/RELEASE_GUIDE.md) +4. Команды: [MAKEFILE_COMMANDS.md](../ru/MAKEFILE_COMMANDS.md) + +--- + +## 📖 Documentation by Topic / Документация по темам + +### Installation / Установка +| Topic | English | Russian | +|-------|---------|---------| +| Installation Guide | [INSTALL_GUIDE_EN.md](INSTALL_GUIDE_EN.md) | [INSTALL_GUIDE.md](../ru/INSTALL_GUIDE.md) | +| Quick Start | [DESCRIPTION_EN.md](DESCRIPTION_EN.md) | [DESCRIPTION.md](../ru/DESCRIPTION.md) | + +### Building / Сборка +| Topic | English | Russian | +|-------|---------|---------| +| Complete Build Guide | [BUILD_GUIDE_EN.md](BUILD_GUIDE_EN.md) | [BUILD_GUIDE.md](../ru/BUILD_GUIDE.md) | +| Quick Build (5 min) | [QUICKSTART_BUILD_EN.md](QUICKSTART_BUILD_EN.md) | [QUICKSTART_BUILD.md](../ru/QUICKSTART_BUILD.md) | +| Makefile Commands | [MAKEFILE_COMMANDS_EN.md](MAKEFILE_COMMANDS_EN.md) | [MAKEFILE_COMMANDS.md](../ru/MAKEFILE_COMMANDS.md) | + +### Releases / Релизы +| Topic | English | Russian | +|-------|---------|---------| +| Automated Releases | [RELEASE_GUIDE_EN.md](RELEASE_GUIDE_EN.md) | [RELEASE_GUIDE.md](../ru/RELEASE_GUIDE.md) | +| Changelog | [CHANGELOG_EN.md](CHANGELOG_EN.md) | [CHANGELOG.md](../ru/CHANGELOG.md) | + +### Testing / Тестирование +| Topic | English | Russian | +|-------|---------|---------| +| Testing Guide | [TESTING_GUIDE_EN.md](TESTING_GUIDE_EN.md) | [TESTING_GUIDE.md](../ru/TESTING_GUIDE.md) | + +### Reference / Справка +| Topic | English | Russian | +|-------|---------|---------| +| Quick Reference | [CHEATSHEET_EN.md](CHEATSHEET_EN.md) | [CHEATSHEET.md](../ru/CHEATSHEET.md) | +| Project Structure | [PROJECT_STRUCTURE_EN.md](PROJECT_STRUCTURE_EN.md) | [PROJECT_STRUCTURE.md](../ru/PROJECT_STRUCTURE.md) | + +--- + +## 📊 Documentation Status / Статус документации + +| Document | English | Russian | Status | +|----------|---------|---------|--------| +| Description | ✅ | ✅ | Complete | +| Build Guide | ✅ | ✅ | Complete | +| Quick Build | ✅ | ✅ | Complete | +| Release Guide | ✅ | ✅ | Complete | +| Install Guide | ✅ | ✅ | Complete | +| Makefile Commands | ✅ | ✅ | Complete | +| Testing Guide | ✅ | ✅ | Complete | +| Cheatsheet | ✅ | ✅ | Complete | +| Project Structure | ✅ | ✅ | Complete | +| Gitea Sync | ✅ | ✅ | Complete | +| Changelog | ✅ | ✅ | Complete | + +**Legend:** +- ✅ Complete / Готово +- 🔄 In Progress / В разработке +- ❌ Not Started / Не начато + +--- + +## 🎯 Choose Your Language / Выберите язык + +### 🇬🇧 Prefer English? +👉 Start with [DESCRIPTION_EN.md](DESCRIPTION_EN.md) + +### 🇷🇺 Предпочитаете русский? +👉 Начните с [DESCRIPTION.md](../ru/DESCRIPTION.md) + +--- + +## 💡 Contributing / Вклад + +Help improve documentation / Помогите улучшить документацию: +- Report issues / Сообщайте об ошибках +- Suggest improvements / Предлагайте улучшения +- Fix typos / Исправляйте опечатки +- Translate / Переводите + +--- + +## 🔗 External Resources / Внешние ресурсы + +- **reg.ru API**: https://www.reg.ru/support/api +- **Let's Encrypt**: https://letsencrypt.org/ +- **Nginx Proxy Manager**: https://nginxproxymanager.com/ +- **PyInstaller**: https://pyinstaller.org/ +- **GitHub Actions**: https://docs.github.com/actions +- **Gitea Actions**: https://docs.gitea.com/usage/actions/overview + +--- + +**Last Updated / Обновлено**: October 28, 2025 +**Maintained by / Поддерживает**: Dmitry Fofanov diff --git a/docs/en/GITEA_SYNC_EN.md b/docs/en/GITEA_SYNC_EN.md new file mode 100644 index 0000000..8cfb4df --- /dev/null +++ b/docs/en/GITEA_SYNC_EN.md @@ -0,0 +1,438 @@ +# 🔄 Gitea → GitHub Synchronization + +Automatic repository synchronization from Gitea to GitHub after each push. + +--- + +## 📋 Available Methods + +| Method | Complexity | Speed | Reliability | Recommendation | +|--------|------------|-------|-------------|----------------| +| **1. Git Hooks** | ⭐⭐ | ⚡ Instant | ✅ High | Recommended | +| **2. GitHub Actions** | ⭐⭐⭐ | ⏱️ 1-5 min | ✅ High | Complex scenarios | +| **3. Gitea Mirror** | ⭐ | ⏱️ Scheduled | ⭐⭐ Medium | Simplest | +| **4. Double Remote** | ⭐ | ⚡ Instant | ⭐⭐ Medium | Local work | + +--- + +## 🚀 Method 1: Git Hooks (Recommended) + +### Installation + +**1. On Gitea server, find repository path:** +```bash +# Usually: +/var/lib/gitea/data/gitea-repositories/username/configure_nginx_manager.git +# Or +/home/git/gitea-repositories/username/configure_nginx_manager.git +``` + +**2. Create post-receive hook:** +```bash +cd /path/to/gitea/repos/username/configure_nginx_manager.git/hooks/ +nano post-receive +``` + +**3. Insert content** from `gitea-hooks/post-receive` file (in this repository) + +**4. Configure parameters:** +```bash +# In post-receive file, change: +GITHUB_REPO="git@github.com:YOUR_USERNAME/configure_nginx_manager.git" +# Or for HTTPS with token: +GITHUB_REPO="https://YOUR_TOKEN@github.com/YOUR_USERNAME/configure_nginx_manager.git" +``` + +**5. Make script executable:** +```bash +chmod +x post-receive +``` + +**6. Create log directory:** +```bash +mkdir -p /var/log/gitea +chown git:git /var/log/gitea +``` + +### SSH Key Setup (for git@github.com) + +**On Gitea server:** + +**Step 1: Identify Gitea user** +```bash +# Check which user runs Gitea +ps aux | grep gitea | grep -v grep + +# Usually one of: +# - git (standard installation) +# - gitea (Docker/LXC installation) +``` + +**Step 2: Switch to that user** +```bash +# Try git: +sudo su - git + +# If that doesn't work, try gitea: +sudo su - gitea + +# Verify current user +whoami # Should be: git or gitea +``` + +**Step 3: Create SSH key** +```bash +# Create SSH key (if not exists) +ssh-keygen -t ed25519 -C "gitea-to-github-sync" -f ~/.ssh/id_ed25519 -N "" + +# Copy public key +cat ~/.ssh/id_ed25519.pub +``` + +**On GitHub:** +1. Settings → SSH and GPG keys +2. New SSH key +3. Paste public key +4. Save + +**⚠️ IMPORTANT: Add GitHub to known_hosts:** +```bash +# From the same user (git or gitea) +ssh-keyscan -H github.com >> ~/.ssh/known_hosts + +# Verify key was added +cat ~/.ssh/known_hosts | grep github.com +``` + +**Verify connection:** +```bash +ssh -T git@github.com +# Should output: Hi username! You've successfully authenticated... +``` + +### Token Setup (for HTTPS) + +**On GitHub:** +1. Settings → Developer settings → Personal access tokens → Tokens (classic) +2. Generate new token +3. Select scope: `repo` (full repository access) +4. Copy token + +**In hook file:** +```bash +GITHUB_REPO="https://ghp_YOUR_TOKEN_HERE@github.com/username/configure_nginx_manager.git" +``` + +### Testing + +```bash +# Make test commit in Gitea +cd /tmp +git clone http://gitea.example.com/username/configure_nginx_manager.git +cd configure_nginx_manager +echo "test" >> README.md +git add README.md +git commit -m "Test sync to GitHub" +git push + +# Check log +tail -f /var/log/gitea/github-sync.log + +# Check GitHub - changes should appear +``` + +--- + +## 🔄 Method 2: GitHub Actions + +### Installation + +**1. Create workflow in GitHub repository:** + +File already created: `.github/workflows/sync-from-gitea.yml` + +**2. Configure secrets in GitHub:** + +GitHub Repository → Settings → Secrets and variables → Actions → New repository secret + +Add: +- **Name**: `GITEA_URL` + - **Value**: `https://gitea.example.com/username/configure_nginx_manager.git` + +- **Name**: `GITEA_TOKEN` + - **Value**: Gitea access token + +### Getting Gitea Token + +**In Gitea:** +1. Settings → Applications → Generate New Token +2. Token Name: "GitHub Sync" +3. Select permissions: `read:repository` +4. Generate Token +5. Copy token + +### Running Sync + +**Automatically (scheduled):** +- Checks for changes every hour + +**Manually:** +1. GitHub → Actions +2. Select workflow "Sync from Gitea" +3. Run workflow + +**Via Gitea webhook:** + +In Gitea repository: +1. Settings → Webhooks → Add Webhook → Gitea +2. Target URL: `https://api.github.com/repos/USERNAME/configure_nginx_manager/dispatches` +3. HTTP Method: `POST` +4. POST Content Type: `application/json` +5. Trigger On: `Push events` +6. Body: +```json +{ + "event_type": "gitea-push" +} +``` + +--- + +## 🪞 Method 3: Gitea Mirror (Built-in) + +### Setup + +**In Gitea repository:** +1. Settings → Repository +2. Scroll to "Mirror Settings" +3. Click "Add Push Mirror" +4. Fill in: + - **Git Remote Repository URL**: `https://github.com/username/configure_nginx_manager.git` + - **Username**: your GitHub username + - **Password**: GitHub Personal Access Token + - **Sync Interval**: `8h` (every 8 hours) or `0` (manual only) +5. Save + +### Manual Sync + +Settings → Repository → Mirror Settings → Sync Now + +### Advantages +- ✅ Built-in feature +- ✅ No scripts required +- ✅ Web interface management + +### Disadvantages +- ⚠️ Works on schedule (not instant) +- ⚠️ Not available in all Gitea versions + +--- + +## 🔀 Method 4: Double Remote + +### For Local Work + +**Setup:** +```bash +# In your local repository +cd configure_nginx_manager + +# Add GitHub as second remote +git remote add github git@github.com:username/configure_nginx_manager.git + +# Or configure push to both repositories simultaneously +git remote set-url --add --push origin git@github.com:username/configure_nginx_manager.git + +# Verify +git remote -v +``` + +**Usage:** +```bash +# Normal push (Gitea only) +git push origin main + +# Push to GitHub +git push github main + +# Push to both repositories +git push origin main +git push github main + +# Or create alias +git config alias.pushall '!git push origin main && git push github main' +git pushall +``` + +--- + +## 🔍 Sync Verification + +### Check via Git + +```bash +# Compare commits +git ls-remote git@gitea.example.com:username/configure_nginx_manager.git +git ls-remote git@github.com:username/configure_nginx_manager.git + +# Should have identical SHA +``` + +### Check Logs (Method 1 - Hooks) + +```bash +# On Gitea server +tail -f /var/log/gitea/github-sync.log +``` + +### Check GitHub Actions (Method 2) + +1. GitHub Repository → Actions +2. View recent runs +3. Check execution logs + +--- + +## ⚙️ Recommended Configuration + +For maximum reliability, use **combination of methods**: + +1. **Git Hook** (primary) - instant sync +2. **GitHub Actions** (backup) - hourly check in case of hook failure + +### Installing Both Methods + +```bash +# 1. Install Git Hook on Gitea server +# (see Method 1) + +# 2. Configure GitHub Actions +# (see Method 2) + +# 3. GitHub Actions will catch missed changes +``` + +--- + +## 🐛 Troubleshooting + +### Problem: Hook not firing + +**Check:** +```bash +# On Gitea server +ls -la /path/to/repo.git/hooks/post-receive +# Should be -rwxr-xr-x + +# Check permissions +chmod +x /path/to/repo.git/hooks/post-receive +chown git:git /path/to/repo.git/hooks/post-receive + +# Check Gitea error log +tail -f /var/log/gitea/gitea.log +``` + +### Problem: Permission denied (SSH) + +**Solution:** +```bash +# Ensure SSH key is added to GitHub +ssh -T git@github.com + +# Check .ssh permissions +chmod 700 ~/.ssh +chmod 600 ~/.ssh/id_ed25519 +``` + +### Problem: Authentication failed (HTTPS) + +**Solution:** +- Check GitHub token (should have `repo` scope) +- Token not expired +- Correct URL format: `https://TOKEN@github.com/user/repo.git` + +### Problem: GitHub Actions not triggering + +**Solution:** +1. Check secrets in Settings → Secrets +2. Verify webhook format from Gitea +3. Run manually for test + +--- + +## 📊 Method Comparison + +### Sync Speed +- **Git Hooks**: ⚡ < 1 second +- **GitHub Actions (webhook)**: ⏱️ 10-30 seconds +- **GitHub Actions (schedule)**: ⏱️ up to 1 hour +- **Gitea Mirror**: ⏱️ scheduled + +### Reliability +- **Git Hooks**: ⭐⭐⭐⭐⭐ (when properly configured) +- **GitHub Actions**: ⭐⭐⭐⭐⭐ (very reliable) +- **Gitea Mirror**: ⭐⭐⭐ (depends on Gitea version) +- **Double Remote**: ⭐⭐ (requires manual action) + +--- + +## 🎯 Final Recommendation + +For `configure_nginx_manager` project: + +**1. Primary method: Git Hook** +- Fast +- Reliable +- Automatic + +**2. Backup method: GitHub Actions** +- Hourly check +- Catches missed changes +- Can run manually + +**3. Monitoring:** +```bash +# Weekly verification +git ls-remote origin | head -1 +git ls-remote github | head -1 +# SHA should match +``` + +--- + +## 📝 Quick Setup + +```bash +# On Gitea server +sudo su - git +cd /path/to/gitea-repositories/username/configure_nginx_manager.git/hooks/ + +# Download hook +wget https://raw.githubusercontent.com/username/configure_nginx_manager/main/gitea-hooks/post-receive + +# Configure +nano post-receive +# Change GITHUB_REPO + +# Permissions +chmod +x post-receive + +# Test +echo "test" | ./post-receive +``` + +Done! 🎉 + +--- + +## 📚 Additional Resources + +- [Git Hooks Documentation](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks) +- [GitHub Actions Documentation](https://docs.github.com/en/actions) +- [Gitea Documentation](https://docs.gitea.io/) + +--- + +**Version**: 1.0 +**Author**: Фофанов Дмитрий +**Date**: October 27, 2025 diff --git a/docs/en/INSTALL_GUIDE_EN.md b/docs/en/INSTALL_GUIDE_EN.md new file mode 100644 index 0000000..688ed3e --- /dev/null +++ b/docs/en/INSTALL_GUIDE_EN.md @@ -0,0 +1,415 @@ +# Installation Guide for letsencrypt_regru.sh + +**Author:** Dmitry Fofanov +**Date:** October 28, 2025 + +## Description + +`letsencrypt_regru.sh` is an automated installer for Let's Encrypt Manager with reg.ru and Nginx Proxy Manager integration. + +The script automates: +- Installation of all system dependencies +- Python virtual environment creation +- Python library installation (requests, cryptography, certbot) +- Interactive configuration setup +- Creating and configuring systemd services +- Automatic certificate renewal setup + +## Requirements + +- Linux (Debian/Ubuntu, CentOS/RHEL/Fedora) +- Root access (sudo) +- Minimum 512MB RAM +- Minimum 1GB free disk space +- Internet connection + +## Quick Installation + +**Method 1: Automatic Installation (Recommended)** + +The fastest way - run installation directly from GitHub: + +```bash +sudo bash -c "$(curl -fsSL https://github.com/DFofanov/configure_nginx_manager/raw/refs/heads/master/letsencrypt_regru.sh)" +``` + +This command will: +- Automatically download the installation script +- Run it with root privileges +- Guide you through interactive setup + +**Method 2: Clone Repository** + +If you want to review the code before installation: + +```bash +# 1. Download repository +git clone https://github.com/DFofanov/configure_nginx_manager.git +cd configure_nginx_manager + +# 2. Make executable +chmod +x letsencrypt_regru.sh + +# 3. Run installation +sudo ./letsencrypt_regru.sh +``` + +## Interactive Setup + +During installation, the script will ask for: + +1. **Domain** - your main domain (e.g., `example.com`) +2. **Email** - for Let's Encrypt notifications +3. **reg.ru credentials:** + - Username + - Password +4. **Wildcard certificate** - create `*.example.com` (recommended: Yes) +5. **NPM integration** (optional): + - NPM address (e.g., `http://10.10.10.14:81`) + - NPM login email + - NPM password + +## Structure After Installation + +``` +/opt/letsencrypt-regru/ # Application +├── letsencrypt_regru_api.py # Main script +├── venv/ # Python virtual environment +└── docs/ # Documentation + +/etc/letsencrypt-regru/ # Configuration +└── config.json # Settings (credentials, domain, NPM) + +/var/log/letsencrypt-regru/ # Logs +└── letsencrypt_regru.log + +/etc/letsencrypt/live/ # Let's Encrypt certificates +└── example.com/ + ├── privkey.pem + ├── cert.pem + ├── chain.pem + └── fullchain.pem + +/etc/systemd/system/ # Systemd services +├── letsencrypt-regru.service # Renewal service +└── letsencrypt-regru.timer # Timer (every 12 hours) + +/usr/local/bin/ +└── letsencrypt-regru # Global command +``` + +## Using letsencrypt-regru Command + +After installation, a convenient global command with multiple functions is available: + +### 🔧 Main Commands + +```bash +# Check current certificate expiration +letsencrypt-regru --check + +# Obtain new Let's Encrypt certificate +letsencrypt-regru --obtain + +# Renew existing certificate +letsencrypt-regru --renew + +# Automatically check and renew if needed +letsencrypt-regru --auto + +# Create test self-signed certificate +letsencrypt-regru --test-cert +``` + +### 🧪 Diagnostic and Testing Commands + +```bash +# Check API access to reg.ru +# - Shows current IP address +# - Tests API connection +# - Displays account balance +letsencrypt-regru --test-api + +# Test DNS TXT record creation +# - Full SSL certification process simulation +# - Creates temporary _acme-challenge TXT record +# - Waits for DNS propagation (60 seconds) +# - Verifies via public DNS servers +# - Automatically removes test record +letsencrypt-regru --test-dns + +# Show help for all commands +letsencrypt-regru --help + +# Enable verbose output +letsencrypt-regru --obtain -v +letsencrypt-regru --check -v +``` + +### ⚙️ Service Commands (internal use) + +```bash +# Certbot authentication hook (used by certbot automatically) +letsencrypt-regru --auth-hook + +# Certbot cleanup hook (used by certbot automatically) +letsencrypt-regru --cleanup-hook +``` + +### 📋 Command Reference + +| Command | Description | Use Case | +|---------|-------------|----------| +| `--check` | Check certificate expiration | Regular monitoring | +| `--obtain` | Obtain new certificate from Let's Encrypt | Initial creation | +| `--renew` | Renew existing certificate | Renewal | +| `--auto` | Automatic check and renewal | For cron/systemd | +| `--test-cert` | Create test self-signed certificate | Development/testing | +| `--test-api` | Check API access to reg.ru | Connection diagnostics | +| `--test-dns` | Test DNS record creation | Pre-SSL verification | +| `--auth-hook` | Certbot hook (DNS creation) | Internal | +| `--cleanup-hook` | Certbot hook (DNS deletion) | Internal | +| `--help` | Show help | Help | +| `-v` | Verbose output | Debugging | + +## Automatic Renewal + +The installer configures a systemd timer for automatic checks: + +```bash +# Check timer status +systemctl status letsencrypt-regru.timer + +# When is next run +systemctl list-timers letsencrypt-regru.timer + +# View run history +journalctl -u letsencrypt-regru + +# Follow logs in real-time +journalctl -u letsencrypt-regru -f +``` + +### Timer Settings + +Default settings: +- First run: 15 minutes after system boot +- Frequency: every 12 hours +- Random delay: up to 1 hour (to avoid creating load) + +Can be modified in `/etc/systemd/system/letsencrypt-regru.timer`. + +## Editing Configuration + +```bash +# Open configuration in editor +sudo nano /etc/letsencrypt-regru/config.json + +# After changes, restart timer +sudo systemctl restart letsencrypt-regru.timer +``` + +### Example config.json + +```json +{ + "regru_username": "your_username", + "regru_password": "your_password", + "domain": "example.com", + "wildcard": true, + "email": "admin@example.com", + "cert_dir": "/etc/letsencrypt/live", + "log_file": "/var/log/letsencrypt-regru/letsencrypt_regru.log", + "dns_propagation_wait": 60, + "dns_check_attempts": 10, + "dns_check_interval": 10, + "renewal_days": 30, + "npm_enabled": true, + "npm_host": "http://10.10.10.14:81", + "npm_email": "admin@npm.local", + "npm_password": "secure_password" +} +``` + +## Updating Application + +```bash +# Download latest version +cd configure_nginx_manager +git pull + +# Run update +sudo ./letsencrypt_regru.sh update +``` + +Update will: +- Stop timer +- Update script +- Update Python dependencies +- Restart timer + +## Uninstallation + +```bash +# Complete application removal +sudo ./letsencrypt_regru.sh uninstall +``` + +Script will remove: +- Application from `/opt/letsencrypt-regru/` +- Systemd services +- Global command + +Certificates in `/etc/letsencrypt/live/` are preserved! + +Optionally you can remove: +- Configuration `/etc/letsencrypt-regru/` +- Logs `/var/log/letsencrypt-regru/` + +## Viewing Logs + +```bash +# Systemd logs (recommended) +journalctl -u letsencrypt-regru -f + +# Log file +tail -f /var/log/letsencrypt-regru/letsencrypt_regru.log + +# Last 100 lines +tail -n 100 /var/log/letsencrypt-regru/letsencrypt_regru.log +``` + +## Troubleshooting + +### Installation Check + +```bash +# Check command availability +which letsencrypt-regru + +# Check Python environment +ls -la /opt/letsencrypt-regru/venv/ + +# Check systemd services +systemctl list-unit-files | grep letsencrypt-regru +``` + +### Installation Errors + +**Error: "Permission denied"** +```bash +# Run with sudo +sudo ./letsencrypt_regru.sh +``` + +**Error: "Package not found"** +```bash +# Update package lists +sudo apt-get update # Debian/Ubuntu +sudo yum update # CentOS/RHEL +``` + +**Error: "Python module not found"** +```bash +# Reinstall virtual environment +sudo rm -rf /opt/letsencrypt-regru/venv +sudo ./letsencrypt_regru.sh +``` + +### Certificate Issues + +**Certificate not created** +```bash +# Check logs +tail -n 50 /var/log/letsencrypt-regru/letsencrypt_regru.log + +# Check configuration +cat /etc/letsencrypt-regru/config.json + +# Try manually +letsencrypt-regru --obtain -v +``` + +**DNS not updating** +```bash +# Increase wait time in config.json +"dns_propagation_wait": 120, +"dns_check_attempts": 20 +``` + +### NPM Issues + +**Not uploading to NPM** +```bash +# Check NPM availability +curl http://192.168.10.14:81 + +# Check credentials in config.json +# Try manually +letsencrypt-regru --test-cert -v +``` + +## Supported OS + +✅ Debian 10, 11, 12 +✅ Ubuntu 20.04, 22.04, 24.04 +✅ CentOS 7, 8 +✅ RHEL 7, 8, 9 +✅ Fedora 35+ + +## Additional Features + +### Test Certificate + +For testing without Let's Encrypt rate limits: + +```bash +letsencrypt-regru --test-cert +``` + +Creates self-signed certificate valid for 90 days. + +### Manual Renewal Run + +```bash +# Start service manually +sudo systemctl start letsencrypt-regru.service + +# Check status +systemctl status letsencrypt-regru.service +``` + +### Change Check Frequency + +Edit `/etc/systemd/system/letsencrypt-regru.timer`: + +```ini +[Timer] +# Every 6 hours instead of 12 +OnUnitActiveSec=6h +``` + +Then: +```bash +sudo systemctl daemon-reload +sudo systemctl restart letsencrypt-regru.timer +``` + +## Security + +- Configuration with passwords has `600` permissions (root only) +- Certificate private keys have `600` permissions +- All operations run as root +- Logs accessible only to root + +## Support + +- GitHub Issues: https://github.com/DFofanov/configure_nginx_manager/issues +- Documentation: `/opt/letsencrypt-regru/docs/` +- Email: admin@dfv24.com + +--- + +**Developed by:** Dmitry Fofanov +**Date:** October 28, 2025 +**Version:** 2.0 diff --git a/docs/en/MAKEFILE_COMMANDS_EN.md b/docs/en/MAKEFILE_COMMANDS_EN.md new file mode 100644 index 0000000..7b019a1 --- /dev/null +++ b/docs/en/MAKEFILE_COMMANDS_EN.md @@ -0,0 +1,159 @@ +# Makefile Commands - Quick Reference + +## 📋 Command Categories + +### 🛠️ Installation and Deployment + +```bash +make install # Full application installation +make uninstall # Remove application +make status # Check installation status +make check-config # Verify configuration +``` + +### 🔨 Building Executables + +```bash +make build # Build for current OS +make build-linux # Build for Linux +make build-windows # Build for Windows +make build-all # Build for all platforms +``` + +### 📦 Creating Packages + +```bash +make package-linux # Create tar.gz for Linux +make package-windows # Create zip for Windows +make release # Full release cycle +``` + +### 🧪 Testing + +```bash +make test-run # Test script run +make test-cert # Create test certificate +make test-build # Test built file +``` + +### 🚀 Running Operations + +```bash +make run # Automatic check and renewal +make obtain # Obtain new certificate +make renew # Renew existing certificate +``` + +### 📊 Monitoring + +```bash +make logs # Show logs +make status # Service status +``` + +### 🧹 Cleanup + +```bash +make clean # Clean Python temporary files +make clean-build # Clean build artifacts +``` + +### ℹ️ Information + +```bash +make help # Show help +make build-info # Build environment information +``` + +--- + +## 🎯 Common Scenarios + +### Initial Installation +```bash +sudo make install +sudo make check-config +sudo make test-run +``` + +### Building Release for GitHub +```bash +make clean-build +make release +# Files will be in dist/ +``` + +### Creating Test Environment +```bash +sudo make install +sudo make test-cert +sudo make status +``` + +### Manual Certificate Renewal +```bash +sudo make run +sudo make logs +``` + +### Removing Application +```bash +sudo make uninstall +``` + +--- + +## 📝 Environment Variables + +Main variables defined in Makefile: + +```makefile +INSTALL_DIR = /opt/letsencrypt-regru +CONFIG_FILE = /etc/letsencrypt/regru_config.json +LOG_FILE = /var/log/letsencrypt_regru.log +SERVICE_NAME = letsencrypt-regru +PYTHON = python3 +``` + +--- + +## 🔐 Required Permissions + +**Require sudo:** +- `make install` +- `make uninstall` +- `make run` +- `make obtain` +- `make renew` +- `make test-run` +- `make test-cert` + +**Don't require sudo:** +- `make build*` +- `make package*` +- `make clean*` +- `make help` +- `make build-info` + +--- + +## 💡 Useful Combinations + +```bash +# Full reinstallation +sudo make uninstall && sudo make install + +# Build and test +make build && make test-build + +# Clean and release +make clean-build && make release + +# Post-installation check +sudo make status && sudo make test-run && sudo make logs +``` + +--- + +**Author:** Dmitry Fofanov +**Last Updated:** October 28, 2025 diff --git a/docs/en/Nginx_Manager_SSL_Configuration_EN.md b/docs/en/Nginx_Manager_SSL_Configuration_EN.md new file mode 100644 index 0000000..e15b3d7 --- /dev/null +++ b/docs/en/Nginx_Manager_SSL_Configuration_EN.md @@ -0,0 +1,79 @@ +# Detailed Guide to Configuring Nginx Proxy Manager with One Global SSL Certificate for All dfv24.com Domains + +## Prerequisites +- [Nginx Proxy Manager](http://192.168.10.14:81/) is installed and running +- Main domain: dfv24.com +- Domain hosting and DNS records are on reg.ru +- Need to use one SSL certificate (e.g., wildcard) for all dfv24.com subdomains + +--- + +## Step 1. Purchasing and Obtaining SSL Wildcard Certificate for dfv24.com +1. On reg.ru or any other Certificate Authority (CA), order wildcard certificate for domain `*.dfv24.com`. +2. Obtain certificate files: + - Main certificate (CRT) + - Intermediate certificates (CA Bundle) + - Private key (KEY) + +--- + +## Step 2. Importing Your SSL Certificate to Nginx Proxy Manager +1. Log in to Nginx Proxy Manager at http://192.168.10.14:81/ +2. Go to **SSL Certificates** section → **Add SSL Certificate** button +3. Select **Custom** (custom certificate) +4. Paste into fields: + - **Certificate** — main CRT + CA Bundle (if CA Bundle is separate, concatenate into one file or paste sequentially) + - **Key** — private key content + - Name certificate, e.g., `dfv24_wildcard` +5. Save + +--- + +## Step 3. Configuring Proxy Hosts Using Global Certificate + +1. Go to **Proxy Hosts** → **Add Proxy Host** +2. Fill in fields: + - **Domain Names**: For example, `sub1.dfv24.com` (for first subdomain) + - **Scheme**: http or https, depending on backend + - **Forward Hostname / IP**: IP or DNS address of your internal service + - **Forward Port**: service port (e.g., 80 or 443) +3. Enable **SSL** → Check **Use a shared SSL certificate** (if such option is available) or select previously imported certificate from list +4. Activate: **Block Common Exploits**, **Websockets Support**, set Redirect HTTP to HTTPS if required +5. Save proxy host + +6. Repeat for all subdomains, specifying needed domains and selecting same wildcard SSL certificate + +--- + +## Step 4. Configuring DNS Records on reg.ru + +1. Log in to domain management panel on reg.ru +2. Create or edit DNS A records: + - `dfv24.com` → IP of your Nginx Proxy Manager (e.g., 192.168.10.14) + - `*.dfv24.com` → same IP or specific subdomains if there are special ones +3. Save changes +4. Wait for DNS update (from few minutes to 24 hours) + +--- + +## Step 5. Testing and Verification + +1. In browser, open any subdomain `https://sub1.dfv24.com` +2. Certificate should be valid, issued for wildcard `*.dfv24.com` +3. Check proxy functionality and correct certificate assignment +4. If necessary, check Nginx Proxy Manager logs and fix errors + +--- + +## Additional Information + +- If Nginx Proxy Manager doesn't have GUI option to select shared certificate, you can manually configure configs through `/data/nginx/proxy_host` directory and specify SSL certificate for all hosts. +- When updating certificate — re-import it to Nginx Proxy Manager. +- You can use Let's Encrypt for automatic wildcard certificate obtaining using DNS validation (if supported by your DNS provider). + +--- + +# Summary + +Use one wildcard certificate for all subdomains, import it as custom certificate in Nginx Proxy Manager, when creating proxy hosts select it in SSL settings. Manage DNS records on reg.ru, directing domain to Nginx Proxy Manager IP. +This allows legitimate use of single certificate for all services with different subdomains under your dfv24.com domain. diff --git a/docs/en/PROJECT_STRUCTURE_EN.md b/docs/en/PROJECT_STRUCTURE_EN.md new file mode 100644 index 0000000..046b4e7 --- /dev/null +++ b/docs/en/PROJECT_STRUCTURE_EN.md @@ -0,0 +1,287 @@ +# 📁 configure_nginx_manager Project Structure + +## Main Scripts + +### Python (Recommended) +- **letsencrypt_regru_api.py** (1,411 lines) + - Full-featured Python script + - Direct reg.ru API integration + - Nginx Proxy Manager integration + - Automatic certificate check and renewal + - Test self-signed certificate generation + - Wildcard domain support + +### Bash +- **letsencrypt_regru_dns.sh** + - Bash script with certbot-dns-regru plugin + - Easy to use + - Minimal dependencies + +### PowerShell +- **letsencrypt_regru.ps1** + - Windows version + - Similar to Bash script + +### Testing +- **test_certificate.sh** + - Quick test certificate creation via OpenSSL + - Standalone operation without Python + - Wildcard domain support + +## Automation + +### Makefile +- **Makefile** (415 lines) + - `make install` - Complete installation and setup + - `make uninstall` - Clean removal + - `make status` - Check status + - `make test-cert` - Create test certificate + - `make obtain` - Get Let's Encrypt certificate + - `make renew` - Renew certificate + - `make logs` - View logs + - `make check-config` - Validate configuration + +## Configuration + +### config.json.example +Example configuration with all parameters: +- reg.ru API credentials +- Domain and email settings +- Renewal parameters (renewal_days) +- Nginx Proxy Manager settings +- Directory and log paths + +## Documentation + +### README.md (1,420+ lines) +Main documentation: +- Introduction and features +- Quick start +- Makefile installation +- Test certificate creation +- Requirements and dependencies +- Configuration and usage +- NPM integration +- Automatic check and renewal +- Automation via cron/systemd +- Troubleshooting + +### README_EN.md (English version) +Complete English translation of main guide + +### TESTING_GUIDE.md (370+ lines) +Testing guide: +- Why test certificates are needed +- Bypass Let's Encrypt limits (5 per week) +- Quick start with test certificates +- Method comparison +- Development usage +- Test automation +- Transition from test to production +- FAQ +- CI/CD and Docker examples + +### TESTING_GUIDE_EN.md (English version) +Complete English translation of testing guide + +### GITEA_SYNC.md +Gitea → GitHub synchronization: +- 4 sync methods (Git Hooks, GitHub Actions, Gitea Mirror, Double Remote) +- Step-by-step installation +- SSH and token setup +- Webhook integration +- Troubleshooting +- Method comparison + +### GITEA_SYNC_EN.md (English version) +Complete English translation of sync guide + +### CHEATSHEET.md +Quick reference: +- Main commands +- Development workflow +- Use case scenarios +- Common errors and solutions +- Checking and debugging + +### CHEATSHEET_EN.md (English version) +Complete English translation of cheatsheet + +### PROJECT_STRUCTURE.md (this file) +- All project files description +- Component overview + +### PROJECT_STRUCTURE_EN.md (English version) +Complete English translation of structure + +### DESCRIPTION.md +Project description: +- Russian description +- English description +- Quick start +- Features overview + +### CHANGELOG.md +Change history: +- Versions and updates +- New features +- Bug fixes +- Roadmap + +### CHANGELOG_EN.md (English version) +Complete English translation of changelog + +## Git Integration + +### .github/workflows/sync-from-gitea.yml +GitHub Actions for synchronization: +- Automatic check every hour +- Webhook trigger from Gitea +- Manual run +- Merge changes from Gitea +- Push to GitHub + +### gitea-hooks/ +Git hooks for Gitea server: + +**post-receive** +- Automatic push to GitHub after commit +- Instant sync (< 1 second) +- Operation logging +- Tag synchronization +- SSH and HTTPS support + +**README.md** +- Hook installation instructions +- Authentication setup +- Troubleshooting + +**README_EN.md** (English version) +Complete English translation + +## Additional Files + +### Markdown Documents +- **Add Let's Encrypt Certificate для провайдера reg.ru.md** + - Initial instructions (Russian) + +- **Создание и продление SSL сертификата.md** + - Additional process information (Russian) + +## Features + +### ✅ Core Features +- [x] Let's Encrypt certificates via reg.ru DNS API +- [x] Wildcard certificates (*.domain.com) +- [x] Automatic certificate renewal +- [x] DNS-01 validation +- [x] Nginx Proxy Manager integration +- [x] Automatic upload/update to NPM + +### ✅ Advanced Features +- [x] Automatic expiration check +- [x] Configurable renewal threshold (renewal_days) +- [x] Systemd service + timer +- [x] Cron automation +- [x] Detailed logging +- [x] Configuration validation + +### 🆕 Testing +- [x] Self-signed test certificate generation +- [x] Bypass Let's Encrypt limits (5/week) +- [x] Instant creation without DNS +- [x] Test certificate NPM integration +- [x] Full structure compatibility with Let's Encrypt + +### 🔄 Repository Sync +- [x] Automatic Gitea → GitHub sync +- [x] Git Hooks (instant sync) +- [x] GitHub Actions (hourly check) +- [x] Webhook integration +- [x] SSH and HTTPS authentication + +## Installation + +### Quick Install +```bash +sudo make install +sudo nano /etc/letsencrypt/regru_config.json +sudo make test-cert # For testing +sudo make obtain # For production +``` + +### Post-Install Structure +``` +/opt/letsencrypt-regru/ +├── letsencrypt_regru_api.py + +/etc/letsencrypt/ +├── regru_config.json +└── live/ + └── example.com/ + ├── privkey.pem + ├── cert.pem + ├── fullchain.pem + └── chain.pem + +/etc/systemd/system/ +├── letsencrypt-regru.service +└── letsencrypt-regru.timer + +/var/log/letsencrypt/ +└── letsencrypt_regru.log +``` + +## Usage + +### Testing (no limits) +```bash +sudo make test-cert # Create test certificate +sudo make status # Check status +``` + +### Production +```bash +sudo make obtain # Get Let's Encrypt certificate +sudo make renew # Renew certificate +sudo make run # Automatic mode +``` + +### Monitoring +```bash +sudo make logs # View logs +sudo make status # Service status +sudo make check-config # Check configuration +``` + +## Technologies + +- **Python 3.6+** - Main language +- **Certbot** - Let's Encrypt client +- **requests** - HTTP API requests +- **cryptography** - Test certificate generation +- **systemd** - Launch automation +- **cron** - Alternative automation +- **Make** - Installation management +- **OpenSSL** - Alternative certificate generation + +## License + +Open Source - Free to use + +## Author + +Фофанов Дмитрий @ 2025 + +## Support + +See documentation: +- [README.md](README.md) / [README_EN.md](README_EN.md) - Main guide +- [TESTING_GUIDE.md](TESTING_GUIDE.md) / [TESTING_GUIDE_EN.md](TESTING_GUIDE_EN.md) - Testing guide +- [GITEA_SYNC.md](GITEA_SYNC.md) / [GITEA_SYNC_EN.md](GITEA_SYNC_EN.md) - Repository sync + +--- + +**Version**: 2.1 +**Date**: October 27, 2025 +**Status**: ✅ Production Ready diff --git a/docs/en/QUICKSTART_BUILD_EN.md b/docs/en/QUICKSTART_BUILD_EN.md new file mode 100644 index 0000000..d1efbe5 --- /dev/null +++ b/docs/en/QUICKSTART_BUILD_EN.md @@ -0,0 +1,111 @@ +# 🎯 Quick Start - Building Executables + +This is a quick guide for those who want to build an executable file fast. + +## For Linux + +### 1. Install dependencies +```bash +sudo apt-get update +sudo apt-get install -y python3 python3-pip git make +``` + +### 2. Clone repository +```bash +git clone https://github.com/DFofanov/configure_nginx_manager.git +cd configure_nginx_manager +``` + +### 3. Build +```bash +make build-linux +``` + +### 4. Result +```bash +ls -lh dist/letsencrypt-regru +# Executable file is ready! +``` + +### 5. Install (optional) +```bash +sudo cp dist/letsencrypt-regru /usr/local/bin/ +sudo chmod +x /usr/local/bin/letsencrypt-regru +``` + +### 6. Use +```bash +letsencrypt-regru --help +``` + +--- + +## For Windows + +### 1. Install Python +Download from [python.org](https://www.python.org/downloads/) and install + +### 2. Clone repository +```powershell +git clone https://github.com/DFofanov/configure_nginx_manager.git +cd configure_nginx_manager +``` + +### 3. Build +```powershell +make build-windows +``` + +### 4. Result +```powershell +dir dist\letsencrypt-regru.exe +# Executable file is ready! +``` + +### 5. Use +```powershell +.\dist\letsencrypt-regru.exe --help +``` + +--- + +## Creating Release for Both Platforms + +```bash +# This will create packages for Linux and Windows +make release +``` + +**Result in `dist/`:** +- `letsencrypt-regru-linux-x86_64.tar.gz` +- `letsencrypt-regru-windows-x86_64.zip` + +--- + +## Useful Commands + +```bash +# Show help for all commands +make help + +# Build environment information +make build-info + +# Test built file +make test-build + +# Clean artifacts +make clean-build +``` + +--- + +## ❓ Problems? + +See [BUILD_GUIDE_EN.md](BUILD_GUIDE_EN.md) for detailed instructions and troubleshooting. + +--- + +**File size:** ~40-60 MB (including Python runtime) +**Build time:** ~2-5 minutes +**Requirements:** Python 3.8+, PyInstaller diff --git a/docs/en/RELEASE_GUIDE_EN.md b/docs/en/RELEASE_GUIDE_EN.md new file mode 100644 index 0000000..0e6cf64 --- /dev/null +++ b/docs/en/RELEASE_GUIDE_EN.md @@ -0,0 +1,178 @@ +# 🎯 Quick Guide: Automatic Releases + +## For GitHub + +### 1. Creating a Release + +```bash +# Create tag +git tag -a v1.0.0 -m "Release version 1.0.0" + +# Push tag +git push origin v1.0.0 +``` + +### 2. What Happens Automatically + +GitHub Actions will run `.github/workflows/build-release.yml`: + +1. ✅ Build Linux version (Ubuntu runner) +2. ✅ Build Windows version (Windows runner) +3. ✅ Create packages +4. ✅ Generate SHA256 checksums +5. ✅ Create GitHub Release +6. ✅ Upload artifacts + +### 3. Result + +Release will appear at: `https://github.com/USER/REPO/releases/tag/v1.0.0` + +**Files:** +- `letsencrypt-regru-linux-x86_64.tar.gz` +- `letsencrypt-regru-linux-x86_64.tar.gz.sha256` +- `letsencrypt-regru-windows-x86_64.zip` +- `letsencrypt-regru-windows-x86_64.zip.sha256` + +--- + +## For Gitea + +### 1. Setup (one time) + +#### Enable Actions in Gitea: + +Edit `app.ini`: + +```ini +[actions] +ENABLED = true +DEFAULT_ACTIONS_URL = https://gitea.com +``` + +#### Install Gitea Runner: + +```bash +# Download +wget https://dl.gitea.com/act_runner/latest/act_runner-linux-amd64 -O act_runner +chmod +x act_runner + +# Register +./act_runner register --no-interactive \ + --instance https://your-gitea.com \ + --token YOUR_RUNNER_TOKEN + +# Run +./act_runner daemon +``` + +### 2. Creating a Release + +```bash +# Create tag +git tag -a v1.0.0 -m "Release version 1.0.0" + +# Push tag +git push origin v1.0.0 +``` + +### 3. What Happens + +Gitea Actions will run `.gitea/workflows/release.yml`: + +1. ✅ Build Linux version +2. ✅ Build Windows version +3. ✅ Create packages +4. ✅ Generate SHA256 + MD5 checksums +5. ✅ Create Gitea Release +6. ✅ Detailed release notes + +### 4. Result + +Release will appear at: `https://your-gitea.com/USER/REPO/releases/tag/v1.0.0` + +--- + +## 🔧 Pre-Release Checklist + +```bash +# 1. Local build +make clean-build +make release + +# 2. Testing +make test-build + +# 3. Check files +ls -lh dist/ + +# 4. If all OK - create tag +git tag -a v1.0.0 -m "Release 1.0.0" +git push origin v1.0.0 +``` + +--- + +## 📊 Monitoring + +### GitHub: +`https://github.com/USER/REPO/actions` + +### Gitea: +`https://your-gitea.com/USER/REPO/actions` + +--- + +## 🐛 If Something Goes Wrong + +### Delete tag and release: + +```bash +# Delete local tag +git tag -d v1.0.0 + +# Delete remote tag +git push --delete origin v1.0.0 + +# Delete release manually via web interface +``` + +### Recreate release: + +```bash +# Fix the issue +git commit -am "Fix build" + +# Recreate tag +git tag -a v1.0.0 -m "Release 1.0.0" --force +git push origin v1.0.0 --force +``` + +--- + +## 📝 Semantic Versioning + +```bash +# Major (breaking changes) +git tag v2.0.0 + +# Minor (new features) +git tag v1.1.0 + +# Patch (bug fixes) +git tag v1.0.1 + +# Pre-release +git tag v1.0.0-beta.1 +git tag v1.0.0-rc.1 +``` + +--- + +**See also:** +- [.gitea/README.md](../../.gitea/README.md) - Full Gitea Actions documentation +- [BUILD_GUIDE_EN.md](BUILD_GUIDE_EN.md) - Build guide + +--- + +**Author:** Dmitry Fofanov +**Last Updated:** October 28, 2025 diff --git a/docs/en/SSL_Certificate_Creation_and_Renewal_EN.md b/docs/en/SSL_Certificate_Creation_and_Renewal_EN.md new file mode 100644 index 0000000..f382ad0 --- /dev/null +++ b/docs/en/SSL_Certificate_Creation_and_Renewal_EN.md @@ -0,0 +1,86 @@ +# Guide to Creating Wildcard Certificate *.dfv24.com in Nginx Proxy Manager and Configuring Automatic SSL Renewal + +--- + +## Step 1. Preparation + +- Ensure Nginx Proxy Manager (NPM) is installed and accessible at http://192.168.10.14:81/ +- You have access to DNS records for dfv24.com domain in reg.ru control panel or another registrar + +--- + +## Step 2. Creating Wildcard SSL Certificate in Nginx Proxy Manager + +1. Log in to Nginx Proxy Manager admin panel at http://192.168.10.14:81/ + +2. Navigate to **SSL Certificates** → click **Add SSL Certificate** button + +3. Select **Let's Encrypt** + +4. Fill in the fields: + - **Domain Names:** + Enter `*.dfv24.com` — for wildcard certificate + Also recommended to add main domain `dfv24.com` (comma-separated or in new field) + - **Email Address:** + Specify your Email for Let's Encrypt notifications (required) + - **HTTP Challenge:** + Leave HTTP verification if NPM is accessible from internet on ports 80 and 443, or configure DNS Challenge if supported by your DNS + +5. Check "Agree to the Let's Encrypt Terms of Service" + +6. Click **Save** + +- NPM will begin certificate obtaining process with domain verification. +- Upon successful certificate request, you'll see new certificate in the list. + +--- + +## Step 3. Configuring Automatic Renewal + +- Nginx Proxy Manager automatically handles Let's Encrypt certificate renewal. +- For this, server must be accessible from internet on ports 80 and 443, and DNS records must correctly point to your server. +- NPM periodically (usually 30 days before expiration) requests certificate renewal. +- When using DNS Challenge, NPM must have DNS provider integration configured (if supported). + +--- + +## Step 4. Using Wildcard Certificate in Proxy Hosts + +1. Go to **Proxy Hosts** → Create or edit proxy entry + +2. In **Domain Names** field, specify needed subdomain from dfv24.com, for example: + `api.dfv24.com` or `www.dfv24.com` + +3. In **SSL** section, select your wildcard certificate `*.dfv24.com` that you obtained in Step 2 + +4. Enable options: + - Use SSL + - Force SSL + - HSTS (if needed) + +5. Save changes. + +--- + +## Step 5. Verification + +1. Verify that all subdomains use the same certificate +2. Visit https://api.dfv24.com or other subdomains from browser +3. Ensure certificate is valid, not expired, and issued for *.dfv24.com +4. Check certificate renewal status in SSL Certificates section + +--- + +## Additional Information + +- If Let's Encrypt cannot perform HTTP Challenge due to closed port, configure DNS Challenge (may require DNS provider API key) +- For security and notifications, keep Email up to date +- Check Nginx Proxy Manager logs to identify renewal errors + +--- + +# Summary + +Nginx Proxy Manager allows easy obtaining and automatic renewal of wildcard SSL certificates for *.dfv24.com domain using Let's Encrypt. +Main requirements — properly configured DNS records and internet access on HTTP/HTTPS ports. +Then use one global certificate for all your subdomains through Proxy Hosts settings. diff --git a/docs/en/SSL_SCRIPTS_README_EN.md b/docs/en/SSL_SCRIPTS_README_EN.md new file mode 100644 index 0000000..770eb38 --- /dev/null +++ b/docs/en/SSL_SCRIPTS_README_EN.md @@ -0,0 +1,250 @@ +# SSL Certificate Automation Scripts + +**Author:** Фофанов Дмитрий + +## 📖 Overview + +This project contains scripts for automating the creation and renewal of Let's Encrypt SSL certificates using DNS-01 Challenge via the reg.ru API. + +## 🎯 Quick Start + +### Linux (Bash) + +```bash +# 1. Install dependencies +sudo apt-get install certbot jq + +# 2. Configure credentials +nano ~/.regru_credentials +# Add: +# export REGRU_USERNAME="your_login" +# export REGRU_PASSWORD="your_password" + +# 3. Set permissions +chmod 600 ~/.regru_credentials + +# 4. Run the script +./letsencrypt_regru.sh \ + -d "*.dfv24.com" \ + -e "dfofanov@dfv24.com" +``` + +### Linux (Python) + +```bash +# 1. Install dependencies +pip install requests dnspython certbot + +# 2. Configure +cp config.example.yml config.yml +nano config.yml + +# 3. Run +python letsencrypt_regru.py + +# 4. Setup auto-renewal (cron) +crontab -e +# Add: +# 0 3 * * 1 /usr/bin/python3 /path/to/letsencrypt_regru.py +``` + +### Windows (PowerShell) + +```powershell +# 1. Run as Administrator +Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser + +# 2. Configure credentials +$env:REGRU_USERNAME = "your_login" +$env:REGRU_PASSWORD = "your_password" + +# 3. Run +.\letsencrypt_regru.ps1 ` + -Domain "*.dfv24.com" ` + -Email "dfofanov@dfv24.com" + +# 4. Setup auto-renewal (Task Scheduler) +# Import-Module .\ScheduledTask.psm1 +# Create-CertRenewalTask +``` + +## ⚙️ Configuration + +### Bash Script (`letsencrypt_regru.sh`) + +```bash +#!/bin/bash + +# Required parameters +DOMAIN="*.dfv24.com" # Your domain +EMAIL="dfofanov@dfv24.com" # Contact email +REGRU_USERNAME="your_login" # reg.ru login +REGRU_PASSWORD="your_password" # reg.ru password + +# Optional parameters +DNS_PROPAGATION_WAIT=60 # Wait time for DNS propagation (seconds) +LOG_FILE="/var/log/letsencrypt_regru.log" +WEBSERVER="nginx" # nginx or apache2 +``` + +### Python Script (`letsencrypt_regru.py`) + +Create `config.yml`: + +```yaml +# reg.ru credentials +regru: + username: "your_login" + password: "your_password" + +# Certificate settings +certificate: + domain: "*.dfv24.com" + email: "dfofanov@dfv24.com" + dns_propagation_wait: 60 + +# Logging +logging: + file: "/var/log/letsencrypt_regru.log" + level: "INFO" + +# Web server +webserver: + type: "nginx" # nginx, apache2, or null + reload_command: "systemctl reload nginx" +``` + +### PowerShell Script (`letsencrypt_regru.ps1`) + +```powershell +# Configuration +$Config = @{ + Domain = "*.dfv24.com" + Email = "dfofanov@dfv24.com" + RegRuUsername = $env:REGRU_USERNAME + RegRuPassword = $env:REGRU_PASSWORD + DnsPropagationWait = 60 + LogFile = ".\letsencrypt_regru.log" +} +``` + +## 📋 Requirements + +### Bash Script +- **certbot** - Let's Encrypt client +- **jq** - JSON processor +- **curl** - HTTP requests +- **dig** (optional) - DNS queries + +### Python Script +- **Python 3.6+** +- **requests** - HTTP library +- **dnspython** - DNS operations +- **certbot** - Let's Encrypt client +- **PyYAML** - YAML configuration + +### PowerShell Script +- **PowerShell 5.1+** or **PowerShell Core 7+** +- **certbot** (via Chocolatey or manual installation) + +## 🔄 Automatic Renewal + +### Linux (cron) + +```bash +# Edit crontab +crontab -e + +# Add (runs every Monday at 3 AM): +0 3 * * 1 /path/to/letsencrypt_regru.sh >> /var/log/cert_renewal.log 2>&1 + +# Or for Python: +0 3 * * 1 /usr/bin/python3 /path/to/letsencrypt_regru.py +``` + +### Windows (Task Scheduler) + +```powershell +# Create scheduled task +$Action = New-ScheduledTaskAction -Execute "PowerShell.exe" ` + -Argument "-File C:\path\to\letsencrypt_regru.ps1" + +$Trigger = New-ScheduledTaskTrigger -Weekly -DaysOfWeek Monday -At 3am + +Register-ScheduledTask -TaskName "SSL Certificate Renewal" ` + -Action $Action -Trigger $Trigger -RunLevel Highest +``` + +## ✨ Features + +✅ Automatic DNS validation via reg.ru API +✅ Certificate expiration check +✅ Automatic renewal before expiration +✅ Web server reload after renewal +✅ Detailed logging of all operations + +## 🔧 Using with Nginx Proxy Manager + +After obtaining the certificate: + +1. Log in to NPM: http://192.168.10.14:81/ +2. SSL Certificates → Add SSL Certificate → Custom +3. Paste the content: + - Certificate Key: `/etc/letsencrypt/live/domain.com/privkey.pem` + - Certificate: `/etc/letsencrypt/live/domain.com/fullchain.pem` + +## 📝 Logs + +- Bash: `/var/log/letsencrypt_regru.log` +- Python: `/var/log/letsencrypt_regru.log` +- PowerShell: `.\letsencrypt_regru.log` +- Certbot: `/var/log/letsencrypt/letsencrypt.log` + +## 🆘 Troubleshooting + +### API Authentication Error +- Check your reg.ru credentials +- Ensure the domain is under your control + +### DNS Record Not Propagating +- Increase `dns_propagation_wait` to 120 seconds +- Check DNS: `nslookup -type=TXT _acme-challenge.domain.com` + +### Certbot Not Found +```bash +# Ubuntu/Debian +sudo apt-get install certbot + +# Or via snap +sudo snap install --classic certbot +``` + +## 📚 Documentation + +Detailed documentation in [USAGE.md](USAGE.md) + +## 🔐 Security + +- Keep credentials secure +- Use `chmod 600` for configuration files +- Regularly update passwords + +## ⚠️ Important + +- Let's Encrypt certificates are valid for 90 days +- Automatic renewal setup is recommended +- Wildcard certificates require DNS validation + +## 📞 Support + +- [reg.ru API Documentation](https://www.reg.ru/support/api) +- [Let's Encrypt Documentation](https://letsencrypt.org/docs/) +- [Certbot Documentation](https://certbot.eff.org/docs/) + +## 📄 License + +Scripts are provided "as is" for free use. + +--- + +**Happy Automation! 🔒** diff --git a/docs/en/TESTING_GUIDE_EN.md b/docs/en/TESTING_GUIDE_EN.md new file mode 100644 index 0000000..29e9686 --- /dev/null +++ b/docs/en/TESTING_GUIDE_EN.md @@ -0,0 +1,379 @@ +# 🧪 SSL Certificate Testing Guide + +## Why do you need test certificates? + +Let's Encrypt has **strict limits**: +- ⚠️ Maximum **5 certificates per week** per domain +- ⚠️ Maximum **50 certificates per week** per account +- ⚠️ **1 week ban** if limits exceeded + +**Solution**: Use self-signed test certificates for development! + +--- + +## Quick Start + +### Option 1: Via Makefile (Recommended) + +```bash +# After script installation (make install) +sudo make test-cert +``` + +**Result**: Certificate created in `/etc/letsencrypt/live/your-domain/` + +### Option 2: Via Python Script + +```bash +sudo python3 letsencrypt_regru_api.py \ + --config /etc/letsencrypt/regru_config.json \ + --test-cert -v +``` + +### Option 3: Via Bash Script (Standalone) + +```bash +# Simple domain +sudo ./test_certificate.sh example.com no + +# With wildcard +sudo ./test_certificate.sh example.com yes +``` + +--- + +## Method Comparison + +| Method | Speed | Requirements | NPM Integration | Limits | +|--------|-------|--------------|-----------------|--------| +| **Let's Encrypt** | 2-5 min | Internet, DNS | ✅ Yes | ⚠️ 5/week | +| **Test (Python)** | 1-2 sec | Python only | ✅ Yes | ✅ None | +| **Test (Bash)** | 1-2 sec | OpenSSL only | ❌ Manual | ✅ None | + +--- + +## Detailed Instructions + +### 1. Configuration Setup + +```bash +# Create configuration +sudo nano /etc/letsencrypt/regru_config.json +``` + +```json +{ + "domain": "test.example.com", + "wildcard": true, + "cert_dir": "/etc/letsencrypt/live", + "npm_enabled": true, + "npm_host": "https://npm.example.com", + "npm_email": "admin@example.com", + "npm_password": "your_password" +} +``` + +### 2. Create Test Certificate + +```bash +sudo make test-cert +``` + +### 3. Verify Created Files + +```bash +ls -la /etc/letsencrypt/live/test.example.com/ +# Should contain: +# - privkey.pem (private key) +# - cert.pem (certificate) +# - fullchain.pem (full chain) +# - chain.pem (CA chain) +``` + +### 4. View Certificate Information + +```bash +openssl x509 -in /etc/letsencrypt/live/test.example.com/cert.pem -text -noout +``` + +--- + +## Using in Nginx + +### Direct Usage + +```nginx +server { + listen 443 ssl; + server_name test.example.com; + + ssl_certificate /etc/letsencrypt/live/test.example.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/test.example.com/privkey.pem; + + # ... rest of configuration +} +``` + +### Via Nginx Proxy Manager + +If `npm_enabled: true` in configuration, certificate will automatically upload to NPM. + +**Check in NPM:** +1. Open NPM web interface +2. Go to **SSL Certificates** +3. Find your domain in the list +4. ⚠️ Will be marked as "Custom" (not Let's Encrypt) + +--- + +## Test Automation + +### CI/CD Script + +```bash +#!/bin/bash +# test_ssl_integration.sh + +set -e + +echo "🧪 Testing SSL integration..." + +# 1. Create test certificate +sudo python3 letsencrypt_regru_api.py \ + --config test_config.json \ + --test-cert + +# 2. Verify files +if [ ! -f "/etc/letsencrypt/live/test.example.com/fullchain.pem" ]; then + echo "❌ Certificate not created" + exit 1 +fi + +# 3. Check validity +openssl x509 -in /etc/letsencrypt/live/test.example.com/cert.pem -noout -checkend 0 +if [ $? -eq 0 ]; then + echo "✅ Certificate is valid" +else + echo "❌ Certificate is invalid" + exit 1 +fi + +echo "✅ All tests passed" +``` + +### Makefile for Testing + +```makefile +.PHONY: test-ssl test-npm test-all + +test-ssl: + @echo "Creating test certificate..." + sudo make test-cert + @echo "Verifying files..." + test -f /etc/letsencrypt/live/$(DOMAIN)/fullchain.pem + @echo "✅ SSL test passed" + +test-npm: + @echo "Checking NPM integration..." + # Your NPM API checks + @echo "✅ NPM test passed" + +test-all: test-ssl test-npm + @echo "✅ All tests passed" +``` + +--- + +## Transition to Production + +### Step 1: Testing + +```bash +# 1. Create test certificate +sudo make test-cert + +# 2. Verify with NPM +# Open https://your-domain and check + +# 3. Ensure everything works +``` + +### Step 2: Switch to Let's Encrypt + +```bash +# 1. Remove test certificate +sudo rm -rf /etc/letsencrypt/live/your-domain/ + +# 2. Get real certificate +sudo make obtain + +# 3. Verify update in NPM +sudo make status +``` + +--- + +## FAQ + +### Q: Why does browser show warning? + +**A:** Self-signed certificates are not trusted by browsers. This is normal for testing. + +To avoid browser warning (local testing only): +1. Chrome: `chrome://flags/#allow-insecure-localhost` +2. Firefox: Click "Advanced" → "Accept the Risk" + +### Q: Can I use in production? + +**A:** ❌ **NO!** Test certificates are for development and testing only. + +### Q: How often can I create test certificates? + +**A:** ✅ Unlimited! No limits whatsoever. + +### Q: Do they upload to NPM automatically? + +**A:** ✅ Yes, if `npm_enabled: true` in configuration. + +### Q: Do they work with wildcard domains? + +**A:** ✅ Yes! Just set `"wildcard": true` in configuration. + +### Q: How to check expiration date? + +```bash +openssl x509 -in /etc/letsencrypt/live/your-domain/cert.pem -noout -dates +``` + +### Q: How to change validity period? + +Edit `validity_days` in `generate_self_signed_certificate()` function: + +```python +validity_days: int = 365 # Change to desired number of days +``` + +--- + +## Troubleshooting + +### Error: Permission denied + +```bash +# Run with sudo +sudo make test-cert +``` + +### Error: Module 'cryptography' not found + +```bash +# Install dependencies +sudo pip3 install cryptography +``` + +### NPM doesn't show certificate + +1. Check NPM settings in configuration +2. Check logs: `sudo make logs` +3. Try uploading manually via NPM web interface + +### Certificate not created + +```bash +# Check permissions +ls -la /etc/letsencrypt/live/ + +# Create directory manually +sudo mkdir -p /etc/letsencrypt/live/ + +# Check configuration +sudo make check-config +``` + +--- + +## Usage Examples + +### Docker Development + +```dockerfile +FROM nginx:alpine + +# Copy test certificate +COPY test-certs/ /etc/nginx/ssl/ + +# Nginx configuration +COPY nginx.conf /etc/nginx/nginx.conf + +EXPOSE 443 +``` + +### Local Testing + +```bash +# Create certificate for localhost +sudo python3 letsencrypt_regru_api.py --test-cert + +# Add to /etc/hosts +echo "127.0.0.1 test.example.com" | sudo tee -a /etc/hosts + +# Start nginx +sudo nginx -t && sudo nginx -s reload + +# Open in browser +open https://test.example.com +``` + +### Automated Testing Before Deployment + +```bash +#!/bin/bash +# pre-deploy.sh + +# Test SSL check +sudo make test-cert +if [ $? -eq 0 ]; then + echo "✅ Test certificate created successfully" + echo "✅ Ready for production certificate" + sudo make obtain +else + echo "❌ Error creating test certificate" + exit 1 +fi +``` + +--- + +## Additional Resources + +- 📘 [Let's Encrypt Rate Limits](https://letsencrypt.org/docs/rate-limits/) +- 📘 [OpenSSL Documentation](https://www.openssl.org/docs/) +- 📘 [Nginx Proxy Manager Docs](https://nginxproxymanager.com/guide/) + +--- + +## Quick Reference + +```bash +# Installation +sudo make install + +# Configuration +sudo nano /etc/letsencrypt/regru_config.json + +# Create test certificate +sudo make test-cert + +# Verify +sudo make check-config +sudo make status + +# Switch to production +sudo rm -rf /etc/letsencrypt/live/domain/ +sudo make obtain + +# Automatic renewal +sudo make run +``` + +**Done!** 🎉 Now you can test SSL certificates without limits! diff --git a/docs/ru/API_TROUBLESHOOTING.md b/docs/ru/API_TROUBLESHOOTING.md new file mode 100644 index 0000000..0312708 --- /dev/null +++ b/docs/ru/API_TROUBLESHOOTING.md @@ -0,0 +1,206 @@ +# 🔧 Решение проблем с API reg.ru + +## ❌ Проблема: "Access to API from this IP denied" + +Эта ошибка возникает, когда API reg.ru заблокирован для вашего IP адреса из соображений безопасности. + +### 🔍 Диагностика + +Сначала определите ваш текущий IP адрес: + +```bash +# Способ 1: Через встроенную функцию скрипта +sudo letsencrypt-regru --test-api + +# Способ 2: Через curl +curl -s https://ipinfo.io/ip + +# Способ 3: Через веб-сайт +# Откройте https://whatismyipaddress.com/ +``` + +### ✅ Решение + +#### Метод 1: Добавить IP в белый список (рекомендуется) + +1. **Войдите в личный кабинет reg.ru** + - Откройте https://www.reg.ru/ + - Войдите в личный кабинет + +2. **Перейдите в настройки API** + - Меню → "Настройки" + - Раздел "Безопасность" + - Подраздел "API" + +3. **Настройте доступ по IP** + - Найдите раздел "Ограничения по IP" + - Нажмите "Добавить IP адрес" + - Введите ваш текущий IP адрес + - Сохраните настройки + +4. **Проверьте настройки** + ```bash + sudo letsencrypt-regru --test-api + ``` + +#### Метод 2: Отключить ограничения по IP (менее безопасно) + +⚠️ **ВНИМАНИЕ**: Это снижает безопасность вашего аккаунта! + +1. В настройках API reg.ru найдите "Ограничения по IP" +2. Отключите опцию "Разрешить доступ только с указанных IP" +3. Сохраните настройки + +### 🔒 Рекомендации по безопасности + +1. **Используйте статический IP** + - Если у вас динамический IP, рассмотрите покупку статического + - Или регулярно обновляйте список разрешенных IP + +2. **Ограничьте доступ к API** + - Добавляйте только необходимые IP адреса + - Регулярно проверяйте и очищайте список + +3. **Используйте сильные пароли** + - Сложный пароль для аккаунта reg.ru + - Двухфакторная аутентификация если доступна + +## ❌ Проблема: "Invalid username or password" + +### ✅ Решение + +1. **Проверьте учетные данные** + ```bash + sudo nano /etc/letsencrypt-regru/config.json + ``` + + Убедитесь что указаны правильные: + - `regru_username` - логин от reg.ru + - `regru_password` - пароль от reg.ru + +2. **Проверьте права на файл** + ```bash + sudo chmod 600 /etc/letsencrypt-regru/config.json + sudo chown root:root /etc/letsencrypt-regru/config.json + ``` + +3. **Протестируйте подключение** + ```bash + sudo letsencrypt-regru --test-api + ``` + +## ❌ Проблема: "IP exceeded allowed connection rate" + +### Причина +API reg.ru ограничивает частоту запросов с одного IP (обычно 10-20 запросов в минуту). + +### ✅ Решение + +1. **Подождите 5-10 минут** + ```bash + # Подождите перед следующей попыткой + sleep 600 # 10 минут + sudo letsencrypt-regru --obtain + ``` + +2. **Настройте автоматизацию правильно** + ```bash + # Проверка сертификатов 1 раз в день + sudo systemctl enable letsencrypt-regru.timer + sudo systemctl start letsencrypt-regru.timer + + # Проверить расписание + sudo systemctl cat letsencrypt-regru.timer + ``` + +3. **Рекомендации по частоте запросов** + - ✅ Автоматическая проверка: **1 раз в день** + - ✅ Ручная проверка: **не чаще 1 раза в час** + - ❌ Избегайте частых тестов `--test-api` + - ❌ Не создавайте cron с частым запуском + +4. **Используйте --check вместо --obtain** + ```bash + # Проверка без создания сертификата + sudo letsencrypt-regru --check + ``` + +## ❌ Проблема: Таймаут подключения + +### ✅ Решение + +1. **Проверьте интернет соединение** + ```bash + ping -c 4 api.reg.ru + curl -I https://api.reg.ru/api/regru2 + ``` + +2. **Проверьте брандмауэр** + ```bash + # Временно отключите firewall для теста + sudo ufw status + sudo iptables -L + ``` + +3. **Проверьте прокси настройки** + - Убедитесь что переменные окружения `HTTP_PROXY`, `HTTPS_PROXY` не мешают + +## 🧪 Тестирование API + +Всегда тестируйте API перед использованием: + +```bash +# Полный тест API +sudo letsencrypt-regru --test-api + +# Тест с подробным выводом +sudo letsencrypt-regru --test-api -v + +# Проверка конфигурации +sudo letsencrypt-regru --check +``` + +## 📞 Получение помощи + +### Техподдержка reg.ru + +- **Email**: support@reg.ru +- **Телефон**: 8 (495) 580-11-11 +- **Онлайн чат**: на сайте reg.ru + +### Документация + +- **API reg.ru**: https://www.reg.ru/support/api +- **Примеры использования**: https://www.reg.ru/support/api/examples +- **FAQ по API**: https://www.reg.ru/support/api/faq + +### Логи для диагностики + +Всегда включайте логи при обращении в поддержку: + +```bash +# Включить подробные логи +sudo letsencrypt-regru --test-api -v + +# Посмотреть последние логи +sudo tail -n 50 /var/log/letsencrypt-regru/letsencrypt_regru.log + +# Логи certbot +sudo tail -n 50 /var/log/letsencrypt/letsencrypt.log +``` + +## 🔄 Альтернативные DNS провайдеры + +Если проблемы с reg.ru API критичны, рассмотрите альтернативы: + +1. **Cloudflare** - отличный API, бесплатный DNS +2. **Route53** (AWS) - мощный, но платный +3. **DigitalOcean DNS** - простой и надежный +4. **Google Cloud DNS** - интеграция с GCP + +Для них потребуется модификация скрипта или использование других плагинов certbot. + +--- + +**Дата обновления**: 29.10.2025 +**Версия документа**: 1.0 \ No newline at end of file diff --git a/docs/ru/Add Let's Encrypt Certificate для провайдера reg.ru.md b/docs/ru/Add Let's Encrypt Certificate для провайдера reg.ru.md new file mode 100644 index 0000000..bf4f748 --- /dev/null +++ b/docs/ru/Add Let's Encrypt Certificate для провайдера reg.ru.md @@ -0,0 +1,56 @@ +# Инструкция по созданию Let's Encrypt сертификата с DNS Challenge для провайдера reg.ru в Nginx Proxy Manager + +--- + +## Предпосылки +- Доступ к Nginx Proxy Manager (NPM) +- Доступ к аккаунту reg.ru с правами управления DNS-записями +- API-ключ для управления DNS в reg.ru (если есть автоматическая интеграция) +- Нужно получить сертификат для `*.dfv24.com` (wildcard сертификат) + +--- + +## Шаг 1. Получение API-ключа для reg.ru + +1. Войдите в панель управления reg.ru +2. Перейдите в раздел управления API (если поддерживается) +3. Создайте или найдите API-ключ с правом редактирования DNS записей +4. Сохраните API-ключ и секрет (Client ID и API Token) + +--- + +## Шаг 2. Настройка Nginx Proxy Manager для использования DNS Challenge reg.ru + +1. В админке NPM перейдите в **SSL Certificates → Add SSL Certificate** +2. Выберите **Let's Encrypt** -> **DNS Challenge** +3. В поле **Provider** выберите `reg_ru` или `custom` (если провайдера нет, потребуется писать скрипт) +4. В поля API впишите необходимые параметры: + - Client ID + - API Token +5. В поле **Domain Names** укажите: + `*.dfv24.com` (для wildcard сертификата) + и основной домен `dfv24.com` +6. Включите остальные опции (Terms of Service, Email) +7. Нажмите **Save** для запроса сертификата +8. NPM автоматически добавит DNS TXT-записи для подтверждения владения доменом через API reg.ru + +--- + +## Шаг 3. Проверка и автоматическое продление + +- После успешного создания сертификата NPM будет автоматически обновлять его через DNS Challenge. +- Для успешного продления важно, чтобы API-ключ был действующим, а NPM имел доступ к DNS управлению. + +--- + +## Если в NPM нет готовой интеграции с reg.ru + +- Используйте внешний скрипт для обновления TXT записей DNS в reg.ru, настраиваемый в NPM через **Custom DNS Provider**. +- Нужна настройка curl-запросов к API reg.ru для добавления/удаления TXT записей. + +--- + +# Итог + +Для wildcard сертификатов Let's Encrypt у reg.ru необходимо использовать DNS Challenge, используя API провайдера для автоматического управления DNS записями. +В Nginx Proxy Manager настройте DNS Challenge с учётом особенностей reg.ru для бесшовного получения и продления сертификатов. diff --git a/docs/ru/BUILD_GUIDE.md b/docs/ru/BUILD_GUIDE.md new file mode 100644 index 0000000..fad01f3 --- /dev/null +++ b/docs/ru/BUILD_GUIDE.md @@ -0,0 +1,455 @@ +# 🔨 Руководство по сборке исполняемых файлов + +Данное руководство описывает процесс компиляции Python-скрипта `letsencrypt_regru_api.py` в исполняемые файлы для Linux и Windows с использованием PyInstaller. + +## 📋 Содержание + +- [Преимущества исполняемых файлов](#преимущества-исполняемых-файлов) +- [Быстрый старт](#быстрый-старт) +- [Подробные инструкции](#подробные-инструкции) +- [Кросс-компиляция](#кросс-компиляция) +- [Troubleshooting](#troubleshooting) + +--- + +## ✅ Преимущества исполняемых файлов + +### Плюсы: +- ✅ **Один файл** - легко распространять и развертывать +- ✅ **Автономность** - не требует установленного Python на целевой системе +- ✅ **Все зависимости включены** - requests, cryptography и certbot модули упакованы +- ✅ **Простота запуска** - просто скачать и запустить + +### Минусы: +- ❌ **Большой размер** - ~40-60 MB (включая Python runtime и библиотеки) +- ❌ **Certbot зависимость** - системный certbot все равно требуется +- ❌ **Медленный первый запуск** - распаковка занимает несколько секунд +- ❌ **Требуется пересборка** - при изменении кода нужно пересобирать + +--- + +## 🚀 Быстрый старт + +### Сборка для текущей ОС: +```bash +make build +``` + +### Сборка для всех платформ: +```bash +make build-all +``` + +### Полный релиз (сборка + пакеты): +```bash +make release +``` + +--- + +## 📖 Подробные инструкции + +### 1. Установка зависимостей + +#### Вариант А: Автоматическая установка +```bash +make install-pyinstaller +``` + +#### Вариант Б: Ручная установка +```bash +pip install pyinstaller +pip install -r requirements.txt +``` + +### 2. Сборка для Linux + +**На Linux системе:** +```bash +make build-linux +``` + +**Результат:** +- Файл: `dist/letsencrypt-regru` +- Размер: ~45-55 MB +- Формат: ELF 64-bit executable + +**Тестирование:** +```bash +./dist/letsencrypt-regru --help +sudo ./dist/letsencrypt-regru --check -c /etc/letsencrypt-regru/config.json +``` + +### 3. Сборка для Windows + +**На Windows системе (PowerShell/CMD):** +```bash +make build-windows +``` + +**Результат:** +- Файл: `dist/letsencrypt-regru.exe` +- Размер: ~40-50 MB +- Формат: PE32+ executable (Windows) + +**Тестирование:** +```powershell +.\dist\letsencrypt-regru.exe --help +``` + +### 4. Создание пакетов для распространения + +#### Linux пакет (tar.gz): +```bash +make package-linux +``` + +**Содержимое пакета:** +- `letsencrypt-regru` - исполняемый файл +- `README.md` - документация +- `systemd/` - systemd unit файлы +- `config.json.example` - пример конфигурации + +**Результат:** `dist/letsencrypt-regru-linux-x86_64.tar.gz` + +#### Windows пакет (zip): +```bash +make package-windows +``` + +**Результат:** `dist/letsencrypt-regru-windows-x86_64.zip` + +### 5. Полный цикл релиза + +Создание релиза со всеми артефактами: + +```bash +make release +``` + +**Что происходит:** +1. Очистка старых артефактов (`clean-build`) +2. Установка/обновление PyInstaller +3. Сборка для Linux (`build-linux`) +4. Сборка для Windows (`build-windows`) +5. Создание пакета для Linux (`package-linux`) +6. Создание пакета для Windows (`package-windows`) +7. Генерация SHA256 контрольных сумм + +**Результат в `dist/`:** +``` +letsencrypt-regru # Linux executable +letsencrypt-regru.exe # Windows executable +letsencrypt-regru-linux-x86_64.tar.gz +letsencrypt-regru-windows-x86_64.zip +``` + +--- + +## 🔄 Кросс-компиляция + +### ⚠️ Важные замечания + +**Не рекомендуется:** +- Собирать Linux версию на Windows +- Собирать Windows версию на Linux +- Собирать macOS версию на других ОС + +**Причины:** +- Несовместимость системных библиотек +- Разные форматы исполняемых файлов +- Проблемы с путями и разделителями + +### Рекомендации + +#### Для Linux сборки: +1. Используйте Ubuntu 20.04+ или Debian 10+ +2. Установите build-essential +3. Используйте виртуальное окружение Python + +```bash +sudo apt-get update +sudo apt-get install -y python3 python3-pip build-essential +make build-linux +``` + +#### Для Windows сборки: +1. Используйте Windows 10/11 +2. Установите Python 3.8+ +3. Используйте PowerShell или CMD + +```powershell +python -m pip install --upgrade pip +make build-windows +``` + +#### Для обеих платформ: +Используйте CI/CD (GitHub Actions, GitLab CI): + +```yaml +# .github/workflows/build.yml +name: Build Releases + +on: + push: + tags: + - 'v*' + +jobs: + build-linux: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Build Linux + run: make build-linux + + build-windows: + runs-on: windows-latest + steps: + - uses: actions/checkout@v3 + - name: Build Windows + run: make build-windows +``` + +--- + +## 🛠️ Все команды Makefile + +### Основные команды: + +| Команда | Описание | +|---------|----------| +| `make build` | Собрать для текущей ОС | +| `make build-linux` | Собрать для Linux | +| `make build-windows` | Собрать для Windows | +| `make build-all` | Собрать для всех платформ | +| `make package-linux` | Создать tar.gz пакет | +| `make package-windows` | Создать zip пакет | +| `make release` | Полный цикл релиза | + +### Вспомогательные команды: + +| Команда | Описание | +|---------|----------| +| `make install-pyinstaller` | Установить PyInstaller | +| `make test-build` | Протестировать собранный файл | +| `make clean-build` | Очистить артефакты сборки | +| `make build-info` | Показать информацию о среде | + +--- + +## 🐛 Troubleshooting + +### Проблема: PyInstaller не найден + +**Ошибка:** +``` +make: pyinstaller: Command not found +``` + +**Решение:** +```bash +make install-pyinstaller +# или +pip install pyinstaller +``` + +--- + +### Проблема: Импорт модулей не работает + +**Ошибка:** +``` +ModuleNotFoundError: No module named 'requests' +``` + +**Решение:** +```bash +pip install -r requirements.txt +# или добавьте в PyInstaller команду: +--hidden-import requests +--hidden-import certbot +--hidden-import cryptography +``` + +--- + +### Проблема: Большой размер файла + +**Размер ~100+ MB вместо 40-60 MB** + +**Причины:** +- Включены лишние модули +- Не используется `--onefile` +- Включены debug символы + +**Решение:** +```bash +# Используйте флаги оптимизации: +pyinstaller --onefile \ + --strip \ + --exclude-module tkinter \ + --exclude-module matplotlib \ + letsencrypt_regru_api.py +``` + +--- + +### Проблема: Certbot не работает в исполняемом файле + +**Ошибка:** +``` +certbot: command not found +``` + +**Решение:** + +Certbot вызывается через `subprocess` и должен быть установлен в системе: + +**Linux:** +```bash +sudo apt-get install certbot +``` + +**Windows:** +- Не поддерживается напрямую +- Используйте WSL или Docker + +--- + +### Проблема: Права доступа к файлам + +**Ошибка:** +``` +Permission denied: /etc/letsencrypt/ +``` + +**Решение:** +```bash +# Linux/macOS +sudo ./dist/letsencrypt-regru --check + +# Или установите правильные права: +sudo chmod +x ./dist/letsencrypt-regru +sudo chown root:root ./dist/letsencrypt-regru +``` + +--- + +### Проблема: Медленный запуск + +**Первый запуск занимает 5-10 секунд** + +**Причина:** +PyInstaller распаковывает файлы во временную директорию при каждом запуске. + +**Решение:** +- Это нормальное поведение для `--onefile` +- Используйте `--onedir` для более быстрого запуска (но будет много файлов) +- Кэшируйте временную директорию (автоматически) + +--- + +### Проблема: Антивирус блокирует файл + +**Windows Defender помечает .exe как вирус** + +**Причины:** +- Самораспаковывающийся архив похож на вредоносное ПО +- Отсутствие цифровой подписи +- Малоизвестный исполняемый файл + +**Решение:** +1. **Добавьте в исключения:** + - Windows Defender → Settings → Exclusions + +2. **Подпишите файл цифровой подписью:** + ```bash + # Требуется сертификат Code Signing + signtool sign /f cert.pfx /p password dist/letsencrypt-regru.exe + ``` + +3. **Проверьте на VirusTotal:** + - Загрузите файл на virustotal.com + - Добавьте результаты в README + +--- + +## 📊 Сравнение: Python vs Исполняемый файл + +| Характеристика | Python скрипт | Исполняемый файл | +|----------------|---------------|------------------| +| Размер | ~50 KB | ~40-60 MB | +| Зависимости | Требует Python + pip | Автономный | +| Скорость запуска | Быстро (~1 сек) | Медленно (~5-10 сек) | +| Обновление | Просто заменить .py | Требуется пересборка | +| Совместимость | Любая ОС с Python | Только для целевой ОС | +| Установка | Требует venv setup | Скачать и запустить | +| Certbot | Через subprocess | Через subprocess | + +--- + +## 🎯 Рекомендации + +### Используйте Python скрипт если: +- ✅ Python уже установлен в системе +- ✅ Нужны частые обновления кода +- ✅ Используете виртуальное окружение +- ✅ Работаете на серверах (production) + +### Используйте исполняемый файл если: +- ✅ Python не установлен +- ✅ Нужна простота развертывания +- ✅ Распространяете для конечных пользователей +- ✅ Тестирование на чистых системах + +--- + +## 📦 Пример использования собранного файла + +### Linux: + +```bash +# Скачать и распаковать +wget https://github.com/user/repo/releases/download/v1.0/letsencrypt-regru-linux-x86_64.tar.gz +tar -xzf letsencrypt-regru-linux-x86_64.tar.gz + +# Установить +sudo mv letsencrypt-regru /usr/local/bin/ +sudo chmod +x /usr/local/bin/letsencrypt-regru + +# Использовать +sudo letsencrypt-regru --help +sudo letsencrypt-regru --check -c /etc/letsencrypt-regru/config.json +``` + +### Windows: + +```powershell +# Скачать и распаковать +Invoke-WebRequest -Uri "https://github.com/user/repo/releases/download/v1.0/letsencrypt-regru-windows-x86_64.zip" -OutFile "letsencrypt-regru.zip" +Expand-Archive -Path letsencrypt-regru.zip -DestinationPath "C:\Program Files\LetsEncrypt-RegRu" + +# Использовать +cd "C:\Program Files\LetsEncrypt-RegRu" +.\letsencrypt-regru.exe --help +``` + +--- + +## 📝 Дополнительные ресурсы + +- [PyInstaller Documentation](https://pyinstaller.org/en/stable/) +- [PyInstaller FAQ](https://pyinstaller.org/en/stable/FAQ.html) +- [Building Cross-Platform Applications](https://pyinstaller.org/en/stable/operating-mode.html) + +--- + +## 📄 Лицензия + +Этот проект использует лицензию согласно основному README.md. + +--- + +**Автор:** Фофанов Дмитрий +**Дата обновления:** 28.10.2025 diff --git a/docs/ru/CHANGELOG.md b/docs/ru/CHANGELOG.md new file mode 100644 index 0000000..9fcac2b --- /dev/null +++ b/docs/ru/CHANGELOG.md @@ -0,0 +1,153 @@ +# 📋 Журнал изменений (Changelog) + +## [2.1.0] - 2025-10-27 + +### 🆕 Добавлено + +#### Генерация тестовых SSL сертификатов +- ✨ **Новый класс `TestCertificateGenerator`** - генерация самоподписанных сертификатов +- ✨ **Команда `--test-cert`** в Python скрипте для создания тестовых сертификатов +- ✨ **Скрипт `test_certificate.sh`** - автономное создание через OpenSSL +- ✨ **Команда `make test-cert`** в Makefile для быстрого тестирования + +#### Документация +- 📘 **TESTING_GUIDE.md** (370+ строк) - полное руководство по тестированию + - Обход лимитов Let's Encrypt (5 сертификатов в неделю) + - Сравнение методов создания сертификатов + - Примеры для CI/CD и Docker + - Переход с тестовых на production + - Частые вопросы и решения + +- 📘 **PROJECT_STRUCTURE.md** - структура проекта + - Описание всех файлов + - Список возможностей + - Технологии + +- 📘 **CHEATSHEET.md** - быстрая шпаргалка + - Основные команды + - Сценарии использования + - Частые ошибки и решения + - Workflow разработки + +#### Функциональность +- ✨ Поддержка **неограниченного количества** тестовых сертификатов +- ✨ **Мгновенное создание** (1-2 секунды) без DNS валидации +- ✨ **Автоматическая загрузка** тестовых сертификатов в NPM +- ✨ **Полная совместимость** структуры с Let's Encrypt +- ✨ **Wildcard поддержка** для тестовых сертификатов + +### 🔧 Улучшено + +#### Python скрипт +- Добавлен импорт библиотеки `cryptography` с проверкой установки +- Новые параметры командной строки: + - `--test-cert` - создание тестового сертификата + - `--auto` - явное указание автоматического режима +- Улучшенная обработка тестовых сертификатов в NPM +- Детальное логирование процесса генерации + +#### Makefile +- Добавлена команда `make test-cert` с красивым выводом +- Информационные сообщения о преимуществах тестовых сертификатов +- Предупреждения о безопасности + +#### README.md +- Раздел "Создание тестового самоподписанного сертификата" +- Обновленное содержание с ссылкой на тестовые сертификаты +- Примеры использования тестовых сертификатов +- Интеграция с NPM для тестовых сертификатов +- Ссылки на дополнительную документацию + +### 🎯 Преимущества + +#### Для разработчиков +- ✅ **Нет лимитов** - неограниченное количество сертификатов +- ✅ **Быстро** - создание за 1-2 секунды +- ✅ **Офлайн** - работает без интернета +- ✅ **Идентичная структура** - те же файлы что и Let's Encrypt + +#### Для тестирования +- ✅ **CI/CD friendly** - быстрое создание в pipeline +- ✅ **Docker ready** - легко встраивается в контейнеры +- ✅ **Staging окружения** - идеально для тестовых серверов +- ✅ **Локальная разработка** - HTTPS на localhost + +### 📊 Статистика + +- **Строк кода**: 1,411 (Python скрипт) +- **Строк в Makefile**: 415 +- **Строк документации**: 2,200+ +- **Команд в Makefile**: 13 +- **Режимов работы**: 4 (obtain, renew, auto, test-cert) + +--- + +## [2.0.0] - 2025-10-27 + +### 🆕 Добавлено +- ✨ Интеграция с Nginx Proxy Manager (NPM) +- ✨ Класс `NginxProxyManagerAPI` для управления сертификатами через API +- ✨ Автоматическая загрузка сертификатов в NPM +- ✨ Автоматическое обновление сертификатов в NPM +- ✨ Автоматическая проверка срока действия +- ✨ Настраиваемый порог обновления (`renewal_days`) +- ✨ Makefile для автоматизации установки/удаления +- ✨ Systemd service + timer +- ✨ Cron автоматизация + +### 🔧 Улучшено +- Консолидация документации в единый README.md +- Подробное логирование с статусами операций +- Валидация конфигурации +- Улучшенная обработка ошибок + +### 📘 Документация +- Полное руководство по NPM интеграции +- Быстрый старт за 3 команды +- Примеры автоматизации + +--- + +## [1.0.0] - 2025-10-26 + +### 🆕 Первый релиз +- Python скрипт для Let's Encrypt через reg.ru API +- Bash скрипт с certbot-dns-regru +- PowerShell версия для Windows +- DNS-01 валидация +- Wildcard сертификаты +- Базовая документация + +--- + +## Roadmap (Планы) + +### [2.2.0] - Планируется +- [ ] Веб-интерфейс для управления +- [ ] Поддержка множественных доменов +- [ ] Notifications (email, telegram) +- [ ] Grafana dashboard для мониторинга +- [ ] Backup сертификатов + +### [3.0.0] - Будущее +- [ ] Поддержка других DNS провайдеров +- [ ] Cloudflare API +- [ ] Route53 (AWS) +- [ ] Google Cloud DNS + +--- + +## Типы изменений +- `🆕 Добавлено` - новый функционал +- `🔧 Улучшено` - улучшения существующего функционала +- `🐛 Исправлено` - исправление багов +- `🗑️ Удалено` - удаленный функционал +- `🔒 Безопасность` - изменения безопасности +- `📘 Документация` - изменения в документации + +--- + +**Версионирование**: Semantic Versioning (MAJOR.MINOR.PATCH) +- **MAJOR**: Несовместимые изменения API +- **MINOR**: Новый функционал с обратной совместимостью +- **PATCH**: Исправления багов diff --git a/docs/ru/CHEATSHEET.md b/docs/ru/CHEATSHEET.md new file mode 100644 index 0000000..748e367 --- /dev/null +++ b/docs/ru/CHEATSHEET.md @@ -0,0 +1,287 @@ +# ⚡ Шпаргалка по SSL сертификатам + +## 🚀 Быстрый старт + +### Установка за 3 команды +```bash +sudo make install +sudo nano /etc/letsencrypt/regru_config.json # Заполнить данные +sudo make test-cert # Тест +``` + +--- + +## 🧪 Тестирование (БЕЗ лимитов Let's Encrypt) + +```bash +# Создать тестовый сертификат (неограниченно) +sudo make test-cert + +# Проверить статус +sudo make status + +# Просмотреть логи +sudo make logs +``` + +**Когда использовать:** +- ⚠️ Let's Encrypt: макс. 5 сертификатов/неделю +- ✅ Тестовые: НЕОГРАНИЧЕННО +- ⚡ Создание: 1-2 секунды vs 2-5 минут + +--- + +## 🔒 Production (Let's Encrypt) + +```bash +# Получить настоящий сертификат +sudo make obtain + +# Автоматический режим (проверка + обновление) +sudo make run + +# Принудительное обновление +sudo make renew +``` + +--- + +## 📋 Основные команды + +### Команды letsencrypt-regru + +| Команда | Описание | Лимиты | Использование | +|---------|----------|--------|---------------| +| `--check` | Проверить срок действия | - | Мониторинг | +| `--obtain` | Получить новый сертификат | ⚠️ 5/неделю | Первое создание | +| `--renew` | Обновить существующий | ⚠️ 5/неделю | Продление | +| `--auto` | Авто-проверка и обновление | ⚠️ 5/неделю | Cron/systemd | +| `--test-cert` | Тестовый сертификат | ✅ Нет | Разработка | +| `--test-api` | Проверить API reg.ru | - | Диагностика | +| `--test-dns` | Тест создания DNS записи | - | Проверка перед SSL | +| `--help` | Справка | - | Помощь | +| `-v` | Подробный вывод | - | Отладка | + +### Команды Makefile + +| Команда | Описание | Эквивалент | +|---------|----------|------------| +| `make test-cert` | Тестовый сертификат | `letsencrypt-regru --test-cert` | +| `make obtain` | Let's Encrypt новый | `letsencrypt-regru --obtain` | +| `make renew` | Обновить существующий | `letsencrypt-regru --renew` | +| `make run` | Авто-режим | `letsencrypt-regru --auto` | +| `make status` | Статус системы | - | +| `make logs` | Показать логи | `journalctl -u letsencrypt-regru` | +| `make check-config` | Проверить конфигурацию | - | + +### Команды letsencrypt_regru.sh + +| Команда | Описание | +|---------|----------| +| `sudo bash letsencrypt_regru.sh install` | Установить приложение | +| `sudo bash letsencrypt_regru.sh update` | Обновить приложение | +| `sudo bash letsencrypt_regru.sh uninstall` | Удалить приложение | + +--- + +## 📝 Конфигурация + +### Минимальная (тестирование) +```json +{ + "domain": "test.example.com", + "wildcard": true, + "cert_dir": "/etc/letsencrypt/live" +} +``` + +### Полная (production + NPM) +```json +{ + "regru_username": "myuser", + "regru_password": "mypassword", + "domain": "example.com", + "wildcard": true, + "email": "admin@example.com", + "renewal_days": 30, + "npm_enabled": true, + "npm_host": "https://npm.example.com", + "npm_email": "admin@example.com", + "npm_password": "npm_password" +} +``` + +--- + +## 🔄 Workflow + +### Разработка → Production + +```bash +# 1. Разработка (тестовые сертификаты) +sudo make test-cert # Создать тестовый +# Тестировать приложение... + +# 2. Production (Let's Encrypt) +sudo rm -rf /etc/letsencrypt/live/example.com/ # Удалить тест +sudo make obtain # Создать production +``` + +--- + +## 📁 Важные пути + +```bash +# Конфигурация +/etc/letsencrypt/regru_config.json + +# Сертификаты +/etc/letsencrypt/live/example.com/ +├── privkey.pem # Приватный ключ +├── cert.pem # Сертификат +├── fullchain.pem # Полная цепочка (для nginx) +└── chain.pem # CA цепочка + +# Скрипты +/opt/letsencrypt-regru/letsencrypt_regru_api.py + +# Логи +/var/log/letsencrypt_regru.log +``` + +--- + +## 🔍 Проверка + +```bash +# Проверить конфигурацию +sudo make check-config + +# Проверить сертификат +openssl x509 -in /etc/letsencrypt/live/example.com/cert.pem -text -noout + +# Проверить срок действия +openssl x509 -in /etc/letsencrypt/live/example.com/cert.pem -noout -dates + +# Проверить systemd +sudo systemctl status letsencrypt-regru.timer +sudo systemctl list-timers letsencrypt-regru.timer + +# Проверить cron +sudo crontab -l | grep letsencrypt +``` + +--- + +## 🐛 Отладка + +```bash +# Подробные логи +sudo make logs + +# Тестовый запуск с подробностями +sudo python3 /opt/letsencrypt-regru/letsencrypt_regru_api.py \ + -c /etc/letsencrypt/regru_config.json --check -v + +# Логи certbot +sudo tail -f /var/log/letsencrypt/letsencrypt.log + +# Логи systemd +sudo journalctl -u letsencrypt-regru.service -f +``` + +--- + +## ⚠️ Частые ошибки + +### Let's Encrypt: Rate limit exceeded +```bash +# РЕШЕНИЕ: Используйте тестовые сертификаты +sudo make test-cert +``` + +### NPM: Certificate not found +```bash +# РЕШЕНИЕ: Проверьте настройки NPM +sudo make check-config + +# Проверьте подключение +curl -k https://npm.example.com +``` + +### Permission denied +```bash +# РЕШЕНИЕ: Запускайте с sudo +sudo make test-cert +``` + +--- + +## 🎯 Сценарии использования + +### Локальная разработка +```bash +sudo make test-cert +# Открыть https://localhost (игнорировать предупреждение) +``` + +### CI/CD тестирование +```bash +# В pipeline +sudo make test-cert +# Запустить тесты... +sudo make status +``` + +### Staging окружение +```bash +sudo make test-cert # Или +sudo make obtain # Если есть домен +``` + +### Production окружение +```bash +sudo make install +sudo make obtain +# Автоматическое обновление через cron/systemd +``` + +--- + +## 📚 Документация + +- **README.md** - Полное руководство (1420+ строк) +- **TESTING_GUIDE.md** - Тестирование (370+ строк) +- **PROJECT_STRUCTURE.md** - Структура проекта +- **CHEATSHEET.md** - Эта шпаргалка + +--- + +## 🆘 Быстрая помощь + +```bash +# Показать все команды +make help + +# Проверить установку +sudo make status + +# Полная переустановка +sudo make uninstall +sudo make install +``` + +--- + +## 💡 Советы + +1. **Всегда начинайте с тестовых сертификатов** - избегайте лимитов +2. **Проверяйте конфигурацию** - `make check-config` +3. **Мониторьте логи** - `make logs` +4. **Автоматизируйте** - systemd/cron уже настроены +5. **Храните бэкапы** конфигурации + +--- + +**Версия**: 2.1 +**Обновлено**: 27.10.2025 diff --git a/docs/ru/DESCRIPTION.md b/docs/ru/DESCRIPTION.md new file mode 100644 index 0000000..9696911 --- /dev/null +++ b/docs/ru/DESCRIPTION.md @@ -0,0 +1,133 @@ +# 🔒 SSL Certificate Manager для Let's Encrypt + reg.ru + +**Автоматическое управление SSL сертификатами Let's Encrypt с DNS-валидацией через API reg.ru и интеграцией с Nginx Proxy Manager** + +## 📖 Описание + +Комплексное решение для автоматизации создания, обновления и управления SSL сертификатами Let's Encrypt для доменов, зарегистрированных на reg.ru. Поддерживает DNS-01 валидацию, wildcard сертификаты, автоматическую загрузку в Nginx Proxy Manager и генерацию тестовых сертификатов для разработки. + +### ✨ Основные возможности + +- 🔐 **Автоматическое получение SSL сертификатов** через Let's Encrypt +- 🌐 **DNS-01 валидация** через API reg.ru (поддержка wildcard доменов) +- 🔄 **Автоматическое обновление** сертификатов с настраиваемым порогом +- 📦 **Интеграция с Nginx Proxy Manager** - автоматическая загрузка и обновление +- 🧪 **Тестовые сертификаты** - обход лимитов Let's Encrypt (5 в неделю) +- ⚙️ **Полная автоматизация** через systemd/cron +- 🔀 **Синхронизация репозиториев** - автоматическая синхронизация Gitea → GitHub + +### 🚀 Быстрый старт + +```bash +# Установка через Makefile +sudo make install + +# Настройка конфигурации +sudo nano /etc/letsencrypt/regru_config.json + +# Создание тестового сертификата (без лимитов) +sudo make test-cert + +# Получение production сертификата +sudo make obtain +``` + +### 📋 Требования + +- **ОС**: Linux (Ubuntu/Debian/CentOS) +- **Python**: 3.6+ +- **Зависимости**: certbot, requests, cryptography +- **API**: reg.ru (доступ к DNS управлению) +- **Опционально**: Nginx Proxy Manager + +### 🎯 Сценарии использования + +- ✅ Автоматизация SSL сертификатов для web-серверов +- ✅ Централизованное управление через Nginx Proxy Manager +- ✅ Тестирование и разработка с самоподписанными сертификатами +- ✅ CI/CD интеграция +- ✅ Мультидоменные конфигурации с wildcard + +### 📚 Документация + +- [README.md](README.md) - Полное руководство (1400+ строк) +- [TESTING_GUIDE.md](TESTING_GUIDE.md) - Руководство по тестированию +- [GITEA_SYNC.md](GITEA_SYNC.md) - Синхронизация Gitea → GitHub +- [CHEATSHEET.md](CHEATSHEET.md) - Быстрая шпаргалка + +--- + +## 📖 Description (English) + +**Automated Let's Encrypt SSL Certificate Manager with DNS validation via reg.ru API and Nginx Proxy Manager integration** + +Comprehensive solution for automating the creation, renewal, and management of Let's Encrypt SSL certificates for domains registered with reg.ru. Supports DNS-01 validation, wildcard certificates, automatic upload to Nginx Proxy Manager, and test certificate generation for development. + +### ✨ Key Features + +- 🔐 **Automatic SSL certificate** issuance via Let's Encrypt +- 🌐 **DNS-01 validation** via reg.ru API (wildcard domain support) +- 🔄 **Automatic renewal** with configurable threshold +- 📦 **Nginx Proxy Manager integration** - automatic upload and update +- 🧪 **Test certificates** - bypass Let's Encrypt rate limits (5 per week) +- ⚙️ **Full automation** via systemd/cron +- 🔀 **Repository sync** - automatic Gitea → GitHub synchronization + +### 🚀 Quick Start + +```bash +# Install via Makefile +sudo make install + +# Configure +sudo nano /etc/letsencrypt/regru_config.json + +# Create test certificate (no limits) +sudo make test-cert + +# Get production certificate +sudo make obtain +``` + +### 📋 Requirements + +- **OS**: Linux (Ubuntu/Debian/CentOS) +- **Python**: 3.6+ +- **Dependencies**: certbot, requests, cryptography +- **API**: reg.ru (DNS management access) +- **Optional**: Nginx Proxy Manager + +### 🎯 Use Cases + +- ✅ SSL certificate automation for web servers +- ✅ Centralized management via Nginx Proxy Manager +- ✅ Development and testing with self-signed certificates +- ✅ CI/CD integration +- ✅ Multi-domain configurations with wildcards + +### 📚 Documentation + +- [README.md](README.md) - Complete guide (1400+ lines) +- [TESTING_GUIDE.md](TESTING_GUIDE.md) - Testing guide +- [GITEA_SYNC.md](GITEA_SYNC.md) - Gitea → GitHub sync +- [CHEATSHEET.md](CHEATSHEET.md) - Quick reference + +--- + +## 👤 Автор / Author + +**Фофанов Дмитрий** @ 2025 + +## 📄 Лицензия / License + +Open Source - Free to use + +## 🤝 Вклад / Contributing + +Pull requests приветствуются / Pull requests are welcome! + +## 🔗 Ссылки / Links + +- **Документация reg.ru API**: https://www.reg.ru/support/api +- **Let's Encrypt**: https://letsencrypt.org/ +- **Nginx Proxy Manager**: https://nginxproxymanager.com/ diff --git a/docs/ru/DOCS_INDEX.md b/docs/ru/DOCS_INDEX.md new file mode 100644 index 0000000..6c0208f --- /dev/null +++ b/docs/ru/DOCS_INDEX.md @@ -0,0 +1,111 @@ +# 📚 Documentation Index / Индекс документации + +## 🇷🇺 Русская документация / Russian Documentation + +### Основные руководства / Main Guides +- **[README.md](README.md)** - Полное руководство (1,420+ строк) +- **[TESTING_GUIDE.md](TESTING_GUIDE.md)** - Руководство по тестированию +- **[GITEA_SYNC.md](GITEA_SYNC.md)** - Синхронизация Gitea → GitHub +- **[PROJECT_STRUCTURE.md](PROJECT_STRUCTURE.md)** - Структура проекта + +### Справочная информация / Reference +- **[CHEATSHEET.md](CHEATSHEET.md)** - Быстрая шпаргалка +- **[CHANGELOG.md](CHANGELOG.md)** - История изменений +- **[DESCRIPTION.md](DESCRIPTION.md)** - Описание проекта + +### Git Hooks +- **[gitea-hooks/README.md](gitea-hooks/README.md)** - Установка Git hooks + +--- + +## 🇬🇧 English Documentation / Английская документация + +### Main Guides / Основные руководства +- **[README_EN.md](README_EN.md)** - Complete Guide (Coming Soon) +- **[TESTING_GUIDE_EN.md](TESTING_GUIDE_EN.md)** - Testing Guide ✅ +- **[GITEA_SYNC_EN.md](GITEA_SYNC_EN.md)** - Gitea → GitHub Sync ✅ +- **[PROJECT_STRUCTURE_EN.md](PROJECT_STRUCTURE_EN.md)** - Project Structure ✅ + +### Reference / Справочная информация +- **[CHEATSHEET_EN.md](CHEATSHEET_EN.md)** - Quick Reference ✅ +- **[CHANGELOG_EN.md](CHANGELOG_EN.md)** - Change History ✅ +- **[DESCRIPTION.md](DESCRIPTION.md)** - Project Description (Bilingual) ✅ + +### Git Hooks +- **[gitea-hooks/README_EN.md](gitea-hooks/README_EN.md)** - Git Hooks Installation ✅ + +--- + +## 📖 Quick Links / Быстрые ссылки + +### For Users / Для пользователей +| Topic | Russian | English | +|-------|---------|---------| +| Getting Started | [README.md](README.md) | [README_EN.md](README_EN.md) | +| Testing Certificates | [TESTING_GUIDE.md](TESTING_GUIDE.md) | [TESTING_GUIDE_EN.md](TESTING_GUIDE_EN.md) | +| Quick Commands | [CHEATSHEET.md](CHEATSHEET.md) | [CHEATSHEET_EN.md](CHEATSHEET_EN.md) | + +### For Developers / Для разработчиков +| Topic | Russian | English | +|-------|---------|---------| +| Project Structure | [PROJECT_STRUCTURE.md](PROJECT_STRUCTURE.md) | [PROJECT_STRUCTURE_EN.md](PROJECT_STRUCTURE_EN.md) | +| Repository Sync | [GITEA_SYNC.md](GITEA_SYNC.md) | [GITEA_SYNC_EN.md](GITEA_SYNC_EN.md) | +| Changelog | [CHANGELOG.md](CHANGELOG.md) | [CHANGELOG_EN.md](CHANGELOG_EN.md) | + +--- + +## 🚀 Quick Start / Быстрый старт + +### Installation / Установка +```bash +sudo make install +sudo nano /etc/letsencrypt/regru_config.json +sudo make test-cert +``` + +### Documentation Priority / Приоритет документации +1. Start here / Начните здесь: **README.md** / **README_EN.md** +2. Testing / Тестирование: **TESTING_GUIDE.md** / **TESTING_GUIDE_EN.md** +3. Quick ref / Шпаргалка: **CHEATSHEET.md** / **CHEATSHEET_EN.md** + +--- + +## 📊 Documentation Status / Статус документации + +| File | Russian | English | Lines | Status | +|------|---------|---------|-------|--------| +| Main Guide | ✅ | 🔄 | 1,420+ | RU Complete | +| Testing Guide | ✅ | ✅ | 370+ | Both Complete | +| Cheatsheet | ✅ | ✅ | 200+ | Both Complete | +| Project Structure | ✅ | ✅ | 200+ | Both Complete | +| Gitea Sync | ✅ | ✅ | 400+ | Both Complete | +| Changelog | ✅ | ✅ | 150+ | Both Complete | +| Git Hooks | ✅ | ✅ | 100+ | Both Complete | + +**Legend:** +- ✅ Complete / Готово +- 🔄 In Progress / В разработке +- ❌ Not Started / Не начато + +--- + +## 🎯 Choose Your Language / Выберите язык + +### Prefer Russian? / Предпочитаете русский? +👉 Начните с [README.md](README.md) + +### Prefer English? / Предпочитаете английский? +👉 Start with [README_EN.md](README_EN.md) or [DESCRIPTION.md](DESCRIPTION.md) + +--- + +## 💡 Contributing / Вклад + +Help us translate / Помогите с переводом: +- [ ] Complete README_EN.md / Завершить README_EN.md +- [ ] Translate docs/ folder / Перевести папку docs/ + +--- + +**Last Updated / Обновлено**: October 27, 2025 +**Maintained by / Поддерживает**: Фофанов Дмитрий diff --git a/docs/ru/GITEA_SYNC.md b/docs/ru/GITEA_SYNC.md new file mode 100644 index 0000000..3137fc7 --- /dev/null +++ b/docs/ru/GITEA_SYNC.md @@ -0,0 +1,425 @@ +# 🔄 Синхронизация Gitea → GitHub + +Автоматическая синхронизация репозитория из Gitea в GitHub после каждого push. + +--- + +## 📋 Доступные методы + +| Метод | Сложность | Скорость | Надежность | Рекомендация | +|-------|-----------|----------|------------|--------------| +| **1. Git Hooks** | ⭐⭐ | ⚡ Мгновенно | ✅ Высокая | Рекомендуется | +| **2. GitHub Actions** | ⭐⭐⭐ | ⏱️ 1-5 мин | ✅ Высокая | Для сложных сценариев | +| **3. Gitea Mirror** | ⭐ | ⏱️ По расписанию | ⭐⭐ Средняя | Самый простой | +| **4. Двойной Remote** | ⭐ | ⚡ Мгновенно | ⭐⭐ Средняя | Локальная работа | + +--- + +## 🚀 Метод 1: Git Hooks (Рекомендуется) + +### Установка + +**1. На сервере Gitea найдите путь к репозиторию:** +```bash +# Обычно это: +/var/lib/gitea/data/gitea-repositories/username/configure_nginx_manager.git +# Или +/home/git/gitea-repositories/username/configure_nginx_manager.git +``` + +**2. Создайте post-receive hook:** +```bash +cd /path/to/gitea/repos/username/configure_nginx_manager.git/hooks/ +nano post-receive +``` + +**3. Вставьте содержимое** из файла `gitea-hooks/post-receive` (в этом репозитории) + +**4. Настройте параметры:** +```bash +# В файле post-receive измените: +GITHUB_REPO="git@github.com:YOUR_USERNAME/configure_nginx_manager.git" +# Или для HTTPS с токеном: +GITHUB_REPO="https://YOUR_TOKEN@github.com/YOUR_USERNAME/configure_nginx_manager.git" +``` + +**5. Сделайте скрипт исполняемым:** +```bash +chmod +x post-receive +``` + +**6. Создайте директорию для логов:** +```bash +mkdir -p /var/log/gitea +chown git:git /var/log/gitea +``` + +### Настройка SSH ключей (для git@github.com) + +**На сервере Gitea:** + +**Шаг 1: Определите пользователя Gitea** +```bash +# Проверьте под каким пользователем запущен Gitea +ps aux | grep gitea | grep -v grep + +# Обычно это один из: +# - git (стандартная установка) +# - gitea (установка через Docker/LXC) +``` + +**Шаг 2: Переключитесь на этого пользователя** +```bash +# Попробуйте git: +sudo su - git + +# Если не работает, попробуйте gitea: +sudo su - gitea + +# Проверьте текущего пользователя +whoami # Должно быть: git или gitea +``` + +**Шаг 3: Создайте SSH ключ** +```bash +# Создайте SSH ключ (если его ещё нет) +ssh-keygen -t ed25519 -C "gitea-to-github-sync" -f ~/.ssh/id_ed25519 -N "" + +# Скопируйте публичный ключ +cat ~/.ssh/id_ed25519.pub +``` + +**На GitHub:** +1. Settings → SSH and GPG keys +2. New SSH key +3. Вставьте публичный ключ +4. Save + +**⚠️ ВАЖНО: Добавьте GitHub в known_hosts:** +```bash +# От того же пользователя (git или gitea) +ssh-keyscan -H github.com >> ~/.ssh/known_hosts + +# Проверьте что ключ добавлен +cat ~/.ssh/known_hosts | grep github.com +``` + +**Проверка подключения:** +```bash +ssh -T git@github.com +# Должно вывести: Hi username! You've successfully authenticated... +``` + +### Настройка токена (для HTTPS) + +**На GitHub:** +1. Settings → Developer settings → Personal access tokens → Tokens (classic) +2. Generate new token +3. Выберите scope: `repo` (полный доступ к репозиториям) +4. Скопируйте токен + +**В hook файле:** +```bash +GITHUB_REPO="https://ghp_YOUR_TOKEN_HERE@github.com/username/configure_nginx_manager.git" +``` + +### Тестирование + +```bash +# Сделайте тестовый commit в Gitea +cd /tmp +git clone http://gitea.example.com/username/configure_nginx_manager.git +cd configure_nginx_manager +echo "test" >> README.md +git add README.md +git commit -m "Test sync to GitHub" +git push + +# Проверьте лог +tail -f /var/log/gitea/github-sync.log + +# Проверьте GitHub - изменения должны появиться +``` + +--- + +## 🔄 Метод 2: GitHub Actions + +### Установка + +**1. Создайте workflow в GitHub репозитории:** + +Файл уже создан: `.github/workflows/sync-from-gitea.yml` + +**2. Настройте секреты в GitHub:** + +GitHub Repository → Settings → Secrets and variables → Actions → New repository secret + +Добавьте: +- **Name**: `GITEA_URL` + - **Value**: `https://gitea.example.com/username/configure_nginx_manager.git` + +- **Name**: `GITEA_TOKEN` + - **Value**: Токен доступа Gitea + +### Получение токена Gitea + +**В Gitea:** +1. Settings → Applications → Generate New Token +2. Token Name: "GitHub Sync" +3. Select permissions: `read:repository` +4. Generate Token +5. Скопируйте токен + +### Запуск синхронизации + +**Автоматически (по расписанию):** +- Каждый час проверяет изменения + +**Вручную:** +1. GitHub → Actions +2. Выберите workflow "Sync from Gitea" +3. Run workflow + +**Через webhook от Gitea:** + +В Gitea репозитории: +1. Settings → Webhooks → Add Webhook → Gitea +2. Target URL: `https://api.github.com/repos/USERNAME/configure_nginx_manager/dispatches` +3. HTTP Method: `POST` +4. POST Content Type: `application/json` +5. Secret: оставьте пустым или используйте +6. Trigger On: `Push events` +7. Body: +```json +{ + "event_type": "gitea-push" +} +``` + +--- + +## 🪞 Метод 3: Gitea Mirror (Встроенная функция) + +### Настройка + +**В Gitea репозитории:** +1. Settings → Repository +2. Прокрутите до "Mirror Settings" +3. Нажмите "Add Push Mirror" +4. Заполните: + - **Git Remote Repository URL**: `https://github.com/username/configure_nginx_manager.git` + - **Username**: ваш GitHub username + - **Password**: GitHub Personal Access Token + - **Sync Interval**: `8h` (каждые 8 часов) или `0` (только вручную) +5. Save + +### Ручная синхронизация + +Settings → Repository → Mirror Settings → Sync Now + +### Преимущества +- ✅ Встроенная функция +- ✅ Не требует скриптов +- ✅ Управление через веб-интерфейс + +### Недостатки +- ⚠️ Работает по расписанию (не мгновенно) +- ⚠️ Доступно не во всех версиях Gitea + +--- + +## 🔀 Метод 4: Двойной Remote + +### Для локальной работы + +**Настройка:** +```bash +# В вашем локальном репозитории +cd configure_nginx_manager + +# Добавьте GitHub как второй remote +git remote add github git@github.com:username/configure_nginx_manager.git + +# Или настройте push в оба репозитория одновременно +git remote set-url --add --push origin git@github.com:username/configure_nginx_manager.git + +# Проверьте +git remote -v +``` + +**Использование:** +```bash +# Обычный push (только в Gitea) +git push origin main + +# Push в GitHub +git push github main + +# Push в оба репозитория +git push origin main +git push github main + +# Или создайте alias +git config alias.pushall '!git push origin main && git push github main' +git pushall +``` + +--- + +## 🔍 Проверка синхронизации + +### Проверка через Git + +```bash +# Сравнить коммиты +git ls-remote git@gitea.example.com:username/configure_nginx_manager.git +git ls-remote git@github.com:username/configure_nginx_manager.git + +# Должны быть одинаковые SHA +``` + +### Проверка логов (Метод 1 - Hooks) + +```bash +# На сервере Gitea +tail -f /var/log/gitea/github-sync.log +``` + +### Проверка GitHub Actions (Метод 2) + +1. GitHub Repository → Actions +2. Смотрите последние запуски +3. Проверьте логи выполнения + +--- + +## ⚙️ Рекомендованная конфигурация + +Для максимальной надежности используйте **комбинацию методов**: + +1. **Git Hook** (основной) - мгновенная синхронизация +2. **GitHub Actions** (резервный) - проверка каждый час на случай сбоя hook + +### Установка обоих методов + +```bash +# 1. Установите Git Hook на сервере Gitea +# (см. Метод 1) + +# 2. Настройте GitHub Actions +# (см. Метод 2) + +# 3. GitHub Actions будет подхватывать пропущенные изменения +``` + +--- + +## 🐛 Устранение проблем + +### Проблема: Hook не срабатывает + +**Проверка:** +```bash +# На сервере Gitea +ls -la /path/to/repo.git/hooks/post-receive +# Должно быть -rwxr-xr-x + +# Проверьте права +chmod +x /path/to/repo.git/hooks/post-receive +chown git:git /path/to/repo.git/hooks/post-receive + +# Проверьте лог ошибок Gitea +tail -f /var/log/gitea/gitea.log +``` + +### Проблема: Permission denied (SSH) + +**Решение:** +```bash +# Убедитесь что SSH ключ добавлен в GitHub +ssh -T git@github.com + +# Проверьте права на .ssh +chmod 700 ~/.ssh +chmod 600 ~/.ssh/id_ed25519 +``` + +### Проблема: Authentication failed (HTTPS) + +**Решение:** +- Проверьте токен GitHub (должен иметь scope `repo`) +- Токен не истёк +- Правильный формат URL: `https://TOKEN@github.com/user/repo.git` + +### Проблема: GitHub Actions не запускается + +**Решение:** +1. Проверьте секреты в Settings → Secrets +2. Проверьте формат webhook от Gitea +3. Запустите вручную для теста + +--- + +## 📊 Сравнение методов + +### Скорость синхронизации +- **Git Hooks**: ⚡ < 1 секунды +- **GitHub Actions (webhook)**: ⏱️ 10-30 секунд +- **GitHub Actions (schedule)**: ⏱️ до 1 часа +- **Gitea Mirror**: ⏱️ по расписанию + +### Надежность +- **Git Hooks**: ⭐⭐⭐⭐⭐ (при правильной настройке) +- **GitHub Actions**: ⭐⭐⭐⭐⭐ (очень надежно) +- **Gitea Mirror**: ⭐⭐⭐ (зависит от версии Gitea) +- **Двойной Remote**: ⭐⭐ (требует ручного действия) + +--- + +## 🎯 Итоговая рекомендация + +Для проекта `configure_nginx_manager`: + +**1. Основной метод: Git Hook** +- Быстро +- Надежно +- Автоматически + +**2. Резервный метод: GitHub Actions** +- Проверка каждый час +- Подхватит пропущенные изменения +- Можно запустить вручную + +**3. Мониторинг:** +```bash +# Еженедельная проверка +git ls-remote origin | head -1 +git ls-remote github | head -1 +# SHA должны совпадать +``` + +--- + +## 📝 Быстрая установка + +```bash +# На сервере Gitea +sudo su - git +cd /path/to/gitea-repositories/username/configure_nginx_manager.git/hooks/ + +# Скачайте hook +wget https://raw.githubusercontent.com/username/configure_nginx_manager/main/gitea-hooks/post-receive + +# Настройте +nano post-receive +# Измените GITHUB_REPO + +# Права +chmod +x post-receive + +# Тест +echo "test" | ./post-receive +``` + +Готово! 🎉 diff --git a/docs/ru/INSTALL_GUIDE.md b/docs/ru/INSTALL_GUIDE.md new file mode 100644 index 0000000..cd3e433 --- /dev/null +++ b/docs/ru/INSTALL_GUIDE.md @@ -0,0 +1,415 @@ +# Руководство по использованию letsencrypt_regru.sh + +**Автор:** Фофанов Дмитрий +**Дата:** 28.10.2025 + +## Описание + +`letsencrypt_regru.sh` - это автоматический установщик для Let's Encrypt Manager с интеграцией reg.ru и Nginx Proxy Manager. + +Скрипт автоматизирует: +- Установку всех системных зависимостей +- Создание виртуального окружения Python +- Установку Python библиотек (requests, cryptography, certbot) +- Интерактивную настройку конфигурации +- Создание и настройку systemd сервисов +- Настройку автоматического обновления сертификатов + +## Требования + +- Linux (Debian/Ubuntu, CentOS/RHEL/Fedora) +- Root доступ (sudo) +- Минимум 512MB RAM +- Минимум 1GB свободного места на диске +- Интернет соединение + +## Быстрая установка + +**Способ 1: Автоматическая установка (рекомендуется)** + +Самый быстрый способ - запустить установку напрямую с GitHub: + +```bash +sudo bash -c "$(curl -fsSL https://github.com/DFofanov/configure_nginx_manager/raw/refs/heads/master/letsencrypt_regru.sh)" +``` + +Эта команда: +- Автоматически скачает установочный скрипт +- Запустит его с правами root +- Проведет через интерактивную настройку + +**Способ 2: Через клонирование репозитория** + +Если вы хотите изучить код перед установкой: + +```bash +# 1. Скачайте репозиторий +git clone https://github.com/DFofanov/configure_nginx_manager.git +cd configure_nginx_manager + +# 2. Дайте права на выполнение +chmod +x letsencrypt_regru.sh + +# 3. Запустите установку +sudo ./letsencrypt_regru.sh +``` + +## Интерактивная настройка + +Во время установки скрипт спросит: + +1. **Домен** - ваш основной домен (например, `example.com`) +2. **Email** - для уведомлений Let's Encrypt +3. **Учетные данные reg.ru:** + - Имя пользователя + - Пароль +4. **Wildcard сертификат** - создавать ли `*.example.com` (рекомендуется: Да) +5. **Интеграция с NPM** (опционально): + - Адрес NPM (например, `http://10.10.10.14:81`) + - Email для входа в NPM + - Пароль NPM + +## Структура после установки + +``` +/opt/letsencrypt-regru/ # Приложение +├── letsencrypt_regru_api.py # Основной скрипт +├── venv/ # Виртуальное окружение Python +└── docs/ # Документация + +/etc/letsencrypt-regru/ # Конфигурация +└── config.json # Настройки (credentials, домен, NPM) + +/var/log/letsencrypt-regru/ # Логи +└── letsencrypt_regru.log + +/etc/letsencrypt/live/ # Сертификаты Let's Encrypt +└── example.com/ + ├── privkey.pem + ├── cert.pem + ├── chain.pem + └── fullchain.pem + +/etc/systemd/system/ # Systemd сервисы +├── letsencrypt-regru.service # Сервис обновления +└── letsencrypt-regru.timer # Таймер (каждые 12 часов) + +/usr/local/bin/ +└── letsencrypt-regru # Глобальная команда +``` + +## Использование команды letsencrypt-regru + +После установки доступна удобная глобальная команда с множеством функций: + +### 🔧 Основные команды + +```bash +# Проверить срок действия текущего сертификата +letsencrypt-regru --check + +# Получить новый сертификат Let's Encrypt +letsencrypt-regru --obtain + +# Обновить существующий сертификат +letsencrypt-regru --renew + +# Автоматически проверить и обновить при необходимости +letsencrypt-regru --auto + +# Создать тестовый самоподписанный сертификат +letsencrypt-regru --test-cert +``` + +### 🧪 Команды диагностики и тестирования + +```bash +# Проверить доступ к API reg.ru +# - Показывает текущий IP +# - Тестирует подключение к API +# - Отображает баланс аккаунта +letsencrypt-regru --test-api + +# Тестовое создание DNS записи TXT +# - Полная симуляция процесса SSL сертификации +# - Создает временную TXT запись _acme-challenge +# - Ожидает распространения DNS (60 секунд) +# - Проверяет через публичные DNS серверы +# - Автоматически удаляет тестовую запись +letsencrypt-regru --test-dns + +# Показать справку по всем командам +letsencrypt-regru --help + +# Включить подробный вывод (verbose mode) +letsencrypt-regru --obtain -v +letsencrypt-regru --check -v +``` + +### ⚙️ Служебные команды (внутреннее использование) + +```bash +# Certbot authentication hook (используется certbot автоматически) +letsencrypt-regru --auth-hook + +# Certbot cleanup hook (используется certbot автоматически) +letsencrypt-regru --cleanup-hook +``` + +### 📋 Описание команд + +| Команда | Описание | Использование | +|---------|----------|---------------| +| `--check` | Проверяет срок действия сертификата | Регулярная проверка | +| `--obtain` | Получает новый сертификат от Let's Encrypt | Первое создание | +| `--renew` | Обновляет существующий сертификат | Продление срока | +| `--auto` | Автоматическая проверка и обновление | Для cron/systemd | +| `--test-cert` | Создает тестовый самоподписанный сертификат | Разработка/тестирование | +| `--test-api` | Проверяет доступ к API reg.ru | Диагностика подключения | +| `--test-dns` | Тестирует создание DNS записи | Проверка перед SSL | +| `--auth-hook` | Hook для certbot (создание DNS) | Внутреннее | +| `--cleanup-hook` | Hook для certbot (удаление DNS) | Внутреннее | +| `--help` | Показывает справку | Помощь | +| `-v` | Подробный вывод | Отладка | + +## Автоматическое обновление + +Установщик настраивает systemd timer для автоматической проверки: + +```bash +# Проверить статус таймера +systemctl status letsencrypt-regru.timer + +# Когда следующий запуск +systemctl list-timers letsencrypt-regru.timer + +# Посмотреть историю запусков +journalctl -u letsencrypt-regru + +# Следить за логами в реальном времени +journalctl -u letsencrypt-regru -f +``` + +### Настройки таймера + +По умолчанию: +- Первый запуск: через 15 минут после загрузки системы +- Периодичность: каждые 12 часов +- Случайная задержка: до 1 часа (чтобы не создавать нагрузку) + +Изменить можно в `/etc/systemd/system/letsencrypt-regru.timer`. + +## Редактирование конфигурации + +```bash +# Открыть конфигурацию в редакторе +sudo nano /etc/letsencrypt-regru/config.json + +# После изменений перезапустите таймер +sudo systemctl restart letsencrypt-regru.timer +``` + +### Пример config.json + +```json +{ + "regru_username": "your_username", + "regru_password": "your_password", + "domain": "example.com", + "wildcard": true, + "email": "admin@example.com", + "cert_dir": "/etc/letsencrypt/live", + "log_file": "/var/log/letsencrypt-regru/letsencrypt_regru.log", + "dns_propagation_wait": 60, + "dns_check_attempts": 10, + "dns_check_interval": 10, + "renewal_days": 30, + "npm_enabled": true, + "npm_host": "http://10.10.10.14:81", + "npm_email": "admin@npm.local", + "npm_password": "secure_password" +} +``` + +## Обновление приложения + +```bash +# Скачайте последнюю версию +cd configure_nginx_manager +git pull + +# Запустите обновление +sudo ./letsencrypt_regru.sh update +``` + +Обновление: +- Остановит таймер +- Обновит скрипт +- Обновит Python зависимости +- Перезапустит таймер + +## Удаление + +```bash +# Полное удаление приложения +sudo ./letsencrypt_regru.sh uninstall +``` + +Скрипт удалит: +- Приложение из `/opt/letsencrypt-regru/` +- Systemd сервисы +- Глобальную команду + +Сертификаты в `/etc/letsencrypt/live/` сохраняются! + +Опционально можно удалить: +- Конфигурацию `/etc/letsencrypt-regru/` +- Логи `/var/log/letsencrypt-regru/` + +## Просмотр логов + +```bash +# Логи systemd (рекомендуется) +journalctl -u letsencrypt-regru -f + +# Файл лога +tail -f /var/log/letsencrypt-regru/letsencrypt_regru.log + +# Последние 100 строк +tail -n 100 /var/log/letsencrypt-regru/letsencrypt_regru.log +``` + +## Устранение проблем + +### Проверка установки + +```bash +# Проверить наличие команды +which letsencrypt-regru + +# Проверить Python окружение +ls -la /opt/letsencrypt-regru/venv/ + +# Проверить systemd сервисы +systemctl list-unit-files | grep letsencrypt-regru +``` + +### Ошибки при установке + +**Ошибка: "Permission denied"** +```bash +# Запустите с sudo +sudo ./letsencrypt_regru.sh +``` + +**Ошибка: "Package not found"** +```bash +# Обновите списки пакетов +sudo apt-get update # Debian/Ubuntu +sudo yum update # CentOS/RHEL +``` + +**Ошибка: "Python module not found"** +```bash +# Переустановите виртуальное окружение +sudo rm -rf /opt/letsencrypt-regru/venv +sudo ./letsencrypt_regru.sh +``` + +### Проблемы с сертификатами + +**Сертификат не создается** +```bash +# Проверьте логи +tail -n 50 /var/log/letsencrypt-regru/letsencrypt_regru.log + +# Проверьте конфигурацию +cat /etc/letsencrypt-regru/config.json + +# Попробуйте вручную +letsencrypt-regru --obtain -v +``` + +**DNS не обновляется** +```bash +# Увеличьте время ожидания в config.json +"dns_propagation_wait": 120, +"dns_check_attempts": 20 +``` + +### Проблемы с NPM + +**Не загружается в NPM** +```bash +# Проверьте доступность NPM +curl http://192.168.10.14:81 + +# Проверьте учетные данные в config.json +# Попробуйте вручную +letsencrypt-regru --test-cert -v +``` + +## Поддерживаемые ОС + +✅ Debian 10, 11, 12 +✅ Ubuntu 20.04, 22.04, 24.04 +✅ CentOS 7, 8 +✅ RHEL 7, 8, 9 +✅ Fedora 35+ + +## Дополнительные возможности + +### Тестовый сертификат + +Для тестирования без лимитов Let's Encrypt: + +```bash +letsencrypt-regru --test-cert +``` + +Создаст самоподписанный сертификат на 90 дней. + +### Ручной запуск обновления + +```bash +# Запустить сервис вручную +sudo systemctl start letsencrypt-regru.service + +# Посмотреть статус +systemctl status letsencrypt-regru.service +``` + +### Изменить периодичность проверки + +Отредактируйте `/etc/systemd/system/letsencrypt-regru.timer`: + +```ini +[Timer] +# Каждые 6 часов вместо 12 +OnUnitActiveSec=6h +``` + +Затем: +```bash +sudo systemctl daemon-reload +sudo systemctl restart letsencrypt-regru.timer +``` + +## Безопасность + +- Конфигурация с паролями имеет права `600` (только root) +- Приватные ключи сертификатов имеют права `600` +- Все операции выполняются от root +- Логи доступны только root + +## Поддержка + +- GitHub Issues: https://github.com/YOUR_USERNAME/configure_nginx_manager/issues +- Документация: `/opt/letsencrypt-regru/docs/` +- Email: admin@dfv24.com + +--- + +**Разработано:** Фофанов Дмитрий +**Дата:** 28.10.2025 +**Версия:** 2.0 diff --git a/docs/ru/MAKEFILE_COMMANDS.md b/docs/ru/MAKEFILE_COMMANDS.md new file mode 100644 index 0000000..eaeb374 --- /dev/null +++ b/docs/ru/MAKEFILE_COMMANDS.md @@ -0,0 +1,154 @@ +# Makefile Commands - Quick Reference + +## 📋 Категории команд + +### 🛠️ Установка и развертывание + +```bash +make install # Полная установка приложения +make uninstall # Удаление приложения +make status # Проверка статуса установки +make check-config # Проверка конфигурации +``` + +### 🔨 Сборка исполняемых файлов + +```bash +make build # Собрать для текущей ОС +make build-linux # Собрать для Linux +make build-windows # Собрать для Windows +make build-all # Собрать для всех платформ +``` + +### 📦 Создание пакетов + +```bash +make package-linux # Создать tar.gz для Linux +make package-windows # Создать zip для Windows +make release # Полный цикл релиза +``` + +### 🧪 Тестирование + +```bash +make test-run # Тестовый запуск скрипта +make test-cert # Создать тестовый сертификат +make test-build # Протестировать собранный файл +``` + +### 🚀 Запуск операций + +```bash +make run # Автоматическая проверка и обновление +make obtain # Получить новый сертификат +make renew # Обновить существующий сертификат +``` + +### 📊 Мониторинг + +```bash +make logs # Показать логи +make status # Статус служб +``` + +### 🧹 Очистка + +```bash +make clean # Очистить временные файлы Python +make clean-build # Очистить артефакты сборки +``` + +### ℹ️ Информация + +```bash +make help # Показать справку +make build-info # Информация о среде сборки +``` + +--- + +## 🎯 Типовые сценарии + +### Первоначальная установка +```bash +sudo make install +sudo make check-config +sudo make test-run +``` + +### Сборка релиза для GitHub +```bash +make clean-build +make release +# Файлы будут в dist/ +``` + +### Создание тестового окружения +```bash +sudo make install +sudo make test-cert +sudo make status +``` + +### Обновление сертификата вручную +```bash +sudo make run +sudo make logs +``` + +### Удаление приложения +```bash +sudo make uninstall +``` + +--- + +## 📝 Переменные окружения + +Основные переменные определены в Makefile: + +```makefile +INSTALL_DIR = /opt/letsencrypt-regru +CONFIG_FILE = /etc/letsencrypt/regru_config.json +LOG_FILE = /var/log/letsencrypt_regru.log +SERVICE_NAME = letsencrypt-regru +PYTHON = python3 +``` + +--- + +## 🔐 Требуемые права + +**Требуют sudo:** +- `make install` +- `make uninstall` +- `make run` +- `make obtain` +- `make renew` +- `make test-run` +- `make test-cert` + +**Не требуют sudo:** +- `make build*` +- `make package*` +- `make clean*` +- `make help` +- `make build-info` + +--- + +## 💡 Полезные комбинации + +```bash +# Полная переустановка +sudo make uninstall && sudo make install + +# Сборка и тестирование +make build && make test-build + +# Очистка и релиз +make clean-build && make release + +# Проверка после установки +sudo make status && sudo make test-run && sudo make logs +``` diff --git a/docs/ru/PROJECT_STRUCTURE.md b/docs/ru/PROJECT_STRUCTURE.md new file mode 100644 index 0000000..cd189d4 --- /dev/null +++ b/docs/ru/PROJECT_STRUCTURE.md @@ -0,0 +1,258 @@ +# 📁 Структура проекта configure_nginx_manager + +## Основные скрипты + +### Python (Рекомендуется) +- **letsencrypt_regru_api.py** (1,411 строк) + - Полнофункциональный Python скрипт + - Прямая работа с API reg.ru + - Интеграция с Nginx Proxy Manager + - Автоматическая проверка и обновление сертификатов + - Генерация тестовых самоподписанных сертификатов + - Поддержка wildcard доменов + +### Bash +- **letsencrypt_regru_dns.sh** + - Bash скрипт с certbot-dns-regru плагином + - Простота использования + - Минимальные зависимости + +### PowerShell +- **letsencrypt_regru.ps1** + - Windows версия + - Аналогична Bash скрипту + +### Тестирование +- **test_certificate.sh** + - Быстрое создание тестовых сертификатов через OpenSSL + - Автономная работа без Python + - Поддержка wildcard доменов + +## Автоматизация + +### Makefile +- **Makefile** (415 строк) + - `make install` - Полная установка и настройка + - `make uninstall` - Чистое удаление + - `make status` - Проверка состояния + - `make test-cert` - Создание тестового сертификата + - `make obtain` - Получение Let's Encrypt сертификата + - `make renew` - Обновление сертификата + - `make logs` - Просмотр логов + - `make check-config` - Валидация конфигурации + +## Конфигурация + +### config.json.example +Пример конфигурации со всеми параметрами: +- Учетные данные reg.ru API +- Настройки домена и email +- Параметры обновления (renewal_days) +- Настройки Nginx Proxy Manager +- Пути к директориям и логам + +## Документация + +### README.md (1,420+ строк) +Основная документация: +- Введение и возможности +- Быстрый старт +- Установка через Makefile +- Создание тестовых сертификатов +- Требования и установка зависимостей +- Настройка и использование +- Интеграция с NPM +- Автоматическая проверка и обновление +- Автоматизация через cron/systemd +- Устранение неполадок + +### TESTING_GUIDE.md (370+ строк) +Руководство по тестированию: +- Зачем нужны тестовые сертификаты +- Обход лимитов Let's Encrypt (5 в неделю) +- Быстрый старт с тестовыми сертификатами +- Сравнение методов создания +- Использование в разработке +- Автоматизация тестирования +- Переход с тестовых на production +- Частые вопросы +- Примеры для CI/CD и Docker + +### GITEA_SYNC.md +Синхронизация Gitea → GitHub: +- 4 метода синхронизации (Git Hooks, GitHub Actions, Gitea Mirror, Double Remote) +- Пошаговые инструкции установки +- Настройка SSH и токенов +- Webhook интеграция +- Устранение проблем +- Сравнение методов + +### CHEATSHEET.md +Быстрая шпаргалка: +- Основные команды +- Workflow разработки +- Сценарии использования +- Частые ошибки и решения +- Проверка и отладка + +### PROJECT_STRUCTURE.md (этот файл) +- Описание всех файлов проекта +- Краткая характеристика каждого компонента + +### CHANGELOG.md +История изменений: +- Версии и обновления +- Новые возможности +- Исправления +- Roadmap + +## Интеграция с Git + +### .github/workflows/sync-from-gitea.yml +GitHub Actions для синхронизации: +- Автоматическая проверка каждый час +- Webhook триггер от Gitea +- Ручной запуск +- Merge изменений из Gitea +- Push в GitHub + +### gitea-hooks/ +Git hooks для Gitea сервера: + +**post-receive** +- Автоматический push в GitHub после commit +- Мгновенная синхронизация (< 1 секунды) +- Логирование операций +- Синхронизация тегов +- Поддержка SSH и HTTPS + +**README.md** +- Инструкции по установке hook +- Настройка аутентификации +- Устранение проблем + +## Вспомогательные файлы + +### Markdown документы +- **Add Let's Encrypt Certificate для провайдера reg.ru.md** + - Первоначальные инструкции + +- **Создание и продление SSL сертификата.md** + - Дополнительная информация о процессе + +## Возможности + +### ✅ Основные +- [x] Создание Let's Encrypt сертификатов через reg.ru DNS API +- [x] Wildcard сертификаты (*.domain.com) +- [x] Автоматическое обновление сертификатов +- [x] DNS-01 валидация +- [x] Интеграция с Nginx Proxy Manager +- [x] Автоматическая загрузка/обновление в NPM + +### ✅ Продвинутые +- [x] Автоматическая проверка срока действия +- [x] Настраиваемый порог обновления (renewal_days) +- [x] Systemd service + timer +- [x] Cron автоматизация +- [x] Подробное логирование +- [x] Валидация конфигурации + +### 🆕 Тестирование +- [x] Генерация самоподписанных тестовых сертификатов +- [x] Обход лимитов Let's Encrypt (5/неделю) +- [x] Мгновенное создание без DNS +- [x] Интеграция тестовых сертификатов с NPM +- [x] Полная совместимость структуры с Let's Encrypt + +### 🔄 Синхронизация репозиториев +- [x] Автоматическая синхронизация Gitea → GitHub +- [x] Git Hooks (мгновенная синхронизация) +- [x] GitHub Actions (проверка каждый час) +- [x] Webhook интеграция +- [x] SSH и HTTPS аутентификация + +## Установка + +### Быстрая установка +```bash +sudo make install +sudo nano /etc/letsencrypt/regru_config.json +sudo make test-cert # Для тестирования +sudo make obtain # Для production +``` + +### Структура после установки +``` +/opt/letsencrypt-regru/ +├── letsencrypt_regru_api.py + +/etc/letsencrypt/ +├── regru_config.json +└── live/ + └── example.com/ + ├── privkey.pem + ├── cert.pem + ├── fullchain.pem + └── chain.pem + +/etc/systemd/system/ +├── letsencrypt-regru.service +└── letsencrypt-regru.timer + +/var/log/letsencrypt/ +└── letsencrypt_regru.log +``` + +## Использование + +### Тестирование (без лимитов) +```bash +sudo make test-cert # Создать тестовый сертификат +sudo make status # Проверить статус +``` + +### Production +```bash +sudo make obtain # Получить Let's Encrypt сертификат +sudo make renew # Обновить сертификат +sudo make run # Автоматический режим +``` + +### Мониторинг +```bash +sudo make logs # Просмотр логов +sudo make status # Статус служб +sudo make check-config # Проверка конфигурации +``` + +## Технологии + +- **Python 3.6+** - Основной язык +- **Certbot** - Let's Encrypt клиент +- **requests** - HTTP запросы к API +- **cryptography** - Генерация тестовых сертификатов +- **systemd** - Автоматизация запуска +- **cron** - Альтернативная автоматизация +- **Make** - Управление установкой +- **OpenSSL** - Альтернативная генерация сертификатов + +## Лицензия + +Open Source - свободное использование + +## Автор + +Фофанов Дмитрий @ 2025 + +## Поддержка + +См. документацию: +- [README.md](README.md) - Основное руководство +- [TESTING_GUIDE.md](TESTING_GUIDE.md) - Руководство по тестированию + +--- + +**Версия**: 2.1 +**Дата**: 27 октября 2025 +**Статус**: ✅ Production Ready diff --git a/docs/ru/QUICKSTART_BUILD.md b/docs/ru/QUICKSTART_BUILD.md new file mode 100644 index 0000000..3732f96 --- /dev/null +++ b/docs/ru/QUICKSTART_BUILD.md @@ -0,0 +1,111 @@ +# 🎯 Быстрый старт - Сборка исполняемых файлов + +Это краткое руководство для тех, кто хочет быстро собрать исполняемый файл. + +## Для Linux + +### 1. Установите зависимости +```bash +sudo apt-get update +sudo apt-get install -y python3 python3-pip git make +``` + +### 2. Клонируйте репозиторий +```bash +git clone https://github.com/DFofanov/configure_nginx_manager.git +cd configure_nginx_manager +``` + +### 3. Соберите +```bash +make build-linux +``` + +### 4. Результат +```bash +ls -lh dist/letsencrypt-regru +# Исполняемый файл готов! +``` + +### 5. Установите (опционально) +```bash +sudo cp dist/letsencrypt-regru /usr/local/bin/ +sudo chmod +x /usr/local/bin/letsencrypt-regru +``` + +### 6. Используйте +```bash +letsencrypt-regru --help +``` + +--- + +## Для Windows + +### 1. Установите Python +Скачайте с [python.org](https://www.python.org/downloads/) и установите + +### 2. Клонируйте репозиторий +```powershell +git clone https://github.com/DFofanov/configure_nginx_manager.git +cd configure_nginx_manager +``` + +### 3. Соберите +```powershell +make build-windows +``` + +### 4. Результат +```powershell +dir dist\letsencrypt-regru.exe +# Исполняемый файл готов! +``` + +### 5. Используйте +```powershell +.\dist\letsencrypt-regru.exe --help +``` + +--- + +## Создание релиза для обеих платформ + +```bash +# Это создаст пакеты для Linux и Windows +make release +``` + +**Результат в `dist/`:** +- `letsencrypt-regru-linux-x86_64.tar.gz` +- `letsencrypt-regru-windows-x86_64.zip` + +--- + +## Полезные команды + +```bash +# Показать справку по всем командам +make help + +# Информация о среде сборки +make build-info + +# Протестировать собранный файл +make test-build + +# Очистить артефакты +make clean-build +``` + +--- + +## ❓ Проблемы? + +См. [BUILD_GUIDE.md](BUILD_GUIDE.md) для подробных инструкций и решения проблем. + +--- + +**Размер файла:** ~40-60 MB (включая Python runtime) +**Время сборки:** ~2-5 минут +**Требования:** Python 3.8+, PyInstaller diff --git a/docs/ru/RELEASE_GUIDE.md b/docs/ru/RELEASE_GUIDE.md new file mode 100644 index 0000000..e647e91 --- /dev/null +++ b/docs/ru/RELEASE_GUIDE.md @@ -0,0 +1,173 @@ +# 🎯 Краткое руководство: Автоматические релизы + +## Для GitHub + +### 1. Создание релиза + +```bash +# Создать тег +git tag -a v1.0.0 -m "Release version 1.0.0" + +# Отправить тег +git push origin v1.0.0 +``` + +### 2. Что произойдет автоматически + +GitHub Actions запустит `.github/workflows/build-release.yml`: + +1. ✅ Сборка Linux версии (Ubuntu runner) +2. ✅ Сборка Windows версии (Windows runner) +3. ✅ Создание пакетов +4. ✅ Генерация SHA256 checksums +5. ✅ Создание GitHub Release +6. ✅ Загрузка артефактов + +### 3. Результат + +Релиз появится на: `https://github.com/USER/REPO/releases/tag/v1.0.0` + +**Файлы:** +- `letsencrypt-regru-linux-x86_64.tar.gz` +- `letsencrypt-regru-linux-x86_64.tar.gz.sha256` +- `letsencrypt-regru-windows-x86_64.zip` +- `letsencrypt-regru-windows-x86_64.zip.sha256` + +--- + +## Для Gitea + +### 1. Настройка (один раз) + +#### Включить Actions в Gitea: + +Отредактируйте `app.ini`: + +```ini +[actions] +ENABLED = true +DEFAULT_ACTIONS_URL = https://gitea.com +``` + +#### Установить Gitea Runner: + +```bash +# Скачать +wget https://dl.gitea.com/act_runner/latest/act_runner-linux-amd64 -O act_runner +chmod +x act_runner + +# Зарегистрировать +./act_runner register --no-interactive \ + --instance https://your-gitea.com \ + --token YOUR_RUNNER_TOKEN + +# Запустить +./act_runner daemon +``` + +### 2. Создание релиза + +```bash +# Создать тег +git tag -a v1.0.0 -m "Release version 1.0.0" + +# Отправить тег +git push origin v1.0.0 +``` + +### 3. Что произойдет + +Gitea Actions запустит `.gitea/workflows/release.yml`: + +1. ✅ Сборка Linux версии +2. ✅ Сборка Windows версии +3. ✅ Создание пакетов +4. ✅ Генерация SHA256 + MD5 checksums +5. ✅ Создание Gitea Release +6. ✅ Детальные release notes + +### 4. Результат + +Релиз появится на: `https://your-gitea.com/USER/REPO/releases/tag/v1.0.0` + +--- + +## 🔧 Проверка перед релизом + +```bash +# 1. Локальная сборка +make clean-build +make release + +# 2. Тестирование +make test-build + +# 3. Проверка файлов +ls -lh dist/ + +# 4. Если все OK - создать тег +git tag -a v1.0.0 -m "Release 1.0.0" +git push origin v1.0.0 +``` + +--- + +## 📊 Мониторинг + +### GitHub: +`https://github.com/USER/REPO/actions` + +### Gitea: +`https://your-gitea.com/USER/REPO/actions` + +--- + +## 🐛 Если что-то пошло не так + +### Удалить тег и релиз: + +```bash +# Удалить локальный тег +git tag -d v1.0.0 + +# Удалить удаленный тег +git push --delete origin v1.0.0 + +# Удалить релиз вручную через веб-интерфейс +``` + +### Пересоздать релиз: + +```bash +# Исправить проблему +git commit -am "Fix build" + +# Пересоздать тег +git tag -a v1.0.0 -m "Release 1.0.0" --force +git push origin v1.0.0 --force +``` + +--- + +## 📝 Semantic Versioning + +```bash +# Major (несовместимые изменения) +git tag v2.0.0 + +# Minor (новые функции) +git tag v1.1.0 + +# Patch (исправления) +git tag v1.0.1 + +# Pre-release +git tag v1.0.0-beta.1 +git tag v1.0.0-rc.1 +``` + +--- + +**См. также:** +- [.gitea/README.md](.gitea/README.md) - Полная документация по Gitea Actions +- [BUILD_GUIDE.md](BUILD_GUIDE.md) - Руководство по сборке diff --git a/docs/ru/SSL_SCRIPTS_README.md b/docs/ru/SSL_SCRIPTS_README.md new file mode 100644 index 0000000..5627e77 --- /dev/null +++ b/docs/ru/SSL_SCRIPTS_README.md @@ -0,0 +1,170 @@ +# Автоматизация SSL сертификатов Let's Encrypt для reg.ru + +Набор скриптов для автоматического создания и обновления SSL сертификатов Let's Encrypt с использованием DNS-валидации через API reg.ru. + +## 📁 Содержимое проекта + +- **letsencrypt_regru_dns.sh** - Bash скрипт (Linux) с certbot-dns-regru +- **letsencrypt_regru_api.py** - Python скрипт с прямым API интеграцией +- **letsencrypt_regru.ps1** - PowerShell скрипт (Windows) +- **config.json.example** - Пример файла конфигурации +- **USAGE.md** - Подробная инструкция по использованию + +## 🚀 Быстрый старт + +### Linux (Bash) + +```bash +# 1. Отредактируйте конфигурацию в скрипте +nano letsencrypt_regru_dns.sh + +# 2. Установите права +chmod +x letsencrypt_regru_dns.sh + +# 3. Запустите +sudo ./letsencrypt_regru_dns.sh +``` + +### Linux (Python) + +```bash +# 1. Создайте конфигурацию +sudo python3 letsencrypt_regru_api.py --create-config /etc/letsencrypt/regru_config.json + +# 2. Отредактируйте конфигурацию +sudo nano /etc/letsencrypt/regru_config.json + +# 3. Получите сертификат +sudo python3 letsencrypt_regru_api.py -c /etc/letsencrypt/regru_config.json --obtain +``` + +### Windows (PowerShell) + +```powershell +# 1. Создайте файл конфигурации config.json на основе config.json.example + +# 2. Запустите скрипт +.\letsencrypt_regru.ps1 -ConfigFile .\config.json +``` + +## ⚙️ Конфигурация + +Отредактируйте `config.json`: + +```json +{ + "regru_username": "ваш_логин", + "regru_password": "ваш_пароль", + "domain": "dfv24.com", + "wildcard": true, + "email": "admin@dfv24.com" +} +``` + +## 📋 Требования + +### Linux +- certbot +- Python 3.6+ +- pip3 +- requests, cryptography (Python модули) +- certbot-dns-regru (опционально) + +### Windows +- certbot +- PowerShell 5.1+ +- openssl (для проверки сертификатов) + +## 🔄 Автоматическое обновление + +### Через cron (Linux) + +```bash +# Добавьте в crontab +sudo crontab -e + +# Проверка каждый день в 3:00 +0 3 * * * /usr/bin/python3 /path/to/letsencrypt_regru_api.py -c /etc/letsencrypt/regru_config.json +``` + +### Через Task Scheduler (Windows) + +1. Откройте Task Scheduler +2. Создайте новую задачу +3. Триггер: Ежедневно в 3:00 +4. Действие: Запуск PowerShell скрипта + +## 📖 Функции + +✅ Создание wildcard сертификатов (*.domain.com) +✅ Автоматическая DNS-валидация через API reg.ru +✅ Проверка срока действия сертификата +✅ Автоматическое обновление перед истечением +✅ Перезагрузка веб-сервера после обновления +✅ Подробное логирование всех операций + +## 🔧 Использование с Nginx Proxy Manager + +После получения сертификата: + +1. Войдите в NPM: http://192.168.10.14:81/ +2. SSL Certificates → Add SSL Certificate → Custom +3. Вставьте содержимое: + - Certificate Key: `/etc/letsencrypt/live/domain.com/privkey.pem` + - Certificate: `/etc/letsencrypt/live/domain.com/fullchain.pem` + +## 📝 Логи + +- Bash: `/var/log/letsencrypt_regru.log` +- Python: `/var/log/letsencrypt_regru.log` +- PowerShell: `.\letsencrypt_regru.log` +- Certbot: `/var/log/letsencrypt/letsencrypt.log` + +## 🆘 Устранение неполадок + +### Ошибка аутентификации API +- Проверьте учетные данные reg.ru +- Убедитесь, что домен под вашим управлением + +### DNS запись не распространяется +- Увеличьте `dns_propagation_wait` до 120 секунд +- Проверьте DNS: `nslookup -type=TXT _acme-challenge.domain.com` + +### Certbot не найден +```bash +# Ubuntu/Debian +sudo apt-get install certbot + +# Или через snap +sudo snap install --classic certbot +``` + +## 📚 Документация + +Подробная документация в файле [USAGE.md](USAGE.md) + +## 🔐 Безопасность + +- Храните учетные данные в безопасности +- Используйте `chmod 600` для конфигурационных файлов +- Регулярно обновляйте пароли + +## ⚠️ Важно + +- Let's Encrypt сертификаты действительны 90 дней +- Рекомендуется настроить автоматическое обновление +- Для wildcard сертификатов требуется DNS-валидация + +## 📞 Поддержка + +- [Документация reg.ru API](https://www.reg.ru/support/api) +- [Документация Let's Encrypt](https://letsencrypt.org/docs/) +- [Certbot Documentation](https://certbot.eff.org/docs/) + +## 📄 Лицензия + +Скрипты предоставляются "как есть" для свободного использования. + +--- + +**Успешной автоматизации! 🔒** diff --git a/docs/ru/TESTING_GUIDE.md b/docs/ru/TESTING_GUIDE.md new file mode 100644 index 0000000..fccc5f7 --- /dev/null +++ b/docs/ru/TESTING_GUIDE.md @@ -0,0 +1,382 @@ +# 🧪 Руководство по тестированию SSL сертификатов + +## Зачем нужны тестовые сертификаты? + +Let's Encrypt имеет **строгие ограничения**: +- ⚠️ Максимум **5 сертификатов в неделю** на один домен +- ⚠️ Максимум **50 сертификатов в неделю** на аккаунт +- ⚠️ **Бан на 1 неделю** при превышении лимита + +**Решение**: Используйте самоподписанные тестовые сертификаты для разработки! + +--- + +## Быстрый старт + +### Вариант 1: Через Makefile (рекомендуется) + +```bash +# После установки скрипта (make install) +sudo make test-cert +``` + +**Результат**: Создан сертификат в `/etc/letsencrypt/live/ваш-домен/` + +### Вариант 2: Через Python скрипт + +```bash +sudo python3 letsencrypt_regru_api.py \ + --config /etc/letsencrypt/regru_config.json \ + --test-cert -v +``` + +### Вариант 3: Через Bash скрипт (автономный) + +```bash +# Простой домен +sudo ./test_certificate.sh example.com no + +# С wildcard +sudo ./test_certificate.sh example.com yes +``` + +--- + +## Сравнение методов + +| Метод | Скорость | Требования | NPM интеграция | Лимиты | +|-------|----------|------------|----------------|--------| +| **Let's Encrypt** | 2-5 минут | Internet, DNS | ✅ Да | ⚠️ 5/неделю | +| **Тестовый (Python)** | 1-2 секунды | Только Python | ✅ Да | ✅ Нет | +| **Тестовый (Bash)** | 1-2 секунды | Только OpenSSL | ❌ Ручная | ✅ Нет | + +--- + +## Детальная инструкция + +### 1. Подготовка конфигурации + +```bash +# Создать конфигурацию +sudo nano /etc/letsencrypt/regru_config.json +``` + +```json +{ + "domain": "test.example.com", + "wildcard": true, + "cert_dir": "/etc/letsencrypt/live", + "npm_enabled": true, + "npm_host": "https://npm.example.com", + "npm_email": "admin@example.com", + "npm_password": "your_password" +} +``` + +### 2. Создание тестового сертификата + +```bash +sudo make test-cert +``` + +### 3. Проверка созданных файлов + +```bash +ls -la /etc/letsencrypt/live/test.example.com/ +# Должны быть: +# - privkey.pem (приватный ключ) +# - cert.pem (сертификат) +# - fullchain.pem (полная цепочка) +# - chain.pem (CA цепочка) +``` + +### 4. Просмотр информации о сертификате + +```bash +openssl x509 -in /etc/letsencrypt/live/test.example.com/cert.pem -text -noout +``` + +--- + +## Использование в Nginx + +### Прямое использование + +```nginx +server { + listen 443 ssl; + server_name test.example.com; + + ssl_certificate /etc/letsencrypt/live/test.example.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/test.example.com/privkey.pem; + + # ... остальная конфигурация +} +``` + +### Через Nginx Proxy Manager + +Если `npm_enabled: true` в конфигурации, сертификат автоматически загрузится в NPM. + +**Проверка в NPM:** +1. Откройте веб-интерфейс NPM +2. Перейдите в **SSL Certificates** +3. Найдите ваш домен в списке +4. ⚠️ Будет помечен как "Custom" (не Let's Encrypt) + +--- + +## Автоматизация тестирования + +### Скрипт для CI/CD + +```bash +#!/bin/bash +# test_ssl_integration.sh + +set -e + +echo "🧪 Тестирование SSL интеграции..." + +# 1. Создать тестовый сертификат +sudo python3 letsencrypt_regru_api.py \ + --config test_config.json \ + --test-cert + +# 2. Проверить файлы +if [ ! -f "/etc/letsencrypt/live/test.example.com/fullchain.pem" ]; then + echo "❌ Сертификат не создан" + exit 1 +fi + +# 3. Проверить валидность +openssl x509 -in /etc/letsencrypt/live/test.example.com/cert.pem -noout -checkend 0 +if [ $? -eq 0 ]; then + echo "✅ Сертификат валиден" +else + echo "❌ Сертификат невалиден" + exit 1 +fi + +# 4. Проверить загрузку в NPM (опционально) +# ... ваша проверка через API NPM + +echo "✅ Все тесты пройдены" +``` + +### Makefile для тестирования + +```makefile +.PHONY: test-ssl test-npm test-all + +test-ssl: + @echo "Создание тестового сертификата..." + sudo make test-cert + @echo "Проверка файлов..." + test -f /etc/letsencrypt/live/$(DOMAIN)/fullchain.pem + @echo "✅ SSL тест пройден" + +test-npm: + @echo "Проверка интеграции с NPM..." + # Ваши проверки API NPM + @echo "✅ NPM тест пройден" + +test-all: test-ssl test-npm + @echo "✅ Все тесты пройдены" +``` + +--- + +## Переход на production + +### Шаг 1: Тестирование + +```bash +# 1. Создать тестовый сертификат +sudo make test-cert + +# 2. Проверить работу с NPM +# Открыть https://ваш-домен и проверить + +# 3. Убедиться что все работает +``` + +### Шаг 2: Переключение на Let's Encrypt + +```bash +# 1. Удалить тестовый сертификат +sudo rm -rf /etc/letsencrypt/live/ваш-домен/ + +# 2. Получить настоящий сертификат +sudo make obtain + +# 3. Проверить обновление в NPM +sudo make status +``` + +--- + +## Частые вопросы + +### Q: Почему браузер показывает предупреждение? + +**A:** Самоподписанные сертификаты не доверяются браузерами. Это нормально для тестирования. + +Чтобы избежать предупреждения в браузере (только для локального тестирования): +1. Chrome: `chrome://flags/#allow-insecure-localhost` +2. Firefox: Нажмите "Advanced" → "Accept the Risk" + +### Q: Можно ли использовать для production? + +**A:** ❌ **НЕТ!** Тестовые сертификаты только для разработки и тестирования. + +### Q: Как часто можно создавать тестовые сертификаты? + +**A:** ✅ Неограниченно! Нет никаких лимитов. + +### Q: Загружаются ли в NPM автоматически? + +**A:** ✅ Да, если `npm_enabled: true` в конфигурации. + +### Q: Работают ли с wildcard доменами? + +**A:** ✅ Да! Просто установите `"wildcard": true` в конфигурации. + +### Q: Как проверить срок действия? + +```bash +openssl x509 -in /etc/letsencrypt/live/ваш-домен/cert.pem -noout -dates +``` + +### Q: Как изменить срок действия? + +Отредактируйте `validity_days` в функции `generate_self_signed_certificate()`: + +```python +validity_days: int = 365 # Изменить на нужное количество дней +``` + +--- + +## Устранение проблем + +### Ошибка: Permission denied + +```bash +# Запускайте с sudo +sudo make test-cert +``` + +### Ошибка: Module 'cryptography' not found + +```bash +# Установите зависимости +sudo pip3 install cryptography +``` + +### NPM не показывает сертификат + +1. Проверьте настройки NPM в конфигурации +2. Проверьте логи: `sudo make logs` +3. Попробуйте загрузить вручную через веб-интерфейс NPM + +### Сертификат не создается + +```bash +# Проверьте права +ls -la /etc/letsencrypt/live/ + +# Создайте директорию вручную +sudo mkdir -p /etc/letsencrypt/live/ + +# Проверьте конфигурацию +sudo make check-config +``` + +--- + +## Примеры использования + +### Разработка с Docker + +```dockerfile +FROM nginx:alpine + +# Копировать тестовый сертификат +COPY test-certs/ /etc/nginx/ssl/ + +# Конфигурация nginx +COPY nginx.conf /etc/nginx/nginx.conf + +EXPOSE 443 +``` + +### Локальное тестирование + +```bash +# Создать сертификат для localhost +sudo python3 letsencrypt_regru_api.py --test-cert + +# Добавить в /etc/hosts +echo "127.0.0.1 test.example.com" | sudo tee -a /etc/hosts + +# Запустить nginx +sudo nginx -t && sudo nginx -s reload + +# Открыть в браузере +open https://test.example.com +``` + +### Автоматическое тестирование перед deployment + +```bash +#!/bin/bash +# pre-deploy.sh + +# Тестовая проверка SSL +sudo make test-cert +if [ $? -eq 0 ]; then + echo "✅ Тестовый сертификат создан успешно" + echo "✅ Готово к созданию production сертификата" + sudo make obtain +else + echo "❌ Ошибка при создании тестового сертификата" + exit 1 +fi +``` + +--- + +## Дополнительные ресурсы + +- 📘 [Let's Encrypt Rate Limits](https://letsencrypt.org/docs/rate-limits/) +- 📘 [OpenSSL Documentation](https://www.openssl.org/docs/) +- 📘 [Nginx Proxy Manager Docs](https://nginxproxymanager.com/guide/) + +--- + +## Итоговая шпаргалка + +```bash +# Установка +sudo make install + +# Конфигурация +sudo nano /etc/letsencrypt/regru_config.json + +# Создать тестовый сертификат +sudo make test-cert + +# Проверить +sudo make check-config +sudo make status + +# Переход на production +sudo rm -rf /etc/letsencrypt/live/домен/ +sudo make obtain + +# Автоматическое обновление +sudo make run +``` + +**Готово!** 🎉 Теперь вы можете тестировать SSL сертификаты без ограничений! diff --git a/docs/ru/Настройке Nginx Manager с SSL .md b/docs/ru/Настройке Nginx Manager с SSL .md new file mode 100644 index 0000000..72d2014 --- /dev/null +++ b/docs/ru/Настройке Nginx Manager с SSL .md @@ -0,0 +1,79 @@ +# Подробная инструкция по настройке Nginx Proxy Manager с одним глобальным SSL сертификатом для всех доменов dfv24.com + +## Предпосылки +- Установлен и запущен [Nginx Proxy Manager](http://192.168.10.14:81/) +- Основной домен: dfv24.com +- Хостинг и DNS записи домена находятся на reg.ru +- Нужно использовать один SSL сертификат (например, wildcard) для всех поддоменов dfv24.com + +--- + +## Шаг 1. Покупка и получение SSL Wildcard сертификата для dfv24.com +1. На reg.ru или любом другом удостоверяющем центре (CA) закажите wildcard сертификат на домен вида `*.dfv24.com`. +2. Получите файлы сертификата: + - Главный сертификат (CRT) + - Промежуточные сертификаты (CA Bundle) + - Приватный ключ (KEY) + +--- + +## Шаг 2. Импорт вашего SSL сертификата в Nginx Proxy Manager +1. Авторизуйтесь в Nginx Proxy Manager на http://192.168.10.14:81/ +2. Перейдите в раздел **SSL Certificates** → кнопку **Add SSL Certificate** +3. Выберите **Custom** (пользовательский сертификат) +4. В поля вставьте: + - **Certificate** — основной CRT + CA Bundle (если CA Bundle раздельно, склейте в один файл или вставляйте последовательно) + - **Key** — содержимое приватного ключа + - Имя сертификата задайте, например, `dfv24_wildcard` +5. Сохраните + +--- + +## Шаг 3. Настройка прокси-хостов с использованием глобального сертификата + +1. Перейдите в **Proxy Hosts** → **Add Proxy Host** +2. Заполните поля: + - **Domain Names**: Например, `sub1.dfv24.com` (для первого поддомена) + - **Scheme**: http или https, в зависимости от бекенда + - **Forward Hostname / IP**: IP или DNS адрес вашего внутреннего сервиса + - **Forward Port**: порт сервиса (например, 80 или 443) +3. Включите **SSL** → Отметьте **Use a shared SSL certificate** (если такая опция доступна) или выберите ранее импортированный сертификат из списка +4. Активируйте: **Block Common Exploits**, **Websockets Support**, выставьте Redirect HTTP to HTTPS, если требуется +5. Сохраните прокси-хост + +6. Повторите для всех поддоменов, указывая нужные домены и выбирая тот же wildcard SSL сертификат + +--- + +## Шаг 4. Настройка DNS записей на reg.ru + +1. Войдите в панель управления доменом на reg.ru +2. Создайте или отредактируйте DNS записи типа A: + - `dfv24.com` → IP вашего Nginx Proxy Manager (например, 192.168.10.14) + - `*.dfv24.com` → тот же IP или конкретные поддомены, если есть специальные +3. Сохраните изменения +4. Дождитесь обновления DNS (от нескольких минут до 24 часов) + +--- + +## Шаг 5. Тест и проверка работы + +1. В браузере откройте любой из поддоменов `https://sub1.dfv24.com` +2. Сертификат должен быть валидным, выданным на wildcard `*.dfv24.com` +3. Проверьте работу прокси и корректность подстановки сертификата +4. При необходимости проверьте логи Nginx Proxy Manager и исправьте ошибки + +--- + +## Дополнительно + +- Если в Nginx Proxy Manager нет GUI опции выбора общего сертификата, можно вручную сконфигурировать конфиги через директорий `/data/nginx/proxy_host` и прописать SSL сертификат для всех хостов. +- При обновлении сертификата — повторно импортировать его в Nginx Proxy Manager. +- Можно использовать LetsEncrypt для автоматического получения wildcard сертификата с помощью DNS-валидации (если поддерживается вашим DNS-провайдером). + +--- + +# Итог + +Используйте один wildcard сертификат для всех поддоменов, импортируйте его как пользовательский сертификат в Nginx Proxy Manager, при создании прокси-хостов выбирайте его в настройках SSL. Управляйте DNS записями на reg.ru, направляя domен на IP Nginx Proxy Manager. +Это позволит юридически использовать единый сертификат для всех сервисов с различными поддоменами под вашим доменом dfv24.com. diff --git a/docs/ru/Создание и продление SSL сертификата.md b/docs/ru/Создание и продление SSL сертификата.md new file mode 100644 index 0000000..78a8aaa --- /dev/null +++ b/docs/ru/Создание и продление SSL сертификата.md @@ -0,0 +1,86 @@ +# Инструкция по созданию wildcard сертификата *.dfv24.com в Nginx Proxy Manager и настройке автоматического продления SSL + +--- + +## Шаг 1. Подготовка + +- Убедитесь, что Nginx Proxy Manager (NPM) установлен и доступен по адресу http://192.168.10.14:81/ +- У вас есть доступ к DNS-записям домена dfv24.com в панели управления reg.ru или у другого регистратора + +--- + +## Шаг 2. Создание Wildcard SSL сертификата в Nginx Proxy Manager + +1. Войдите в админку Nginx Proxy Manager по адресу http://192.168.10.14:81/ + +2. Перейдите в раздел **SSL Certificates** → нажмите кнопку **Add SSL Certificate** + +3. Выберите пункт **Let's Encrypt** + +4. Заполните поля: + - **Domain Names:** + Введите `*.dfv24.com` — для wildcard сертификата + Также рекомендуется добавить основной домен `dfv24.com` (через запятую или в новом поле) + - **Email Address:** + Укажите ваш Email для уведомлений от Let's Encrypt (обязательно) + - **HTTP Challenge:** + Оставьте проверку HTTP, если NPM доступен из интернета по порту 80 и 443, или настройте DNS Challenge если поддерживается вашим DNS + +5. Отметьте галочку "Agree to the Let's Encrypt Terms of Service" + +6. Нажмите **Save** + +- NPM начнёт процесс получения сертификата с проверкой домена. +- При успешном запросе сертификата вы увидите новый сертификат в списке. + +--- + +## Шаг 3. Настройка автоматического продления + +- Nginx Proxy Manager автоматически заботится о продлении сертификатов Let's Encrypt. +- Для этого сервер должен быть доступен из интернета по портам 80 и 443, и DNS-записи правильно указывать на ваш сервер. +- NPM периодически (обычно за 30 дней до окончания) запрашивает обновление сертификата. +- В случае использования DNS Challenge необходимо чтобы в NPM была настроена интеграция с DNS провайдером (если поддерживается). + +--- + +## Шаг 4. Использование wildcard сертификата в Proxy Hosts + +1. Перейдите в **Proxy Hosts** → Создайте или отредактируйте запись прокси + +2. В поле **Domain Names** укажите нужный поддомен из dfv24.com, например: + `api.dfv24.com` или `www.dfv24.com` + +3. В разделе **SSL** выберите ваш wildcard сертификат `*.dfv24.com`, который вы получили на шаге 2 + +4. Включите опции: + - Use SSL + - Force SSL + - HSTS (при необходимости) + +5. Сохраните изменения. + +--- + +## Шаг 5. Проверка + +1. Проверьте, что для всех поддоменов используется единый сертификат +2. Посетите https://api.dfv24.com или другие поддомены из браузера +3. Убедитесь, что сертификат валиден, не просрочен и выдан на *.dfv24.com +4. Проверяйте в разделе SSL Certificates статус продления сертификата + +--- + +## Дополнительно + +- Если Let's Encrypt не может выполнить HTTP Challenge из-за закрытого порта, настройте DNS Challenge (может потребоваться ключ API DNS провайдера) +- Для безопасности и уведомлений держите Email в актуальном состоянии +- Проверяйте логи Nginx Proxy Manager для выявления ошибок продления + +--- + +# Итог + +Nginx Proxy Manager позволяет легко получать и автоматически обновлять wildcard SSL сертификаты для домена *.dfv24.com с помощью Let's Encrypt. +Главное — правильно настроить DNS записи и обеспечить интернет доступ на HTTP/HTTPS порты. +Далее используйте один глобальный сертификат для всех ваших поддоменов через настройки Proxy Hosts. \ No newline at end of file diff --git a/gitea-hooks/README.md b/gitea-hooks/README.md new file mode 100644 index 0000000..082dbae --- /dev/null +++ b/gitea-hooks/README.md @@ -0,0 +1,168 @@ +# Git Hooks для Gitea + +Автоматическая синхронизация с GitHub после push в Gitea. + +## 📁 Файлы + +- **post-receive** - Hook для автоматического push в GitHub + +## 🚀 Установка + +### 1. Найдите путь к репозиторию на сервере Gitea + +```bash +# Обычно это один из путей: +/var/lib/gitea/data/gitea-repositories/username/configure_nginx_manager.git +# или +/home/git/gitea-repositories/username/configure_nginx_manager.git +``` + +### 2. Скопируйте hook + +```bash +# На сервере Gitea +cd /path/to/gitea-repositories/username/configure_nginx_manager.git/hooks/ + +# Скопируйте файл +cp /path/to/this/repo/gitea-hooks/post-receive ./ + +# Или загрузите напрямую +wget https://raw.githubusercontent.com/username/configure_nginx_manager/main/gitea-hooks/post-receive +``` + +### 3. Настройте hook + +```bash +nano post-receive +``` + +Измените: +```bash +GITHUB_REPO="git@github.com:YOUR_USERNAME/configure_nginx_manager.git" +``` + +### 4. Сделайте исполняемым + +```bash +chmod +x post-receive +chown git:git post-receive +``` + +### 5. Создайте директорию для логов + +```bash +mkdir -p /var/log/gitea +chown git:git /var/log/gitea +``` + +## 🔑 Настройка аутентификации + +### Вариант A: SSH (Рекомендуется) + +```bash +# На сервере Gitea под пользователем git +sudo su - git +ssh-keygen -t ed25519 -C "gitea-sync" + +# Скопируйте публичный ключ +cat ~/.ssh/id_ed25519.pub + +# Добавьте на GitHub: +# Settings → SSH and GPG keys → New SSH key + +# Проверьте +ssh -T git@github.com +``` + +### Вариант B: HTTPS с токеном + +1. Создайте Personal Access Token на GitHub + - Settings → Developer settings → Personal access tokens + - Scope: `repo` + +2. Используйте в hook: +```bash +GITHUB_REPO="https://YOUR_TOKEN@github.com/username/configure_nginx_manager.git" +``` + +## ✅ Проверка + +```bash +# Тестовый push +cd /tmp +git clone http://gitea.example.com/username/configure_nginx_manager.git +cd configure_nginx_manager +echo "test" >> README.md +git add README.md +git commit -m "Test sync" +git push + +# Проверьте лог +tail -f /var/log/gitea/github-sync.log + +# Проверьте GitHub - изменения должны появиться через 1-2 секунды +``` + +## 📊 Что делает hook + +1. ✅ Отслеживает push в ветки `main` и `master` +2. ✅ Автоматически пушит в GitHub +3. ✅ Синхронизирует теги +4. ✅ Логирует все операции +5. ✅ Показывает красивый вывод с эмодзи + +## 🐛 Устранение проблем + +### Hook не срабатывает + +```bash +# Проверьте права +ls -la post-receive +# Должно быть: -rwxr-xr-x + +# Проверьте владельца +chown git:git post-receive + +# Проверьте синтаксис +bash -n post-receive +``` + +### Permission denied + +```bash +# Для SSH +ssh -T git@github.com + +# Проверьте права на ключ +chmod 600 ~/.ssh/id_ed25519 + +# Для HTTPS - проверьте токен +``` + +### Не находит git + +```bash +# Добавьте PATH в начало hook: +export PATH=/usr/bin:/usr/local/bin:$PATH +``` + +## 📝 Логи + +```bash +# Просмотр логов синхронизации +tail -f /var/log/gitea/github-sync.log + +# Очистка старых логов +> /var/log/gitea/github-sync.log +``` + +## 🔄 Альтернативы + +Если Git Hook не подходит, см. другие методы в [GITEA_SYNC.md](../GITEA_SYNC.md): +- GitHub Actions (каждый час) +- Gitea Mirror (встроенная функция) +- Двойной remote (локально) + +--- + +**См. также**: [GITEA_SYNC.md](../GITEA_SYNC.md) для подробной документации diff --git a/gitea-hooks/README_EN.md b/gitea-hooks/README_EN.md new file mode 100644 index 0000000..f2aada9 --- /dev/null +++ b/gitea-hooks/README_EN.md @@ -0,0 +1,168 @@ +# Git Hooks for Gitea + +Automatic synchronization with GitHub after push to Gitea. + +## 📁 Files + +- **post-receive** - Hook for automatic push to GitHub + +## 🚀 Installation + +### 1. Find Repository Path on Gitea Server + +```bash +# Usually one of these paths: +/var/lib/gitea/data/gitea-repositories/username/configure_nginx_manager.git +# or +/home/git/gitea-repositories/username/configure_nginx_manager.git +``` + +### 2. Copy Hook + +```bash +# On Gitea server +cd /path/to/gitea-repositories/username/configure_nginx_manager.git/hooks/ + +# Copy file +cp /path/to/this/repo/gitea-hooks/post-receive ./ + +# Or download directly +wget https://raw.githubusercontent.com/username/configure_nginx_manager/main/gitea-hooks/post-receive +``` + +### 3. Configure Hook + +```bash +nano post-receive +``` + +Change: +```bash +GITHUB_REPO="git@github.com:YOUR_USERNAME/configure_nginx_manager.git" +``` + +### 4. Make Executable + +```bash +chmod +x post-receive +chown git:git post-receive +``` + +### 5. Create Log Directory + +```bash +mkdir -p /var/log/gitea +chown git:git /var/log/gitea +``` + +## 🔑 Authentication Setup + +### Option A: SSH (Recommended) + +```bash +# On Gitea server as git user +sudo su - git +ssh-keygen -t ed25519 -C "gitea-sync" + +# Copy public key +cat ~/.ssh/id_ed25519.pub + +# Add to GitHub: +# Settings → SSH and GPG keys → New SSH key + +# Verify +ssh -T git@github.com +``` + +### Option B: HTTPS with Token + +1. Create Personal Access Token on GitHub + - Settings → Developer settings → Personal access tokens + - Scope: `repo` + +2. Use in hook: +```bash +GITHUB_REPO="https://YOUR_TOKEN@github.com/username/configure_nginx_manager.git" +``` + +## ✅ Verification + +```bash +# Test push +cd /tmp +git clone http://gitea.example.com/username/configure_nginx_manager.git +cd configure_nginx_manager +echo "test" >> README.md +git add README.md +git commit -m "Test sync" +git push + +# Check log +tail -f /var/log/gitea/github-sync.log + +# Check GitHub - changes should appear in 1-2 seconds +``` + +## 📊 What Hook Does + +1. ✅ Monitors pushes to `main` and `master` branches +2. ✅ Automatically pushes to GitHub +3. ✅ Synchronizes tags +4. ✅ Logs all operations +5. ✅ Shows beautiful output with emojis + +## 🐛 Troubleshooting + +### Hook Not Firing + +```bash +# Check permissions +ls -la post-receive +# Should be: -rwxr-xr-x + +# Check owner +chown git:git post-receive + +# Check syntax +bash -n post-receive +``` + +### Permission Denied + +```bash +# For SSH +ssh -T git@github.com + +# Check key permissions +chmod 600 ~/.ssh/id_ed25519 + +# For HTTPS - check token +``` + +### Can't Find Git + +```bash +# Add PATH to beginning of hook: +export PATH=/usr/bin:/usr/local/bin:$PATH +``` + +## 📝 Logs + +```bash +# View sync logs +tail -f /var/log/gitea/github-sync.log + +# Clear old logs +> /var/log/gitea/github-sync.log +``` + +## 🔄 Alternatives + +If Git Hook doesn't work, see other methods in [GITEA_SYNC_EN.md](../GITEA_SYNC_EN.md): +- GitHub Actions (every hour) +- Gitea Mirror (built-in feature) +- Double remote (locally) + +--- + +**See also**: [GITEA_SYNC_EN.md](../GITEA_SYNC_EN.md) for detailed documentation diff --git a/gitea-hooks/post-receive b/gitea-hooks/post-receive new file mode 100644 index 0000000..21ce0c4 --- /dev/null +++ b/gitea-hooks/post-receive @@ -0,0 +1,83 @@ +#!/bin/bash + +# ============================================================================== +# Post-receive hook для Gitea +# Автоматически синхронизирует изменения с GitHub после push +# +# Установка: +# 1. Разместить в: /path/to/gitea/data/gitea-repositories/username/repo.git/hooks/ +# 2. Переименовать в: post-receive +# 3. chmod +x post-receive +# 4. Настроить переменные ниже +# ============================================================================== + +# Конфигурация +GITHUB_REPO="git@github.com:username/configure_nginx_manager.git" +# Или с HTTPS и токеном: +# GITHUB_REPO="https://YOUR_GITHUB_TOKEN@github.com/username/configure_nginx_manager.git" + +LOG_FILE="/var/log/gitea/github-sync.log" + +# Цвета для логов +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# ============================================================================== +# Функция логирования +# ============================================================================== +log() { + echo -e "${2:-$NC}[$(date +'%d.%m.%Y %H:%M:%S')] $1${NC}" | tee -a "$LOG_FILE" +} + +# ============================================================================== +# Основная логика +# ============================================================================== + +log "═══════════════════════════════════════════════════════════════" "$GREEN" +log "🔄 Начало синхронизации с GitHub" "$GREEN" +log "═══════════════════════════════════════════════════════════════" "$GREEN" + +# Читаем информацию о push +while read oldrev newrev refname; do + log "📝 Изменения обнаружены:" "$YELLOW" + log " Branch: ${refname#refs/heads/}" + log " Old commit: ${oldrev:0:8}" + log " New commit: ${newrev:0:8}" + + # Проверяем наличие GitHub remote + if ! git remote | grep -q github; then + log "➕ Добавление GitHub remote..." "$YELLOW" + git remote add github "$GITHUB_REPO" 2>&1 | tee -a "$LOG_FILE" + fi + + # Пушим в GitHub + log "⬆️ Отправка изменений в GitHub..." "$YELLOW" + + # Только для main/master веток + if [[ "$refname" == "refs/heads/main" ]] || [[ "$refname" == "refs/heads/master" ]]; then + if git push github "$refname" --force 2>&1 | tee -a "$LOG_FILE"; then + log "✅ Успешно синхронизировано с GitHub" "$GREEN" + else + log "❌ Ошибка при синхронизации с GitHub" "$RED" + exit 1 + fi + + # Пушим теги + log "🏷️ Отправка тегов..." "$YELLOW" + if git push github --tags 2>&1 | tee -a "$LOG_FILE"; then + log "✅ Теги синхронизированы" "$GREEN" + else + log "⚠️ Не удалось синхронизировать теги" "$YELLOW" + fi + else + log "ℹ️ Ветка ${refname#refs/heads/} игнорируется (не main/master)" "$YELLOW" + fi +done + +log "═══════════════════════════════════════════════════════════════" "$GREEN" +log "✅ Синхронизация завершена" "$GREEN" +log "═══════════════════════════════════════════════════════════════" "$GREEN" + +exit 0 diff --git a/letsencrypt_regru.ps1 b/letsencrypt_regru.ps1 new file mode 100644 index 0000000..837126e --- /dev/null +++ b/letsencrypt_regru.ps1 @@ -0,0 +1,556 @@ +# ============================================================================ +# Скрипт для создания и обновления SSL сертификата Let's Encrypt +# с использованием DNS-валидации через API reg.ru (PowerShell версия) +# +# Автор: Фофанов Дмитрий +# Дата: 27.10.2025 +# Описание: PowerShell версия скрипта для Windows окружения +# ============================================================================ + +<# +.SYNOPSIS + Автоматизация получения SSL сертификатов Let's Encrypt через DNS-валидацию reg.ru + +.DESCRIPTION + Скрипт позволяет автоматически получать и обновлять SSL сертификаты Let's Encrypt + для доменов на reg.ru используя DNS-01 challenge через API + +.PARAMETER Domain + Основной домен (например, dfv24.com) + +.PARAMETER Email + Email для уведомлений Let's Encrypt + +.PARAMETER RegRuUsername + Имя пользователя reg.ru + +.PARAMETER RegRuPassword + Пароль reg.ru + +.PARAMETER Wildcard + Создать wildcard сертификат (*.domain.com) + +.PARAMETER ConfigFile + Путь к файлу конфигурации JSON + +.EXAMPLE + .\letsencrypt_regru.ps1 -Domain "dfv24.com" -Email "admin@dfv24.com" -Wildcard +#> + +param( + [Parameter(Mandatory=$false)] + [string]$Domain = "dfv24.com", + + [Parameter(Mandatory=$false)] + [string]$Email = "admin@dfv24.com", + + [Parameter(Mandatory=$false)] + [string]$RegRuUsername = "", + + [Parameter(Mandatory=$false)] + [string]$RegRuPassword = "", + + [Parameter(Mandatory=$false)] + [switch]$Wildcard = $true, + + [Parameter(Mandatory=$false)] + [string]$ConfigFile = ".\config.json", + + [Parameter(Mandatory=$false)] + [switch]$Verbose = $false +) + +# ============================================================================ +# КОНФИГУРАЦИЯ +# ============================================================================ + +$Script:Config = @{ + RegRuApiUrl = "https://api.reg.ru/api/regru2" + CertbotPath = "certbot" + LogFile = ".\letsencrypt_regru.log" + DnsPropagationWait = 60 + DnsCheckAttempts = 10 + DnsCheckInterval = 10 +} + +# ============================================================================ +# ФУНКЦИИ ЛОГИРОВАНИЯ +# ============================================================================ + +function Write-Log { + param( + [string]$Message, + [string]$Level = "INFO" + ) + + $Timestamp = Get-Date -Format "dd.MM.yyyy HH:mm:ss" + $LogMessage = "[$Timestamp] [$Level] $Message" + + # Вывод в консоль + switch ($Level) { + "ERROR" { Write-Host $LogMessage -ForegroundColor Red } + "WARNING" { Write-Host $LogMessage -ForegroundColor Yellow } + "SUCCESS" { Write-Host $LogMessage -ForegroundColor Green } + default { Write-Host $LogMessage } + } + + # Запись в файл + Add-Content -Path $Script:Config.LogFile -Value $LogMessage +} + +# ============================================================================ +# ФУНКЦИИ РАБОТЫ С КОНФИГУРАЦИЕЙ +# ============================================================================ + +function Load-Configuration { + param([string]$ConfigPath) + + Write-Log "Загрузка конфигурации из: $ConfigPath" + + if (Test-Path $ConfigPath) { + try { + $config = Get-Content -Path $ConfigPath -Raw | ConvertFrom-Json + + # Обновляем параметры скрипта из конфигурации + if ($config.domain) { $Script:Domain = $config.domain } + if ($config.email) { $Script:Email = $config.email } + if ($config.regru_username) { $Script:RegRuUsername = $config.regru_username } + if ($config.regru_password) { $Script:RegRuPassword = $config.regru_password } + if ($null -ne $config.wildcard) { $Script:Wildcard = $config.wildcard } + + Write-Log "Конфигурация успешно загружена" "SUCCESS" + return $true + } + catch { + Write-Log "Ошибка при загрузке конфигурации: $_" "ERROR" + return $false + } + } + else { + Write-Log "Файл конфигурации не найден: $ConfigPath" "WARNING" + return $false + } +} + +function Create-SampleConfig { + param([string]$OutputPath = ".\config.json") + + $sampleConfig = @{ + regru_username = "your_username" + regru_password = "your_password" + domain = "dfv24.com" + wildcard = $true + email = "admin@dfv24.com" + dns_propagation_wait = 60 + dns_check_attempts = 10 + dns_check_interval = 10 + } + + $sampleConfig | ConvertTo-Json -Depth 10 | Set-Content -Path $OutputPath + Write-Log "Пример конфигурации создан: $OutputPath" "SUCCESS" +} + +# ============================================================================ +# ФУНКЦИИ РАБОТЫ С REG.RU API +# ============================================================================ + +function Invoke-RegRuApi { + param( + [string]$Method, + [hashtable]$Params + ) + + $url = "$($Script:Config.RegRuApiUrl)/$Method" + + # Добавляем учетные данные + $Params["username"] = $Script:RegRuUsername + $Params["password"] = $Script:RegRuPassword + $Params["output_format"] = "json" + + Write-Log "Отправка запроса к API: $Method" "DEBUG" + + try { + $response = Invoke-RestMethod -Uri $url -Method Post -Body $Params -ContentType "application/x-www-form-urlencoded" + + if ($response.result -eq "success") { + Write-Log "Запрос $Method выполнен успешно" "DEBUG" + return $response + } + else { + $errorMsg = if ($response.error_text) { $response.error_text } else { "Неизвестная ошибка" } + Write-Log "Ошибка API: $errorMsg" "ERROR" + throw "API Error: $errorMsg" + } + } + catch { + Write-Log "Ошибка HTTP запроса: $_" "ERROR" + throw + } +} + +function Get-DnsRecords { + param([string]$Domain) + + Write-Log "Получение DNS записей для домена: $Domain" + + $params = @{ + domain = $Domain + } + + $response = Invoke-RegRuApi -Method "zone/get_resource_records" -Params $params + + if ($response.answer -and $response.answer.records) { + $records = $response.answer.records + Write-Log "Получено $($records.Count) DNS записей" + return $records + } + else { + Write-Log "DNS записи не найдены" "WARNING" + return @() + } +} + +function Add-TxtRecord { + param( + [string]$Domain, + [string]$Subdomain, + [string]$TxtValue + ) + + Write-Log "Добавление TXT записи: $Subdomain.$Domain = $TxtValue" + + $params = @{ + domain = $Domain + subdomain = $Subdomain + text = $TxtValue + output_content_type = "plain" + } + + try { + $null = Invoke-RegRuApi -Method "zone/add_txt" -Params $params + Write-Log "TXT запись успешно добавлена" "SUCCESS" + return $true + } + catch { + Write-Log "Не удалось добавить TXT запись: $_" "ERROR" + return $false + } +} + +function Remove-TxtRecord { + param( + [string]$Domain, + [string]$Subdomain, + [string]$TxtValue + ) + + Write-Log "Удаление TXT записи: $Subdomain.$Domain" + + # Получаем список записей + $records = Get-DnsRecords -Domain $Domain + + # Ищем нужную TXT запись + $record = $records | Where-Object { + $_.rectype -eq "TXT" -and + $_.subdomain -eq $Subdomain -and + $_.text -eq $TxtValue + } | Select-Object -First 1 + + if (-not $record) { + Write-Log "TXT запись для удаления не найдена" "WARNING" + return $false + } + + $params = @{ + domain = $Domain + record_id = $record.id + } + + try { + $null = Invoke-RegRuApi -Method "zone/remove_record" -Params $params + Write-Log "TXT запись успешно удалена" "SUCCESS" + return $true + } + catch { + Write-Log "Не удалось удалить TXT запись: $_" "ERROR" + return $false + } +} + +# ============================================================================ +# ФУНКЦИИ РАБОТЫ С CERTBOT +# ============================================================================ + +function Test-CertbotInstalled { + try { + $version = & certbot --version 2>&1 + Write-Log "Certbot установлен: $version" + return $true + } + catch { + Write-Log "Certbot не установлен!" "ERROR" + Write-Log "Установите Certbot: https://certbot.eff.org/instructions" "ERROR" + return $false + } +} + +function Get-CertificateExpiry { + param([string]$Domain) + + $certPath = Join-Path $env:ProgramData "letsencrypt\live\$Domain\cert.pem" + + if (-not (Test-Path $certPath)) { + Write-Log "Сертификат не найден: $certPath" + return $null + } + + try { + # Используем openssl для проверки сертификата + $expiryText = & openssl x509 -enddate -noout -in $certPath 2>&1 + + if ($expiryText -match "notAfter=(.+)") { + $expiryDate = [DateTime]::Parse($matches[1]) + $daysLeft = ($expiryDate - (Get-Date)).Days + + Write-Log "Сертификат истекает: $($expiryDate.ToString('yyyy-MM-dd'))" + Write-Log "Осталось дней: $daysLeft" + + return $daysLeft + } + } + catch { + Write-Log "Ошибка при проверке сертификата: $_" "ERROR" + } + + return $null +} + +function Invoke-DnsChallenge { + param( + [string]$Domain, + [string]$ValidationToken + ) + + Write-Log "=== DNS Challenge: Добавление TXT записи ===" "INFO" + + # Извлекаем поддомен + $subdomain = "_acme-challenge" + + # Добавляем TXT запись + $success = Add-TxtRecord -Domain $Script:Domain -Subdomain $subdomain -TxtValue $ValidationToken + + if ($success) { + # Ждем распространения DNS + $waitTime = $Script:Config.DnsPropagationWait + Write-Log "Ожидание распространения DNS ($waitTime секунд)..." + Start-Sleep -Seconds $waitTime + + Write-Log "DNS валидация готова" "SUCCESS" + return $true + } + + return $false +} + +function Invoke-DnsCleanup { + param( + [string]$Domain, + [string]$ValidationToken + ) + + Write-Log "=== DNS Challenge: Удаление TXT записи ===" "INFO" + + $subdomain = "_acme-challenge" + + return Remove-TxtRecord -Domain $Script:Domain -Subdomain $subdomain -TxtValue $ValidationToken +} + +# ============================================================================ +# ГЛАВНЫЕ ФУНКЦИИ +# ============================================================================ + +function Get-Certificate { + param([string]$Domain, [bool]$WildcardCert) + + Write-Log "=== Запрос нового SSL сертификата ===" "INFO" + + # Формируем список доменов + $domains = @($Domain) + if ($WildcardCert) { + $domains += "*.$Domain" + } + + $domainArgs = @() + foreach ($d in $domains) { + $domainArgs += "-d" + $domainArgs += $d + } + + Write-Log "Домены для сертификата: $($domains -join ', ')" + + # Создаем временные скрипты для хуков + $authHookScript = Join-Path $env:TEMP "certbot_auth_hook.ps1" + $cleanupHookScript = Join-Path $env:TEMP "certbot_cleanup_hook.ps1" + + # Скрипт для аутентификации + @" +param([string]`$Domain, [string]`$Token) +# Вызов функции добавления TXT записи +# Здесь должна быть логика работы с API reg.ru +"@ | Set-Content -Path $authHookScript + + # Скрипт для очистки + @" +param([string]`$Domain, [string]`$Token) +# Вызов функции удаления TXT записи +"@ | Set-Content -Path $cleanupHookScript + + Write-Log "Примечание: Для полной автоматизации используйте Linux версию скрипта" "WARNING" + Write-Log "На Windows рекомендуется использовать плагин certbot-dns-регru или выполнить вручную" "WARNING" + + # Команда certbot (базовая, требует ручной DNS валидации) + $certbotArgs = @( + "certonly", + "--manual", + "--preferred-challenges", "dns", + "--email", $Script:Email, + "--agree-tos", + "--manual-public-ip-logging-ok" + ) + $domainArgs + + Write-Log "Запуск certbot..." + Write-Log "ВАЖНО: Certbot запросит вас добавить TXT записи в DNS" "WARNING" + Write-Log "Используйте API reg.ru или добавьте записи вручную через панель управления" "WARNING" + + try { + & certbot @certbotArgs + + Write-Log "Процесс получения сертификата завершен" "SUCCESS" + return $true + } + catch { + Write-Log "Ошибка при получении сертификата: $_" "ERROR" + return $false + } +} + +function Update-Certificate { + Write-Log "=== Обновление SSL сертификата ===" "INFO" + + try { + & certbot renew + + Write-Log "Проверка обновления завершена" "SUCCESS" + return $true + } + catch { + Write-Log "Ошибка при обновлении: $_" "ERROR" + return $false + } +} + +function Show-CertificateInfo { + param([string]$Domain) + + $certPath = Join-Path $env:ProgramData "letsencrypt\live\$Domain\cert.pem" + + if (-not (Test-Path $certPath)) { + Write-Log "Сертификат не найден" "WARNING" + return + } + + Write-Log ("=" * 60) + Write-Log "ИНФОРМАЦИЯ О СЕРТИФИКАТЕ" + Write-Log ("=" * 60) + + try { + $certInfo = & openssl x509 -in $certPath -text -noout + + # Выводим основную информацию + $certInfo -split "`n" | Where-Object { + $_ -match "Subject:|Issuer:|Not Before|Not After|DNS:" + } | ForEach-Object { + Write-Log $_.Trim() + } + + Write-Log ("=" * 60) + Write-Log "ПУТИ К ФАЙЛАМ СЕРТИФИКАТА:" + Write-Log " Сертификат: $certPath" + Write-Log " Приватный ключ: $(Join-Path $env:ProgramData "letsencrypt\live\$Domain\privkey.pem")" + Write-Log " Цепочка: $(Join-Path $env:ProgramData "letsencrypt\live\$Domain\chain.pem")" + Write-Log " Полная цепочка: $(Join-Path $env:ProgramData "letsencrypt\live\$Domain\fullchain.pem")" + Write-Log ("=" * 60) + } + catch { + Write-Log "Ошибка при чтении сертификата: $_" "ERROR" + } +} + +# ============================================================================ +# ОСНОВНАЯ ЛОГИКА +# ============================================================================ + +function Main { + Write-Log ("=" * 60) + Write-Log "СКРИПТ УПРАВЛЕНИЯ SSL СЕРТИФИКАТАМИ LET'S ENCRYPT" + Write-Log ("=" * 60) + + # Проверка прав администратора + $currentUser = [Security.Principal.WindowsIdentity]::GetCurrent() + $principal = New-Object Security.Principal.WindowsPrincipal($currentUser) + $isAdmin = $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) + + if (-not $isAdmin) { + Write-Log "ПРЕДУПРЕЖДЕНИЕ: Скрипт запущен без прав администратора" "WARNING" + Write-Log "Некоторые операции могут потребовать повышенных прав" "WARNING" + } + + # Загрузка конфигурации + if ($ConfigFile -and (Test-Path $ConfigFile)) { + Load-Configuration -ConfigPath $ConfigFile + } + + # Проверка обязательных параметров + if (-not $Script:RegRuUsername -or -not $Script:RegRuPassword) { + Write-Log "ОШИБКА: Не указаны учетные данные reg.ru" "ERROR" + Write-Log "Укажите RegRuUsername и RegRuPassword или создайте файл конфигурации" "ERROR" + return + } + + # Проверка Certbot + if (-not (Test-CertbotInstalled)) { + Write-Log "Установите Certbot и повторите попытку" "ERROR" + return + } + + # Проверка срока действия сертификата + $daysLeft = Get-CertificateExpiry -Domain $Script:Domain + + if ($null -eq $daysLeft) { + Write-Log "Сертификат не найден. Требуется создание нового." "INFO" + $success = Get-Certificate -Domain $Script:Domain -WildcardCert $Script:Wildcard + } + elseif ($daysLeft -lt 30) { + Write-Log "Сертификат истекает через $daysLeft дней. Требуется обновление!" "WARNING" + $success = Update-Certificate + } + else { + Write-Log "Сертификат действителен ($daysLeft дней)" "SUCCESS" + $success = $true + } + + if ($success) { + Show-CertificateInfo -Domain $Script:Domain + } + + Write-Log ("=" * 60) + Write-Log "Скрипт завершен" + Write-Log ("=" * 60) +} + +# ============================================================================ +# ТОЧКА ВХОДА +# ============================================================================ + +# Запуск основной функции +Main diff --git a/letsencrypt_regru.sh b/letsencrypt_regru.sh new file mode 100644 index 0000000..1891a56 --- /dev/null +++ b/letsencrypt_regru.sh @@ -0,0 +1,695 @@ +#!/usr/bin/env bash + +# ============================================================================== +# Скрипт автоматической установки Let's Encrypt Manager для reg.ru +# Автор: Фофанов Дмитрий +# Дата: 28.10.2025 +# ============================================================================== + +set -euo pipefail + +# Цвета для вывода +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +CYAN='\033[0;36m' +NC='\033[0m' # No Color + +# Конфигурация по умолчанию +APP_NAME="Let's Encrypt Manager" +APP_DIR="/opt/letsencrypt-regru" +CONFIG_DIR="/etc/letsencrypt-regru" +LOG_DIR="/var/log/letsencrypt-regru" +CERT_DIR="/etc/letsencrypt/live" +VENV_DIR="${APP_DIR}/venv" +PYTHON_VERSION="3" + +# ============================================================================== +# Вспомогательные функции +# ============================================================================== + +msg_info() { + echo -e "${BLUE}ℹ ${NC}$1" +} + +msg_ok() { + echo -e "${GREEN}✓${NC} $1" +} + +msg_error() { + echo -e "${RED}✗${NC} $1" +} + +msg_warn() { + echo -e "${YELLOW}⚠${NC} $1" +} + +header() { + echo "" + echo -e "${CYAN}════════════════════════════════════════════════════════════════${NC}" + echo -e "${CYAN} $1${NC}" + echo -e "${CYAN}════════════════════════════════════════════════════════════════${NC}" + echo "" +} + +# Проверка запуска от root +check_root() { + if [[ $EUID -ne 0 ]]; then + msg_error "Этот скрипт должен быть запущен от имени root" + msg_info "Используйте: sudo $0" + exit 1 + fi +} + +# Определение дистрибутива +detect_os() { + if [ -f /etc/os-release ]; then + . /etc/os-release + OS=$ID + VER=$VERSION_ID + else + msg_error "Не удалось определить операционную систему" + exit 1 + fi + + msg_info "Обнаружена ОС: $OS $VER" +} + +# Проверка доступных ресурсов +check_resources() { + local total_ram=$(free -m | awk 'NR==2{print $2}') + local available_disk=$(df -m / | awk 'NR==2{print $4}') + + msg_info "Доступно RAM: ${total_ram}MB, Свободно на диске: ${available_disk}MB" + + if [ "$total_ram" -lt 512 ]; then + msg_warn "Рекомендуется минимум 512MB RAM" + fi + + if [ "$available_disk" -lt 1024 ]; then + msg_warn "Рекомендуется минимум 1GB свободного места" + fi +} + +# Установка зависимостей +install_dependencies() { + header "Установка зависимостей" + + case $OS in + ubuntu|debian) + msg_info "Обновление списка пакетов..." + apt-get update -qq + + msg_info "Установка базовых пакетов..." + apt-get install -y -qq \ + python3 \ + python3-pip \ + python3-venv \ + python3-dev \ + build-essential \ + libssl-dev \ + libffi-dev \ + curl \ + git \ + dnsutils \ + certbot \ + openssl + ;; + centos|rhel|fedora) + msg_info "Обновление списка пакетов..." + yum update -y -q + + msg_info "Установка базовых пакетов..." + yum install -y -q \ + python3 \ + python3-pip \ + python3-devel \ + gcc \ + openssl-devel \ + libffi-devel \ + curl \ + git \ + bind-utils \ + certbot \ + openssl + ;; + *) + msg_error "Неподдерживаемая ОС: $OS" + exit 1 + ;; + esac + + msg_ok "Зависимости установлены" +} + +# Создание структуры директорий +create_directories() { + header "Создание директорий" + + msg_info "Создание структуры директорий..." + + mkdir -p "$APP_DIR" + mkdir -p "$CONFIG_DIR" + mkdir -p "$LOG_DIR" + mkdir -p "$CERT_DIR" + + chmod 755 "$APP_DIR" + chmod 750 "$CONFIG_DIR" + chmod 755 "$LOG_DIR" + chmod 755 "$CERT_DIR" + + msg_ok "Директории созданы" +} + +# Создание виртуального окружения Python +setup_python_venv() { + header "Настройка Python окружения" + + msg_info "Создание виртуального окружения..." + python3 -m venv "$VENV_DIR" + + msg_info "Активация виртуального окружения..." + source "${VENV_DIR}/bin/activate" + + msg_info "Обновление pip..." + pip install --quiet --upgrade pip setuptools wheel + + msg_info "Установка Python зависимостей..." + pip install --quiet requests cryptography certbot + + msg_ok "Python окружение настроено" +} + +# Копирование файлов приложения +install_application() { + header "Установка приложения" + + local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + local github_raw_url="https://raw.githubusercontent.com/DFofanov/configure_nginx_manager/refs/heads/master" + + msg_info "Установка основного скрипта..." + + # Проверяем наличие файла в текущей директории + if [ -f "${script_dir}/letsencrypt_regru_api.py" ]; then + msg_info "Файл найден локально, копируем из ${script_dir}" + cp "${script_dir}/letsencrypt_regru_api.py" "${APP_DIR}/" + chmod 755 "${APP_DIR}/letsencrypt_regru_api.py" + msg_ok "Файл скопирован из локальной директории" + else + msg_warn "Файл letsencrypt_regru_api.py не найден локально" + msg_info "Скачивание с GitHub..." + + if command -v curl &> /dev/null; then + if curl -fsSL "${github_raw_url}/letsencrypt_regru_api.py" -o "${APP_DIR}/letsencrypt_regru_api.py"; then + chmod 755 "${APP_DIR}/letsencrypt_regru_api.py" + msg_ok "Файл успешно скачан с GitHub" + else + msg_error "Не удалось скачать файл с GitHub" + msg_info "URL: ${github_raw_url}/letsencrypt_regru_api.py" + exit 1 + fi + elif command -v wget &> /dev/null; then + if wget -q "${github_raw_url}/letsencrypt_regru_api.py" -O "${APP_DIR}/letsencrypt_regru_api.py"; then + chmod 755 "${APP_DIR}/letsencrypt_regru_api.py" + msg_ok "Файл успешно скачан с GitHub (wget)" + else + msg_error "Не удалось скачать файл с GitHub" + msg_info "URL: ${github_raw_url}/letsencrypt_regru_api.py" + exit 1 + fi + else + msg_error "Не установлены curl или wget для скачивания файлов" + msg_info "Установите один из них: sudo apt-get install curl" + exit 1 + fi + fi + + msg_info "Установка дополнительных файлов..." + + # config.json.example + if [ -f "${script_dir}/config.json.example" ]; then + cp "${script_dir}/config.json.example" "${CONFIG_DIR}/" + msg_ok "Пример конфигурации скопирован" + else + msg_info "Скачивание config.json.example с GitHub..." + if command -v curl &> /dev/null; then + curl -fsSL "${github_raw_url}/config.json.example" -o "${CONFIG_DIR}/config.json.example" 2>/dev/null && \ + msg_ok "config.json.example скачан с GitHub" || \ + msg_warn "Не удалось скачать config.json.example" + fi + fi + + # README.md + if [ -f "${script_dir}/README.md" ]; then + cp "${script_dir}/README.md" "${APP_DIR}/" + msg_ok "README.md скопирован" + else + msg_info "Скачивание README.md с GitHub..." + if command -v curl &> /dev/null; then + curl -fsSL "${github_raw_url}/README.md" -o "${APP_DIR}/README.md" 2>/dev/null && \ + msg_ok "README.md скачан с GitHub" || \ + msg_warn "Не удалось скачать README.md" + fi + fi + + msg_info "Установка systemd файлов..." + + # Systemd service + if [ -f "${script_dir}/systemd/letsencrypt-regru.service" ]; then + cp "${script_dir}/systemd/letsencrypt-regru.service" "/etc/systemd/system/" + msg_ok "Service файл скопирован" + else + msg_info "Скачивание letsencrypt-regru.service с GitHub..." + if command -v curl &> /dev/null; then + curl -fsSL "${github_raw_url}/systemd/letsencrypt-regru.service" -o "/etc/systemd/system/letsencrypt-regru.service" 2>/dev/null && \ + msg_ok "Service файл скачан с GitHub" || \ + msg_warn "Не удалось скачать service файл, будет создан автоматически" + fi + fi + + # Systemd timer + if [ -f "${script_dir}/systemd/letsencrypt-regru.timer" ]; then + cp "${script_dir}/systemd/letsencrypt-regru.timer" "/etc/systemd/system/" + msg_ok "Timer файл скопирован" + else + msg_info "Скачивание letsencrypt-regru.timer с GitHub..." + if command -v curl &> /dev/null; then + curl -fsSL "${github_raw_url}/systemd/letsencrypt-regru.timer" -o "/etc/systemd/system/letsencrypt-regru.timer" 2>/dev/null && \ + msg_ok "Timer файл скачан с GitHub" || \ + msg_warn "Не удалось скачать timer файл, будет создан автоматически" + fi + fi + + msg_ok "Приложение установлено" +} + +# Создание конфигурационного файла +create_config() { + header "Создание конфигурации" + + local config_file="${CONFIG_DIR}/config.json" + + if [ -f "$config_file" ]; then + msg_warn "Файл конфигурации уже существует: $config_file" + read -p "Перезаписать? (y/N): " -n 1 -r + echo + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + msg_info "Пропуск создания конфигурации" + return + fi + fi + + msg_info "Интерактивная настройка конфигурации..." + echo "" + + read -p "Введите ваш домен (например, example.com): " domain + read -p "Введите email для уведомлений Let's Encrypt: " email + read -p "Введите имя пользователя reg.ru: " regru_user + read -s -p "Введите пароль reg.ru: " regru_pass + echo "" + + read -p "Создать wildcard сертификат (*.${domain})? (Y/n): " -n 1 -r + echo "" + wildcard="true" + if [[ $REPLY =~ ^[Nn]$ ]]; then + wildcard="false" + fi + + read -p "Включить интеграцию с Nginx Proxy Manager? (y/N): " -n 1 -r + echo "" + npm_enabled="false" + npm_host="http://10.10.10.14:81" + npm_email="admin@example.com" + npm_password="changeme" + + if [[ $REPLY =~ ^[Yy]$ ]]; then + npm_enabled="true" + read -p "Введите адрес NPM (например, http://10.10.10.14:81): " npm_host + read -p "Введите email для входа в NPM: " npm_email + read -s -p "Введите пароль NPM: " npm_password + echo "" + fi + + cat > "$config_file" < /etc/systemd/system/letsencrypt-regru.service < /etc/systemd/system/letsencrypt-regru.timer < /usr/local/bin/letsencrypt-regru </dev/null; then + echo "🔗 Интеграция с Nginx Proxy Manager: ВКЛЮЧЕНА" + 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 "" +} + +# Функция обновления +update_application() { + header "Обновление приложения" + + local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" + local github_raw_url="https://raw.githubusercontent.com/DFofanov/configure_nginx_manager/refs/heads/master" + + msg_info "Остановка сервиса..." + systemctl stop letsencrypt-regru.timer || true + + msg_info "Обновление файлов..." + + # Попытка скопировать локально или скачать с GitHub + if [ -n "${script_dir}" ] && [ -f "${script_dir}/letsencrypt_regru_api.py" ]; then + msg_info "Копирование из локальной директории..." + cp "${script_dir}/letsencrypt_regru_api.py" "${APP_DIR}/" + chmod 755 "${APP_DIR}/letsencrypt_regru_api.py" + msg_ok "Файл скопирован локально" + else + msg_info "Скачивание обновления с GitHub..." + if command -v curl &> /dev/null; then + if curl -fsSL "${github_raw_url}/letsencrypt_regru_api.py" -o "${APP_DIR}/letsencrypt_regru_api.py"; then + chmod 755 "${APP_DIR}/letsencrypt_regru_api.py" + msg_ok "Файл успешно скачан с GitHub" + else + msg_error "Не удалось скачать файл с GitHub" + return 1 + fi + else + msg_error "Не установлен curl для скачивания файлов" + msg_info "Установите: sudo apt-get install curl" + return 1 + fi + fi + + msg_info "Обновление Python зависимостей..." + source "${VENV_DIR}/bin/activate" + pip install --quiet --upgrade requests cryptography certbot + + msg_info "Перезапуск сервиса..." + systemctl daemon-reload + systemctl start letsencrypt-regru.timer + + msg_ok "Приложение обновлено" +} + +# Функция удаления +uninstall_application() { + header "Удаление приложения" + + msg_warn "ВНИМАНИЕ: Это удалит следующие компоненты:" + echo " • Приложение: ${APP_DIR}" + echo " • Systemd сервисы: /etc/systemd/system/letsencrypt-regru.*" + echo " • Команда: /usr/local/bin/letsencrypt-regru" + echo "" + msg_info "Будут сохранены:" + echo " • Сертификаты: ${CERT_DIR}" + echo " • Конфигурация: ${CONFIG_DIR}/config.json (можно удалить отдельно)" + echo " • Логи: ${LOG_DIR} (можно удалить отдельно)" + echo "" + read -p "Продолжить удаление? (y/N): " -n 1 -r + echo "" + + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + msg_info "Отмена удаления" + exit 0 + fi + + msg_info "Остановка и отключение сервисов..." + systemctl stop letsencrypt-regru.timer || true + systemctl stop letsencrypt-regru.service || true + systemctl disable letsencrypt-regru.timer || true + systemctl disable letsencrypt-regru.service || true + + msg_info "Удаление systemd файлов..." + rm -f /etc/systemd/system/letsencrypt-regru.service + rm -f /etc/systemd/system/letsencrypt-regru.timer + systemctl daemon-reload + + msg_info "Удаление файлов приложения..." + rm -rf "$APP_DIR" + rm -f /usr/local/bin/letsencrypt-regru + + msg_ok "Приложение удалено" + echo "" + + # Опционально удаляем конфигурацию + if [ -d "$CONFIG_DIR" ]; then + msg_warn "Удалить конфигурацию?" + echo " Путь: ${CONFIG_DIR}/config.json" + read -p "Удалить конфигурацию? (y/N): " -n 1 -r + echo "" + if [[ $REPLY =~ ^[Yy]$ ]]; then + rm -rf "$CONFIG_DIR" + msg_ok "Конфигурация удалена" + else + msg_info "Конфигурация сохранена: ${CONFIG_DIR}/config.json" + fi + fi + + # Опционально удаляем логи + if [ -d "$LOG_DIR" ]; then + msg_warn "Удалить логи?" + echo " Путь: ${LOG_DIR}" + read -p "Удалить логи? (y/N): " -n 1 -r + echo "" + if [[ $REPLY =~ ^[Yy]$ ]]; then + rm -rf "$LOG_DIR" + msg_ok "Логи удалены" + else + msg_info "Логи сохранены: ${LOG_DIR}" + fi + fi + + echo "" + msg_ok "Удаление завершено!" + msg_info "Сертификаты сохранены в: ${CERT_DIR}" +} + +# ============================================================================== +# Основная логика +# ============================================================================== + +main() { + clear + header "${APP_NAME} - Установка" + + # Проверка аргументов + case "${1:-install}" in + install) + check_root + detect_os + check_resources + install_dependencies + create_directories + setup_python_venv + install_application + create_config + create_systemd_service + create_aliases + test_certificate + display_summary + ;; + update) + check_root + update_application + msg_ok "Обновление завершено" + ;; + uninstall) + check_root + uninstall_application + ;; + *) + echo "Использование: $0 {install|update|uninstall}" + echo "" + echo " install - Установить приложение (по умолчанию)" + echo " update - Обновить приложение" + echo " uninstall - Удалить приложение" + exit 1 + ;; + esac +} + +# Запуск +main "${@}" diff --git a/letsencrypt_regru_api.py b/letsencrypt_regru_api.py new file mode 100644 index 0000000..0461c8a --- /dev/null +++ b/letsencrypt_regru_api.py @@ -0,0 +1,3191 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" +Скрипт для создания и обновления SSL сертификата Let's Encrypt +с использованием DNS-валидации через API reg.ru + +Автор: Фофанов Дмитрий +Дата: 27.10.2025 + +Описание: + Этот скрипт автоматизирует процесс получения и обновления SSL сертификатов + Let's Encrypt для доменов, зарегистрированных на reg.ru, используя DNS-01 challenge. + Скрипт напрямую работает с API reg.ru для управления DNS записями. + +Требования: + - Python 3.6+ + - requests + - certbot + - cryptography + +Установка зависимостей: + pip install requests certbot cryptography +""" + +import os +import sys +import json +import time +import logging +import argparse +import subprocess +from datetime import datetime, timedelta +from typing import Dict, List, Optional, Tuple + +try: + import requests +except ImportError: + print("ОШИБКА: Необходимо установить модуль 'requests'") + print("Выполните: pip install requests") + sys.exit(1) + +try: + from cryptography import x509 + from cryptography.x509.oid import NameOID, ExtensionOID + from cryptography.hazmat.primitives import hashes, serialization + from cryptography.hazmat.primitives.asymmetric import rsa + from cryptography.hazmat.backends import default_backend +except ImportError: + print("ОШИБКА: Необходимо установить модуль 'cryptography'") + print("Выполните: pip install cryptography") + sys.exit(1) + +# ============================================================================== +# КОНФИГУРАЦИЯ +# ============================================================================== + +# Настройки по умолчанию +DEFAULT_CONFIG = { + # Учетные данные API reg.ru + "regru_username": "your_username", + "regru_password": "your_password", + + # Параметры домена + "domain": "example.com", + "domains": [], # Список доменов для управления из одного конфига + "wildcard": True, # Создавать wildcard сертификат (*.domain.com) + + # Email для уведомлений Let's Encrypt + "email": "admin@example.com", + + # Директории + "cert_dir": "/etc/letsencrypt/live", + "log_file": "/var/log/letsencrypt_regru.log", + + # Параметры DNS + "dns_propagation_wait": 60, # Время ожидания распространения DNS (секунды) + "dns_check_attempts": 10, # Количество попыток проверки DNS + "dns_check_interval": 10, # Интервал между проверками DNS (секунды) + + # Параметры обновления сертификата + "renewal_days": 30, # За сколько дней до истечения обновлять (по умолчанию 30) + + # Настройки Nginx Proxy Manager + "npm_enabled": False, # Включить интеграцию с NPM + "npm_host": "http://10.10.10.14:81", # Адрес NPM + "npm_email": "admin@example.com", # Email для входа в NPM + "npm_password": "changeme", # Пароль NPM +} + +# API endpoints для reg.ru +REGRU_API_URL = "https://api.reg.ru/api/regru2" + +# ============================================================================== +# НАСТРОЙКА ЛОГИРОВАНИЯ +# ============================================================================== + +def setup_logging(log_file: str, verbose: bool = False) -> logging.Logger: + """ + Настройка системы логирования + + Args: + log_file: Путь к файлу лога + verbose: Режим подробного вывода + + Returns: + Logger объект + """ + log_level = logging.DEBUG if verbose else logging.INFO + + # Создаем директорию для логов, если не существует + log_dir = os.path.dirname(log_file) + if log_dir and not os.path.exists(log_dir): + os.makedirs(log_dir, exist_ok=True) + + # Настройка форматирования + formatter = logging.Formatter( + '%(asctime)s - %(levelname)s - %(message)s', + datefmt='%d.%m.%Y %H:%M:%S' + ) + + # Создаем logger + logger = logging.getLogger('LetsEncrypt_RegRU') + logger.setLevel(log_level) + + # Не добавляем обработчики повторно (при повторном вызове) + if not logger.handlers: + # Обработчик для файла + file_handler = logging.FileHandler(log_file, encoding='utf-8') + file_handler.setLevel(log_level) + file_handler.setFormatter(formatter) + + # Обработчик для консоли + console_handler = logging.StreamHandler(sys.stdout) + console_handler.setLevel(log_level) + console_handler.setFormatter(formatter) + + # Добавляем обработчики + logger.addHandler(file_handler) + logger.addHandler(console_handler) + + return logger + + +# ============================================================================== +# КЛАСС ДЛЯ РАБОТЫ С API REG.RU +# ============================================================================== + +class RegRuAPI: + """Класс для работы с API reg.ru""" + + def __init__(self, username: str, password: str, logger: logging.Logger): + """ + Инициализация API клиента + + Args: + username: Имя пользователя reg.ru + password: Пароль reg.ru + logger: Logger объект + """ + self.username = username + self.password = password + self.logger = logger + self.session = requests.Session() + + def _make_request(self, method: str, params: Dict) -> Dict: + """ + Выполнение запроса к API reg.ru + + Args: + method: Название метода API + params: Параметры запроса + + Returns: + Ответ API в формате dict + """ + url = f"{REGRU_API_URL}/{method}" + + # Добавляем учетные данные к параметрам + params.update({ + "username": self.username, + "password": self.password, + "output_format": "json" + }) + + try: + self.logger.debug(f"Отправка запроса к API: {method}") + response = self.session.post(url, data=params, timeout=30) + response.raise_for_status() + + result = response.json() + + if result.get("result") == "success": + self.logger.debug(f"Запрос {method} выполнен успешно") + return result + else: + error_msg = result.get("error_text", "Неизвестная ошибка") + error_code = result.get("error_code", "unknown") + + # Обработка специфических ошибок + if "Access to API from this IP denied" in error_msg or error_code == "IP_DENIED": + self.logger.error("=" * 80) + self.logger.error("🚫 ОШИБКА ДОСТУПА К API REG.RU") + self.logger.error("=" * 80) + self.logger.error("❌ Доступ к API заблокирован для текущего IP адреса") + self.logger.error("") + self.logger.error("🔧 РЕШЕНИЕ ПРОБЛЕМЫ:") + self.logger.error("1. Войдите в личный кабинет reg.ru") + self.logger.error("2. Перейдите в 'Настройки' → 'Безопасность' → 'API'") + self.logger.error("3. Добавьте текущий IP адрес в список разрешенных") + self.logger.error("4. Или отключите ограничение по IP (менее безопасно)") + self.logger.error("") + self.logger.error("🌐 Текущий IP можно узнать командой:") + self.logger.error(" curl -s https://ipinfo.io/ip") + self.logger.error(" или на сайте: https://whatismyipaddress.com/") + self.logger.error("") + self.logger.error("📚 Документация API: https://www.reg.ru/support/api") + self.logger.error("=" * 80) + elif "Invalid username or password" in error_msg: + self.logger.error("=" * 80) + self.logger.error("🔐 ОШИБКА АУТЕНТИФИКАЦИИ") + self.logger.error("=" * 80) + self.logger.error("❌ Неверные учетные данные") + self.logger.error("🔧 Проверьте username и password в конфигурации") + self.logger.error("=" * 80) + elif "IP exceeded allowed connection rate" in error_msg or error_code == "IP_EXCEEDED_ALLOWED_CONNECTION_RATE": + self.logger.error("=" * 80) + self.logger.error("⏱️ ОШИБКА: ПРЕВЫШЕН ЛИМИТ ЗАПРОСОВ К API") + self.logger.error("=" * 80) + self.logger.error("❌ IP адрес превысил допустимую частоту подключений к API reg.ru") + self.logger.error("") + self.logger.error("🔧 РЕШЕНИЕ ПРОБЛЕМЫ:") + self.logger.error("1. Подождите 5-10 минут перед следующей попыткой") + self.logger.error("2. Не запускайте скрипт слишком часто") + self.logger.error("3. Используйте --test-api только для диагностики") + self.logger.error("4. Настройте systemd timer для автоматических проверок (раз в день)") + self.logger.error("") + self.logger.error("📊 ЛИМИТЫ API REG.RU:") + self.logger.error(" • Обычно: не более 10-20 запросов в минуту с одного IP") + self.logger.error(" • Рекомендация: проверка сертификатов 1-2 раза в день") + self.logger.error("") + self.logger.error("⚙️ АВТОМАТИЗАЦИЯ:") + self.logger.error(" sudo systemctl enable letsencrypt-regru.timer") + self.logger.error(" sudo systemctl start letsencrypt-regru.timer") + self.logger.error("=" * 80) + else: + self.logger.error(f"Ошибка API reg.ru: {error_msg} (код: {error_code})") + + raise Exception(f"API Error: {error_msg}") + + except requests.exceptions.Timeout: + self.logger.error("Таймаут при обращении к API reg.ru (30 сек)") + raise + except requests.exceptions.ConnectionError: + self.logger.error("Ошибка соединения с API reg.ru. Проверьте интернет подключение") + raise + except requests.exceptions.RequestException as e: + self.logger.error(f"Ошибка HTTP запроса: {e}") + raise + + def get_zone_records(self, domain: str) -> List[Dict]: + """ + Получение DNS записей домена + + Args: + domain: Доменное имя + + Returns: + Список DNS записей + """ + self.logger.info(f"Получение DNS записей для домена: {domain}") + + # Задержка перед запросом (защита от rate limit) + time.sleep(1) + + params = { + "domain_name": domain, + } + + result = self._make_request("zone/get_resource_records", params) + + if "answer" in result and "records" in result["answer"]: + records = result["answer"]["records"] + self.logger.info(f"Получено {len(records)} DNS записей") + return records + else: + self.logger.warning("DNS записи не найдены") + return [] + + def add_txt_record(self, domain: str, subdomain: str, txt_value: str) -> bool: + """ + Добавление TXT записи для DNS валидации + + Args: + domain: Основной домен + subdomain: Поддомен (например, _acme-challenge) + txt_value: Значение TXT записи + + Returns: + True если успешно, False в противном случае + """ + self.logger.info(f"Добавление TXT записи: {subdomain}.{domain} = {txt_value}") + + # Задержка перед запросом (защита от rate limit) + time.sleep(2) + + params = { + "domain_name": domain, + "subdomain": subdomain, + "text": txt_value, + "output_content_type": "plain" + } + + try: + self._make_request("zone/add_txt", params) + self.logger.info("TXT запись успешно добавлена") + return True + except Exception as e: + self.logger.error(f"Не удалось добавить TXT запись: {e}") + return False + + def get_current_ip(self) -> str: + """ + Получение текущего публичного IP адреса + + Returns: + IP адрес или 'Неизвестно' + """ + try: + response = requests.get("https://ipinfo.io/ip", timeout=10) + if response.status_code == 200: + return response.text.strip() + except: + try: + response = requests.get("https://api.ipify.org", timeout=10) + if response.status_code == 200: + return response.text.strip() + except: + pass + return "Неизвестно" + + def test_api_access(self) -> bool: + """ + Проверка доступности API reg.ru + + Returns: + True если API доступен + """ + # Получаем текущий IP + current_ip = self.get_current_ip() + self.logger.info(f"Текущий IP адрес: {current_ip}") + self.logger.info("Проверка доступности API reg.ru...") + + try: + # Небольшая задержка перед запросом (защита от rate limit) + time.sleep(1) + + # Простой запрос для проверки доступа + params = {} + result = self._make_request("user/get_balance", params) + + if result and result.get("result") == "success": + balance = result.get("answer", {}).get("prepay", "Неизвестно") + self.logger.info(f"✅ API reg.ru доступен. Баланс: {balance} руб.") + return True + else: + self.logger.error("❌ API reg.ru недоступен") + return False + + except Exception as e: + self.logger.error(f"❌ Не удалось подключиться к API reg.ru: {e}") + return False + + def remove_txt_record(self, domain: str, subdomain: str, txt_value: str) -> bool: + """ + Удаление TXT записи + + Args: + domain: Основной домен + subdomain: Поддомен + txt_value: Значение TXT записи + + Returns: + True если успешно, False в противном случае + """ + self.logger.info(f"Удаление TXT записи: {subdomain}.{domain}") + + try: + # Сначала получаем список всех записей + records = self.get_zone_records(domain) + + # Ищем нужную TXT запись + record_id = None + for record in records: + if (record.get("rectype") == "TXT" and + record.get("subdomain") == subdomain and + record.get("text") == txt_value): + record_id = record.get("id") + break + + if not record_id: + self.logger.warning("TXT запись для удаления не найдена") + # Не считаем это критической ошибкой + return True + + params = { + "domain_name": domain, + "record_id": record_id + } + + self._make_request("zone/remove_record", params) + self.logger.info("TXT запись успешно удалена") + return True + + except Exception as e: + self.logger.error(f"Не удалось удалить TXT запись: {e}") + # Для cleanup hook не критично, если не удалось удалить + self.logger.warning("Продолжаем выполнение, несмотря на ошибку удаления") + return True + + +# ============================================================================== +# КЛАСС ДЛЯ РАБОТЫ С NGINX PROXY MANAGER +# ============================================================================== + +class NginxProxyManagerAPI: + """Класс для работы с API Nginx Proxy Manager""" + + def __init__(self, host: str, email: str, password: str, logger: logging.Logger): + """ + Инициализация API клиента NPM + + Args: + host: URL адрес NPM (например, http://10.10.10.14:81) + email: Email для входа + password: Пароль + logger: Logger объект + """ + self.host = host.rstrip('/') + self.email = email + self.password = password + self.logger = logger + self.session = requests.Session() + self.token = None + + def login(self) -> bool: + """ + Авторизация в Nginx Proxy Manager + + Returns: + True если успешно + """ + url = f"{self.host}/api/tokens" + + payload = { + "identity": self.email, + "secret": self.password + } + + try: + self.logger.info("Авторизация в Nginx Proxy Manager...") + response = self.session.post(url, json=payload, timeout=10) + response.raise_for_status() + + data = response.json() + self.token = data.get("token") + + if self.token: + # Устанавливаем токен в заголовки для последующих запросов + self.session.headers.update({ + "Authorization": f"Bearer {self.token}" + }) + self.logger.info("Авторизация в NPM успешна") + return True + else: + self.logger.error("Токен не получен при авторизации") + return False + + except requests.exceptions.RequestException as e: + self.logger.error(f"Ошибка при авторизации в NPM: {e}") + return False + + def get_certificates(self) -> List[Dict]: + """ + Получение списка сертификатов + + Returns: + Список сертификатов + """ + url = f"{self.host}/api/nginx/certificates" + + try: + self.logger.debug("Получение списка сертификатов из NPM...") + response = self.session.get(url, timeout=10) + response.raise_for_status() + + certificates = response.json() + self.logger.debug(f"Получено {len(certificates)} сертификатов") + return certificates + + except requests.exceptions.RequestException as e: + self.logger.error(f"Ошибка при получении списка сертификатов: {e}") + return [] + + def get_certificate_by_id(self, cert_id: int) -> Optional[Dict]: + """Возвращает данные сертификата по ID из NPM""" + url = f"{self.host}/api/nginx/certificates/{cert_id}" + try: + self.logger.debug(f"Запрос сертификата ID={cert_id} из NPM...") + response = self.session.get(url, timeout=10) + response.raise_for_status() + return response.json() + except requests.exceptions.RequestException as e: + self.logger.warning(f"Не удалось получить сертификат ID {cert_id}: {e}") + return None + + def wait_for_certificate_parse(self, cert_id: int, timeout_seconds: int = 30, interval_seconds: float = 2.0) -> Optional[Dict]: + """ + Ожидает, пока NPM распарсит загруженный сертификат и заполнит поля domain_names и expires_on. + + Возвращает актуальные данные сертификата или None по таймауту. + """ + start = time.time() + last: Optional[Dict] = None + while time.time() - start < timeout_seconds: + cert = self.get_certificate_by_id(cert_id) + if cert: + last = cert + domains = cert.get('domain_names', []) or [] + created_on = cert.get('created_on') + expires_on = cert.get('expires_on') + self.logger.debug(f"Проверка парсинга NPM: domains={domains}, expires_on={expires_on}, created_on={created_on}") + # Готово: домены определены и expires_on отличается от created_on + if domains and expires_on and (not created_on or expires_on != created_on): + self.logger.info("NPM завершил парсинг сертификата") + return cert + time.sleep(interval_seconds) + return last + + def find_certificate_by_domain(self, domain: str) -> Optional[Dict]: + """ + Поиск сертификата по домену + + Args: + domain: Доменное имя + + Returns: + Данные сертификата или None + """ + certificates = self.get_certificates() + + self.logger.debug(f"Поиск сертификата для домена: {domain}") + self.logger.debug(f"Всего сертификатов в NPM: {len(certificates)}") + + # Список доменов для поиска (основной домен и wildcard) + search_domains = [domain, f"*.{domain}"] + + for cert in certificates: + cert_id = cert.get("id") + cert_name = cert.get("nice_name", "Unknown") + domains = cert.get("domain_names", []) + + self.logger.debug(f"Проверка сертификата ID={cert_id}, name='{cert_name}', domains={domains}") + + # Проверяем точное совпадение доменов + for search_domain in search_domains: + if search_domain in domains: + self.logger.info(f"✅ Найден существующий сертификат для {domain}") + self.logger.info(f" ID: {cert_id}, Домены: {', '.join(domains)}") + return cert + + # Если NPM ещё не распарсил домены (domains == []), проверяем по nice_name + # Это предотвращает дублирование сертификатов при первичной загрузке + if not domains: + if cert_name.strip().lower() == domain.strip().lower() or cert_name.strip().lower() == f"*.{domain.strip().lower()}": + self.logger.info(f"✅ Найден сертификат по имени (домены ещё не распознаны NPM)") + self.logger.info(f" ID: {cert_id}, Имя: {cert_name}") + return cert + + self.logger.debug(f"Сертификат для {domain} не найден") + return None + + def upload_certificate(self, domain: str, cert_path: str, key_path: str, + chain_path: Optional[str] = None) -> Optional[Dict]: + """ + Загрузка нового сертификата в NPM + + ВАЖНО: NPM автоматически извлекает информацию из сертификата. + Мы загружаем сертификат через веб-интерфейс формы (multipart/form-data), + а не через JSON API, так как JSON endpoint имеет строгую валидацию схемы. + + Args: + domain: Основной домен + cert_path: Путь к файлу сертификата + key_path: Путь к приватному ключу + chain_path: Путь к цепочке сертификатов (опционально) + + Returns: + Данные созданного сертификата или None + """ + url = f"{self.host}/api/nginx/certificates" + + try: + # Читаем приватный ключ + with open(key_path, 'r') as f: + certificate_key = f.read() + + # Определяем, какие файлы использовать + cert_dir = os.path.dirname(cert_path) + cert_only_path = os.path.join(cert_dir, "cert.pem") + chain_only_path = os.path.join(cert_dir, "chain.pem") + + # Используем отдельные файлы cert.pem и chain.pem + # NPM лучше работает с разделенными файлами + if os.path.exists(cert_only_path) and os.path.exists(chain_only_path): + self.logger.info("Загружаем cert.pem и chain.pem отдельно") + with open(cert_only_path, 'rb') as f: + certificate = f.read().decode('utf-8') + with open(chain_only_path, 'rb') as f: + intermediate_certificate = f.read().decode('utf-8') + self.logger.info(f"Загружено: cert.pem ({len(certificate)} байт), chain.pem ({len(intermediate_certificate)} байт)") + else: + # Fallback: загружаем fullchain целиком + self.logger.info("cert.pem/chain.pem не найдены, загружаем fullchain.pem") + with open(cert_path, 'rb') as f: + certificate = f.read().decode('utf-8') + intermediate_certificate = "" + self.logger.info(f"Загружено: fullchain.pem ({len(certificate)} байт)") + + # Проверяем корректность сертификатов + if not certificate.strip().startswith('-----BEGIN CERTIFICATE-----'): + self.logger.error("Ошибка: Основной сертификат не начинается с BEGIN CERTIFICATE") + return None + + if intermediate_certificate and not intermediate_certificate.strip().startswith('-----BEGIN CERTIFICATE-----'): + self.logger.error("Ошибка: Промежуточный сертификат не начинается с BEGIN CERTIFICATE") + return None + + # Показываем первые строки для диагностики + self.logger.debug(f"Основной сертификат начинается с: {certificate[:60]}...") + if intermediate_certificate: + self.logger.debug(f"Промежуточный сертификат начинается с: {intermediate_certificate[:60]}...") + + # NPM Web UI использует multipart/form-data для загрузки custom сертификатов + # Загружаем cert.pem и chain.pem отдельно + files = { + 'certificate': ('cert.pem', certificate, 'application/x-pem-file'), + 'certificate_key': ('privkey.pem', certificate_key, 'application/x-pem-file'), + } + + # Добавляем intermediate_certificate если есть + if intermediate_certificate and intermediate_certificate.strip(): + files['intermediate_certificate'] = ('chain.pem', intermediate_certificate, 'application/x-pem-file') + self.logger.info(f"Загружаем cert ({len(certificate)} байт) + chain ({len(intermediate_certificate)} байт) + privkey") + else: + self.logger.info(f"Загружаем cert ({len(certificate)} байт) + privkey (без chain)") + + # Дополнительные поля формы (только разрешенные NPM поля) + data = { + 'nice_name': domain, + 'provider': 'other', # other для custom сертификатов + } + + self.logger.debug("NPM будет автоматически извлекать домены и дату истечения из сертификата") + + self.logger.debug(f"Uploading certificate as multipart/form-data") + self.logger.debug(f"Files: {list(files.keys())}") + self.logger.debug(f"Data: {data}") + self.logger.info(f"Загрузка сертификата для {domain} в NPM...") + + # Отправляем как multipart/form-data + response = self.session.post(url, files=files, data=data, timeout=30) + response.raise_for_status() + + result = response.json() + cert_id = result.get("id") + + if cert_id: + self.logger.info(f"Сертификат успешно загружен в NPM (ID: {cert_id})") + + # Показываем что вернул NPM + self.logger.debug(f"Полный ответ NPM: {json.dumps(result, indent=2, ensure_ascii=False)}") + + expires = result.get("expires_on") + if expires: + self.logger.info(f"NPM определил дату истечения: {expires}") + else: + self.logger.warning("NPM не вернул дату истечения сертификата!") + + # Проверяем meta.letsencrypt_email - если есть, значит NPM считает это Let's Encrypt + meta = result.get("meta", {}) + if meta: + self.logger.debug(f"NPM meta: {json.dumps(meta, indent=2, ensure_ascii=False)}") + + # После загрузки подождём, пока NPM распарсит сертификат (domain_names, expires_on) + try: + parsed = self.wait_for_certificate_parse(cert_id, timeout_seconds=12, interval_seconds=1) + if parsed: + self.logger.info( + f"Итоговые данные NPM: домены={parsed.get('domain_names', [])}, истекает={parsed.get('expires_on')}" + ) + return parsed + except Exception as e: + self.logger.warning(f"Не удалось дождаться парсинга сертификата в NPM: {e}") + + return result + else: + self.logger.error("Не удалось получить ID созданного сертификата") + self.logger.error(f"Ответ NPM: {result}") + return None + + except FileNotFoundError as e: + self.logger.error(f"Файл сертификата не найден: {e}") + return None + except requests.exceptions.RequestException as e: + self.logger.error(f"Ошибка при загрузке сертификата в NPM: {e}") + if hasattr(e.response, 'text'): + self.logger.error(f"Ответ сервера: {e.response.text}") + return None + + def update_certificate(self, cert_id: int, cert_path: str, key_path: str, + chain_path: Optional[str] = None) -> bool: + """ + Обновление существующего сертификата + + Args: + cert_id: ID сертификата в NPM + cert_path: Путь к файлу сертификата + key_path: Путь к приватному ключу + chain_path: Путь к цепочке сертификатов (опционально) + + Returns: + True если успешно + """ + url = f"{self.host}/api/nginx/certificates/{cert_id}" + + try: + # Читаем приватный ключ + with open(key_path, 'r') as f: + certificate_key = f.read() + + # Определяем, какие файлы использовать + cert_dir = os.path.dirname(cert_path) + cert_only_path = os.path.join(cert_dir, "cert.pem") + chain_only_path = os.path.join(cert_dir, "chain.pem") + + # Используем cert.pem и chain.pem при обновлении, при отсутствии – fullchain + files: Dict[str, Tuple[str, str, str]] + if os.path.exists(cert_only_path) and os.path.exists(chain_only_path): + self.logger.info("Обновление: используем cert.pem и chain.pem") + with open(cert_only_path, 'rb') as f: + certificate = f.read().decode('utf-8') + with open(chain_only_path, 'rb') as f: + intermediate_certificate = f.read().decode('utf-8') + self.logger.debug(f"Загружено: cert.pem ({len(certificate)} байт), chain.pem ({len(intermediate_certificate)} байт)") + files = { + 'certificate': ('cert.pem', certificate, 'application/x-pem-file'), + 'certificate_key': ('privkey.pem', certificate_key, 'application/x-pem-file'), + 'intermediate_certificate': ('chain.pem', intermediate_certificate, 'application/x-pem-file'), + } + else: + self.logger.info("Обновление: cert/chain не найдены, используем fullchain.pem") + with open(cert_path, 'rb') as f: + certificate = f.read().decode('utf-8') + self.logger.debug(f"Загружено: fullchain.pem ({len(certificate)} байт)") + files = { + 'certificate': ('fullchain.pem', certificate, 'application/x-pem-file'), + 'certificate_key': ('privkey.pem', certificate_key, 'application/x-pem-file'), + } + + # Дополнительные поля формы + data = { + 'provider': 'other', # other для custom сертификатов + } + + self.logger.info(f"Обновление сертификата ID {cert_id} в NPM...") + response = self.session.put(url, files=files, data=data, timeout=30) + response.raise_for_status() + + self.logger.info("Сертификат успешно обновлен в NPM") + # Дождаться, пока NPM обновит метаданные + try: + parsed = self.wait_for_certificate_parse(cert_id, timeout_seconds=12, interval_seconds=1) + if parsed: + self.logger.info( + f"Итоговые данные NPM после обновления: домены={parsed.get('domain_names', [])}, истекает={parsed.get('expires_on')}" + ) + except Exception as e: + self.logger.warning(f"Не удалось дождаться обновления метаданных сертификата: {e}") + return True + + except FileNotFoundError as e: + self.logger.error(f"Файл сертификата не найден: {e}") + return False + except requests.exceptions.RequestException as e: + self.logger.error(f"Ошибка при обновлении сертификата в NPM: {e}") + if hasattr(e.response, 'text'): + self.logger.error(f"Ответ сервера: {e.response.text}") + return False + + def delete_certificate(self, cert_id: int) -> bool: + """ + Удаление сертификата из NPM + + Args: + cert_id: ID сертификата в NPM + + Returns: + True если успешно + """ + url = f"{self.host}/api/nginx/certificates/{cert_id}" + + try: + self.logger.info(f"Удаление сертификата ID {cert_id} из NPM...") + response = self.session.delete(url, timeout=10) + response.raise_for_status() + + self.logger.info(f"✅ Сертификат ID {cert_id} успешно удален из NPM") + return True + + except requests.exceptions.RequestException as e: + self.logger.error(f"Ошибка при удалении сертификата: {e}") + if hasattr(e.response, 'text'): + self.logger.error(f"Ответ сервера: {e.response.text}") + return False + + def sync_certificate(self, domain: str, cert_dir: str) -> bool: + """ + Синхронизация сертификата с NPM (создание или обновление) + + Args: + domain: Доменное имя + cert_dir: Директория с сертификатами Let's Encrypt + + Returns: + True если успешно + """ + # Пути к файлам сертификата + cert_path = os.path.join(cert_dir, "cert.pem") + key_path = os.path.join(cert_dir, "privkey.pem") + chain_path = os.path.join(cert_dir, "chain.pem") + fullchain_path = os.path.join(cert_dir, "fullchain.pem") + + # Проверяем наличие файлов + if not os.path.exists(cert_path) or not os.path.exists(key_path): + self.logger.error(f"Файлы сертификата не найдены в {cert_dir}") + return False + + # Авторизуемся в NPM + if not self.login(): + return False + + # Проверяем, существует ли уже сертификат для этого домена + existing_cert = self.find_certificate_by_domain(domain) + + # Используем fullchain если доступен, иначе cert + chain + if os.path.exists(fullchain_path): + final_cert_path = fullchain_path + final_chain_path = None + else: + final_cert_path = cert_path + final_chain_path = chain_path if os.path.exists(chain_path) else None + + if existing_cert: + # Обновляем существующий сертификат + cert_id = existing_cert.get("id") + self.logger.info(f"Обновление существующего сертификата (ID: {cert_id})") + return self.update_certificate(cert_id, final_cert_path, key_path, final_chain_path) + else: + # Создаем новый сертификат + self.logger.info("Создание нового сертификата в NPM") + result = self.upload_certificate(domain, final_cert_path, key_path, final_chain_path) + return result is not None + + +# ============================================================================== +# КЛАСС ДЛЯ ГЕНЕРАЦИИ ТЕСТОВЫХ СЕРТИФИКАТОВ +# ============================================================================== + +class TestCertificateGenerator: + """Класс для генерации самоподписанных тестовых SSL сертификатов""" + + def __init__(self, logger: logging.Logger): + """ + Инициализация генератора тестовых сертификатов + + Args: + logger: Logger объект + """ + self.logger = logger + + def generate_self_signed_certificate( + self, + domain: str, + wildcard: bool = False, + output_dir: str = "/etc/letsencrypt/live", + validity_days: int = 90 + ) -> bool: + """ + Генерация самоподписанного SSL сертификата для тестирования + + Args: + domain: Основной домен + wildcard: Создать wildcard сертификат + output_dir: Директория для сохранения сертификата + validity_days: Срок действия сертификата в днях (по умолчанию 90) + + Returns: + True если сертификат создан успешно, False в противном случае + """ + try: + self.logger.info("=" * 80) + self.logger.info("ГЕНЕРАЦИЯ ТЕСТОВОГО САМОПОДПИСАННОГО СЕРТИФИКАТА") + self.logger.info("=" * 80) + self.logger.info(f"Домен: {domain}") + self.logger.info(f"Wildcard: {wildcard}") + self.logger.info(f"Срок действия: {validity_days} дней") + self.logger.info("⚠️ ВНИМАНИЕ: Это тестовый сертификат, не для production!") + + # Создаем директорию для сертификата + cert_dir = os.path.join(output_dir, domain) + os.makedirs(cert_dir, exist_ok=True) + self.logger.info(f"Директория: {cert_dir}") + + # Генерируем приватный ключ + self.logger.info("Генерация приватного ключа RSA 2048 бит...") + private_key = rsa.generate_private_key( + public_exponent=65537, + key_size=2048, + backend=default_backend() + ) + + # Сохраняем приватный ключ + key_path = os.path.join(cert_dir, "privkey.pem") + with open(key_path, "wb") as f: + f.write(private_key.private_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PrivateFormat.TraditionalOpenSSL, + encryption_algorithm=serialization.NoEncryption() + )) + os.chmod(key_path, 0o600) + self.logger.info(f"✓ Приватный ключ сохранен: {key_path}") + + # Подготовка данных для сертификата + subject = issuer = x509.Name([ + x509.NameAttribute(NameOID.COUNTRY_NAME, "RU"), + x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, "Moscow"), + x509.NameAttribute(NameOID.LOCALITY_NAME, "Moscow"), + x509.NameAttribute(NameOID.ORGANIZATION_NAME, "Test Certificate"), + x509.NameAttribute(NameOID.COMMON_NAME, domain), + ]) + + # Создаем список альтернативных имен (SAN) + san_list = [x509.DNSName(domain)] + if wildcard: + san_list.append(x509.DNSName(f"*.{domain}")) + + # Генерируем сертификат + self.logger.info("Генерация самоподписанного сертификата...") + cert = ( + x509.CertificateBuilder() + .subject_name(subject) + .issuer_name(issuer) + .public_key(private_key.public_key()) + .serial_number(x509.random_serial_number()) + .not_valid_before(datetime.utcnow()) + .not_valid_after(datetime.utcnow() + timedelta(days=validity_days)) + .add_extension( + x509.SubjectAlternativeName(san_list), + critical=False, + ) + .add_extension( + x509.BasicConstraints(ca=False, path_length=None), + critical=True, + ) + .add_extension( + x509.KeyUsage( + digital_signature=True, + key_encipherment=True, + content_commitment=False, + data_encipherment=False, + key_agreement=False, + key_cert_sign=False, + crl_sign=False, + encipher_only=False, + decipher_only=False, + ), + critical=True, + ) + .add_extension( + x509.ExtendedKeyUsage([ + x509.oid.ExtendedKeyUsageOID.SERVER_AUTH, + x509.oid.ExtendedKeyUsageOID.CLIENT_AUTH, + ]), + critical=False, + ) + .sign(private_key, hashes.SHA256(), default_backend()) + ) + + # Сохраняем сертификат + cert_path = os.path.join(cert_dir, "cert.pem") + with open(cert_path, "wb") as f: + f.write(cert.public_bytes(serialization.Encoding.PEM)) + self.logger.info(f"✓ Сертификат сохранен: {cert_path}") + + # Создаем fullchain (для самоподписанного это просто копия cert) + fullchain_path = os.path.join(cert_dir, "fullchain.pem") + with open(fullchain_path, "wb") as f: + f.write(cert.public_bytes(serialization.Encoding.PEM)) + self.logger.info(f"✓ Fullchain сохранен: {fullchain_path}") + + # Создаем chain.pem (пустой для самоподписанного) + chain_path = os.path.join(cert_dir, "chain.pem") + with open(chain_path, "w") as f: + f.write("") + self.logger.info(f"✓ Chain файл создан: {chain_path}") + + # Выводим информацию о сертификате + self.logger.info("") + self.logger.info("=" * 80) + self.logger.info("ИНФОРМАЦИЯ О СЕРТИФИКАТЕ") + self.logger.info("=" * 80) + self.logger.info(f"Домен: {domain}") + if wildcard: + self.logger.info(f"Wildcard: *.{domain}") + self.logger.info(f"Действителен с: {cert.not_valid_before}") + self.logger.info(f"Действителен до: {cert.not_valid_after}") + self.logger.info(f"Серийный номер: {cert.serial_number}") + self.logger.info("") + self.logger.info("📁 Файлы сертификата:") + self.logger.info(f" • Приватный ключ: {key_path}") + self.logger.info(f" • Сертификат: {cert_path}") + self.logger.info(f" • Fullchain: {fullchain_path}") + self.logger.info(f" • Chain: {chain_path}") + self.logger.info("") + self.logger.info("⚠️ ВНИМАНИЕ:") + self.logger.info(" Это самоподписанный тестовый сертификат!") + self.logger.info(" Браузеры будут показывать предупреждение о безопасности.") + self.logger.info(" Используйте ТОЛЬКО для тестирования и разработки!") + self.logger.info(" Для production используйте настоящие Let's Encrypt сертификаты.") + self.logger.info("=" * 80) + + return True + + except Exception as e: + self.logger.error(f"Ошибка при генерации тестового сертификата: {e}") + import traceback + self.logger.error(traceback.format_exc()) + return False + + +# ============================================================================== +# КЛАСС ДЛЯ РАБОТЫ С CERTBOT +# ============================================================================== + +class LetsEncryptManager: + """Класс для управления сертификатами Let's Encrypt""" + + def __init__(self, config: Dict, api: RegRuAPI, logger: logging.Logger): + """ + Инициализация менеджера сертификатов + + Args: + config: Конфигурация + api: API клиент reg.ru + logger: Logger объект + """ + self.config = config + self.api = api + self.logger = logger + self.domain = config["domain"] + self.email = config["email"] + self.cert_dir = os.path.join(config["cert_dir"], self.domain) + + def check_certbot_installed(self) -> bool: + """ + Проверка установки certbot + + Returns: + True если certbot установлен + """ + try: + result = subprocess.run( + ["certbot", "--version"], + capture_output=True, + text=True, + check=True + ) + self.logger.debug(f"Certbot установлен: {result.stdout.strip()}") + return True + except (subprocess.CalledProcessError, FileNotFoundError): + 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 is_staging_certificate(self) -> bool: + """ + Проверка, является ли сертификат staging (тестовым) + + Returns: + True если сертификат staging + """ + cert_file = os.path.join(self.cert_dir, "cert.pem") + + if not os.path.exists(cert_file): + return False + + try: + from cryptography import x509 + from cryptography.hazmat.backends import default_backend + + with open(cert_file, "rb") as f: + cert_data = f.read() + cert = x509.load_pem_x509_certificate(cert_data, default_backend()) + + # Проверяем issuer (издателя сертификата) + issuer = cert.issuer.rfc4514_string() + + # Staging сертификаты Let's Encrypt содержат "Fake LE" или "Staging" в issuer + is_staging = ( + "fake" in issuer.lower() or + "staging" in issuer.lower() or + "test" in issuer.lower() + ) + + return is_staging + + except Exception as e: + self.logger.debug(f"Не удалось проверить тип сертификата: {e}") + return False + + def check_certificate_expiry(self) -> Optional[int]: + """ + Проверка срока действия сертификата + + Returns: + Количество дней до истечения или None если сертификат не найден + """ + cert_file = os.path.join(self.cert_dir, "cert.pem") + + if not os.path.exists(cert_file): + self.logger.info("Сертификат не найден") + return None + + try: + from cryptography import x509 + from cryptography.hazmat.backends import default_backend + import warnings + + with open(cert_file, "rb") as f: + cert_data = f.read() + cert = x509.load_pem_x509_certificate(cert_data, default_backend()) + + # Используем not_valid_after_utc для избежания предупреждения + try: + expiry_date = cert.not_valid_after_utc.replace(tzinfo=None) + except AttributeError: + # Для старых версий cryptography + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + expiry_date = cert.not_valid_after + + days_left = (expiry_date - datetime.now()).days + + self.logger.info(f"Сертификат истекает: {expiry_date.strftime('%d.%m.%Y %H:%M:%S')}") + self.logger.info(f"Осталось дней: {days_left}") + + return days_left + + except Exception as e: + self.logger.error(f"Ошибка при проверке сертификата: {e}") + return None + + def dns_challenge_hook(self, validation_domain: str, validation_token: str) -> bool: + """ + Обработчик DNS challenge - добавление TXT записи + + Args: + validation_domain: Домен для валидации (например, dfv24.com или *.dfv24.com) + validation_token: Токен валидации + + Returns: + True если успешно + """ + try: + self.logger.info("=== DNS Challenge: Добавление TXT записи ===") + + # Определяем зарегистрированный домен и поддомен для API reg.ru + configured_domains = get_configured_domains(self.config) + registrable_domain, subdomain_prefix = extract_registrable_domain( + validation_domain, configured_domains + ) + subdomain = f"_acme-challenge.{subdomain_prefix}" if subdomain_prefix else "_acme-challenge" + + self.logger.info(f"Validation Domain: {validation_domain}") + self.logger.info(f"Registrable Domain (для API): {registrable_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(registrable_domain, subdomain, validation_token) + + if not success: + self.logger.error("Не удалось добавить TXT запись") + return False + + self.logger.info("✅ TXT запись успешно добавлена в API reg.ru") + + # Ждем распространения DNS + wait_time = self.config.get("dns_propagation_wait", 60) + self.logger.info("") + self.logger.info("⏳ Ожидание распространения DNS...") + self.logger.info(f" Время ожидания: {wait_time} секунд") + self.logger.info(f" TXT запись: {subdomain}.{registrable_domain}") + self.logger.info("") + + # Показываем прогресс ожидания + for i in range(wait_time): + if i % 10 == 0: + elapsed_pct = int((i / wait_time) * 100) + self.logger.info(f" ⏱️ Прошло: {i}/{wait_time} сек ({elapsed_pct}%)") + time.sleep(1) + + self.logger.info(f" ✅ Ожидание завершено ({wait_time} секунд)") + self.logger.info("") + + # Проверяем DNS запись (используем base_domain для проверки) + self.logger.info("🔍 Проверка распространения DNS через публичные серверы...") + if self.verify_dns_record_external(registrable_domain, subdomain, validation_token): + self.logger.info("✅ DNS запись подтверждена через публичные DNS серверы") + self.logger.info(" Certbot сможет пройти валидацию") + return True + else: + self.logger.warning("⚠️ DNS запись НЕ обнаружена через публичные DNS, но продолжаем...") + self.logger.warning(" Возможные причины:") + self.logger.warning(" • DNS серверы ещё не обновились (требуется больше времени)") + self.logger.warning(" • Let's Encrypt использует свои DNS серверы") + self.logger.warning(" • API reg.ru обновляет записи с задержкой") + self.logger.warning("") + self.logger.warning(" Certbot будет продолжать попытки валидации...") + 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: + """ + Обработчик очистки DNS challenge - удаление TXT записи + + Args: + validation_domain: Домен валидации (например, dfv24.com или *.dfv24.com) + validation_token: Токен валидации + + Returns: + True если успешно + """ + self.logger.info("=== DNS Challenge: Удаление TXT записи ===") + + # Определяем зарегистрированный домен и поддомен для API + configured_domains = get_configured_domains(self.config) + registrable_domain, subdomain_prefix = extract_registrable_domain( + validation_domain, configured_domains + ) + subdomain = f"_acme-challenge.{subdomain_prefix}" if subdomain_prefix else "_acme-challenge" + + self.logger.info(f"Домен: {registrable_domain}, Поддомен: {subdomain}") + + return self.api.remove_txt_record(registrable_domain, subdomain, validation_token) + + def verify_dns_record_external(self, domain: str, subdomain: str, expected_value: str) -> bool: + """ + Проверка наличия DNS записи через внешний DNS + + Args: + domain: Основной домен + subdomain: Поддомен + expected_value: Ожидаемое значение TXT записи + + Returns: + True если запись найдена + """ + import time + + full_domain = f"{subdomain}.{domain}" + attempts = self.config.get("dns_check_attempts", 10) + interval = self.config.get("dns_check_interval", 10) + + self.logger.info(f" Проверяем: {full_domain}") + self.logger.info(f" Ожидаемое значение: {expected_value[:30]}...") + self.logger.info(f" Попыток: {attempts}, интервал: {interval} сек") + self.logger.info("") + + for attempt in range(attempts): + try: + # Используем nslookup или dig через subprocess + result = subprocess.run( + ["nslookup", "-type=TXT", full_domain], + capture_output=True, + text=True, + timeout=10 + ) + + if expected_value in result.stdout: + self.logger.info(f" ✅ Попытка {attempt + 1}/{attempts}: DNS запись НАЙДЕНА!") + # Показываем найденную запись + for line in result.stdout.split('\n'): + if 'text =' in line.lower() or expected_value[:20] in line: + self.logger.info(f" {line.strip()}") + return True + else: + self.logger.info(f" ⏳ Попытка {attempt + 1}/{attempts}: DNS запись не найдена, ждём...") + + except Exception as e: + self.logger.info(f" ⚠️ Попытка {attempt + 1}/{attempts}: Ошибка nslookup - {e}") + + if attempt < attempts - 1: + time.sleep(interval) + + self.logger.warning(f" ❌ DNS запись не найдена после {attempts} попыток") + return False + + def verify_dns_record(self, subdomain: str, expected_value: str) -> bool: + """ + Проверка наличия DNS записи (использует self.domain) + + Args: + subdomain: Поддомен + expected_value: Ожидаемое значение TXT записи + + Returns: + True если запись найдена + """ + return self.verify_dns_record_external(self.domain, subdomain, expected_value) + + 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 сертификата ===") + + # Проверяем, не запущен ли уже 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): + domains.append(f"*.{self.domain}") + + domain_args = [] + for d in domains: + domain_args.extend(["-d", d]) + + # Создаём временные 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__)} --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__)} --config {config_path} --cleanup-hook\n') + cleanup_hook_script.close() + os.chmod(cleanup_hook_script.name, 0o755) + + # Команда certbot + cmd = [ + "certbot", "certonly", + "--manual", + "--preferred-challenges", "dns", + "--manual-auth-hook", auth_hook_script.name, + "--manual-cleanup-hook", cleanup_hook_script.name, + "--email", self.email, + "--agree-tos", + "--non-interactive", + "--expand", + ] + + # Добавляем --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"Конфигурация: {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: + result = subprocess.run( + cmd, + capture_output=True, + text=True, + check=True + ) + + self.logger.info("=" * 80) + self.logger.info("✅ СЕРТИФИКАТ УСПЕШНО ПОЛУЧЕН!") + self.logger.info("=" * 80) + + # Выводим stdout certbot (может содержать полезную информацию) + if result.stdout: + self.logger.info("Вывод Certbot:") + for line in result.stdout.split('\n'): + if line.strip(): + self.logger.info(f" {line}") + + # Информация о местоположении сертификата + if staging: + self.logger.info("") + self.logger.info("⚠️ Это STAGING сертификат - не используйте на production!") + self.logger.info(" Для получения production сертификата используйте: letsencrypt-regru --obtain") + + return True + + except subprocess.CalledProcessError as e: + self.logger.error("=" * 80) + self.logger.error("❌ ОШИБКА ПРИ ПОЛУЧЕНИИ СЕРТИФИКАТА") + self.logger.error("=" * 80) + self.logger.error(f"Код возврата: {e.returncode}") + + # Выводим stderr (основные ошибки) + if e.stderr: + self.logger.error("") + self.logger.error("Сообщения об ошибках:") + for line in e.stderr.split('\n'): + if line.strip(): + self.logger.error(f" {line}") + + # Выводим stdout (может содержать дополнительную информацию) + if e.stdout: + self.logger.error("") + self.logger.error("Дополнительная информация:") + for line in e.stdout.split('\n'): + if line.strip(): + self.logger.error(f" {line}") + + # Рекомендации по устранению проблем + self.logger.error("") + self.logger.error("=" * 80) + self.logger.error("РЕКОМЕНДАЦИИ ПО УСТРАНЕНИЮ ПРОБЛЕМ:") + self.logger.error("=" * 80) + self.logger.error("1. Проверьте детальный лог Certbot:") + self.logger.error(" tail -100 /var/log/letsencrypt/letsencrypt.log") + self.logger.error("") + self.logger.error("2. Проверьте логи скрипта:") + self.logger.error(" tail -100 /var/log/letsencrypt-regru/letsencrypt_regru.log") + self.logger.error("") + self.logger.error("3. Убедитесь, что DNS записи создаются:") + self.logger.error(" letsencrypt-regru --test-dns") + self.logger.error("") + self.logger.error("4. Проверьте доступ к API reg.ru:") + self.logger.error(" letsencrypt-regru --test-api") + self.logger.error("") + self.logger.error("5. Запустите с подробным выводом:") + self.logger.error(" letsencrypt-regru --staging -v") + self.logger.error("") + self.logger.error("6. Убедитесь что ваш IP в белом списке API reg.ru:") + self.logger.error(" https://www.reg.ru/user/account/#/settings/api/") + self.logger.error("") + self.logger.error("7. Проверьте DNS записи вручную:") + self.logger.error(" nslookup -type=TXT _acme-challenge.{domain}") + self.logger.error(" dig TXT _acme-challenge.{domain}") + self.logger.error("=" * 80) + + return False + finally: + # Удаляем временные wrapper скрипты + try: + os.unlink(auth_hook_script.name) + os.unlink(cleanup_hook_script.name) + except: + pass + + def renew_certificate(self) -> bool: + """ + Обновление существующего сертификата + + Returns: + True если успешно + """ + self.logger.info("=== Обновление SSL сертификата ===") + + # Получаем путь к конфигурации из аргументов командной строки + 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 + + # Создаём временные wrapper скрипты для hooks (аналогично obtain_certificate) + import tempfile + + 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__)} --config {config_path} --auth-hook\n') + auth_hook_script.close() + os.chmod(auth_hook_script.name, 0o755) + + 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__)} --config {config_path} --cleanup-hook\n') + cleanup_hook_script.close() + os.chmod(cleanup_hook_script.name, 0o755) + + cmd = [ + "certbot", "renew", + "--cert-name", self.domain, + "--manual-auth-hook", auth_hook_script.name, + "--manual-cleanup-hook", cleanup_hook_script.name, + "--non-interactive", + ] + + self.logger.info(f"Домен: {self.domain}") + 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(f"Команда: {' '.join(cmd)}") + + try: + result = subprocess.run( + cmd, + capture_output=True, + text=True, + check=True + ) + + self.logger.info("Проверка обновления завершена") + self.logger.debug(result.stdout) + return True + + except subprocess.CalledProcessError as e: + self.logger.error(f"Ошибка при обновлении: {e}") + self.logger.error(e.stderr) + return False + finally: + # Удаляем временные wrapper скрипты + try: + os.unlink(auth_hook_script.name) + os.unlink(cleanup_hook_script.name) + except: + pass + + def display_certificate_info(self): + """Вывод информации о сертификате""" + cert_file = os.path.join(self.cert_dir, "cert.pem") + + if not os.path.exists(cert_file): + self.logger.warning("Сертификат не найден") + return + + self.logger.info("=" * 60) + self.logger.info("ИНФОРМАЦИЯ О СЕРТИФИКАТЕ") + self.logger.info("=" * 60) + + try: + result = subprocess.run( + ["openssl", "x509", "-in", cert_file, "-text", "-noout"], + capture_output=True, + text=True, + check=True + ) + + # Проверяем, является ли сертификат staging + is_staging = "fake" in result.stdout.lower() or "staging" in result.stdout.lower() + + if is_staging: + self.logger.warning("⚠️ ЭТО STAGING (ТЕСТОВЫЙ) СЕРТИФИКАТ!") + self.logger.warning(" Браузеры не будут доверять этому сертификату") + self.logger.warning(" Не используйте на production сайтах") + self.logger.warning("") + + # Выводим только основную информацию + for line in result.stdout.split("\n"): + if any(keyword in line for keyword in ["Subject:", "Issuer:", "Not Before", "Not After", "DNS:"]): + self.logger.info(line.strip()) + + self.logger.info("=" * 60) + self.logger.info("ПУТИ К ФАЙЛАМ СЕРТИФИКАТА:") + self.logger.info(f" Сертификат: {self.cert_dir}/cert.pem") + self.logger.info(f" Приватный ключ: {self.cert_dir}/privkey.pem") + self.logger.info(f" Цепочка: {self.cert_dir}/chain.pem") + self.logger.info(f" Полная цепочка: {self.cert_dir}/fullchain.pem") + + if is_staging: + self.logger.info("") + self.logger.info("🚀 Для получения PRODUCTION сертификата выполните:") + self.logger.info(" sudo letsencrypt-regru --obtain") + + self.logger.info("=" * 60) + + except Exception as e: + self.logger.error(f"Ошибка при чтении сертификата: {e}") + + def sync_with_npm(self, npm_api: NginxProxyManagerAPI) -> bool: + """ + Синхронизация сертификата с Nginx Proxy Manager + + Args: + npm_api: API клиент NPM + + Returns: + True если успешно + """ + self.logger.info("=== Синхронизация сертификата с Nginx Proxy Manager ===") + + # Проверяем наличие сертификата + if not os.path.exists(self.cert_dir): + self.logger.error(f"Директория сертификата не найдена: {self.cert_dir}") + return False + + # Синхронизируем сертификат + return npm_api.sync_certificate(self.domain, self.cert_dir) + + +# ============================================================================== +# ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ +# ============================================================================== + +def reload_webserver(logger: logging.Logger): + """ + Перезагрузка веб-сервера + + Args: + logger: Logger объект + """ + logger.info("Перезагрузка веб-сервера...") + + # Проверяем какие сервисы активны + services = ["nginx", "apache2", "httpd"] + + for service in services: + try: + # Проверяем статус + result = subprocess.run( + ["systemctl", "is-active", service], + capture_output=True, + text=True + ) + + if result.stdout.strip() == "active": + # Перезагружаем + subprocess.run( + ["systemctl", "reload", service], + check=True + ) + logger.info(f"Сервис {service} перезагружен") + return + + except Exception as e: + logger.debug(f"Сервис {service} не активен или ошибка: {e}") + + logger.warning("Активный веб-сервер не найден") + + +def load_config(config_file: Optional[str] = None) -> Dict: + """ + Загрузка конфигурации из файла или использование значений по умолчанию + + Args: + config_file: Путь к файлу конфигурации (JSON) + + Returns: + Словарь с конфигурацией + """ + config = DEFAULT_CONFIG.copy() + + if config_file and os.path.exists(config_file): + try: + with open(config_file, 'r', encoding='utf-8') as f: + user_config = json.load(f) + config.update(user_config) + except Exception as e: + print(f"ОШИБКА: Не удалось загрузить конфигурацию из {config_file}: {e}") + sys.exit(1) + + return config + + +def get_configured_domains(config: Dict) -> List[str]: + """ + Возвращает список доменов из конфигурации (с обратной совместимостью). + + Поддерживаемые варианты: + - domain: "example.com" + - domains: ["example.com", "example.org"] + - оба варианта одновременно + """ + domains: List[str] = [] + + primary_domain = config.get("domain") + if isinstance(primary_domain, str) and primary_domain.strip(): + domains.append(primary_domain.strip()) + + configured_domains = config.get("domains", []) + if isinstance(configured_domains, str): + configured_domains = [configured_domains] + + if isinstance(configured_domains, list): + for item in configured_domains: + if isinstance(item, str) and item.strip(): + domains.append(item.strip()) + + # Удаляем дубликаты с сохранением порядка + unique_domains: List[str] = [] + seen = set() + for domain in domains: + normalized = domain.lower() + if normalized not in seen: + seen.add(normalized) + unique_domains.append(domain) + + if not unique_domains: + raise ValueError("В конфигурации не указан ни один домен (domain/domains)") + + return unique_domains + + +def get_domain_config(base_config: Dict, domain: str) -> Dict: + """Создаёт копию конфигурации для конкретного домена.""" + domain_config = base_config.copy() + domain_config["domain"] = domain + return domain_config + + +def extract_registrable_domain(target_domain: str, configured_domains: List[str]) -> Tuple[str, str]: + """ + Определяет зарегистрированный домен и префикс поддомена для DNS API (reg.ru). + + Для pages.github.dfv24.com (если dfv24.com в конфигурации): + → ("dfv24.com", "pages.github") + + Для dfv24.com: + → ("dfv24.com", "") + + Args: + target_domain: Целевой домен (может быть субдоменом, может содержать "*.") + configured_domains: Список всех доменов из конфигурации + + Returns: + (registrable_domain, subdomain_prefix) + subdomain_prefix пустой если target_domain совпадает с зарегистрированным доменом + """ + clean_domain = target_domain.replace("*.", "") + + # Ищем самый короткий домен из конфигурации, который является суффиксом + # Самый короткий подходящий — наиболее вероятно зарегистрированный домен + sorted_domains = sorted(configured_domains, key=len) + + for cfg_domain in sorted_domains: + cfg_lower = cfg_domain.lower() + target_lower = clean_domain.lower() + + if target_lower == cfg_lower: + return cfg_domain, "" + if target_lower.endswith(f".{cfg_lower}"): + prefix = clean_domain[:-(len(cfg_domain) + 1)] + return cfg_domain, prefix + + # Fallback: извлекаем последние 2 части как зарег. домен + # (работает для простых TLD: .com, .ru, .org и т.д.) + parts = clean_domain.split('.') + if len(parts) >= 2: + registrable = '.'.join(parts[-2:]) + prefix = '.'.join(parts[:-2]) if len(parts) > 2 else '' + return registrable, prefix + + return clean_domain, "" + + +def create_sample_config(output_file: str): + """ + Создание примера файла конфигурации + + Args: + output_file: Путь к выходному файлу + """ + with open(output_file, 'w', encoding='utf-8') as f: + json.dump(DEFAULT_CONFIG, f, indent=4, ensure_ascii=False) + + print(f"Пример конфигурации создан: {output_file}") + print("Отредактируйте файл и укажите ваши учетные данные") + + +# ============================================================================== +# ОСНОВНАЯ ФУНКЦИЯ +# ============================================================================== + +def main(): + """Основная функция скрипта""" + + # Парсинг аргументов командной строки + parser = argparse.ArgumentParser( + description="Автоматическое управление SSL сертификатами Let's Encrypt через API reg.ru", + epilog=""" +================================================================================ +ПРИМЕРЫ ИСПОЛЬЗОВАНИЯ +================================================================================ + +Основные команды: + letsencrypt-regru --check Проверить срок действия (определяет staging/production) + letsencrypt-regru --info Показать полную информацию о сертификате + letsencrypt-regru --obtain Получить production сертификат + letsencrypt-regru --renew Обновить сертификат + letsencrypt-regru --auto Авто-режим (для cron/systemd) + letsencrypt-regru --upload-npm DOMAIN Загрузить сертификат в Nginx Proxy Manager + letsencrypt-regru --list-npm Показать все сертификаты в NPM (с дубликатами) + letsencrypt-regru --delete-npm ID Удалить сертификат из NPM по ID + +Команды тестирования: + letsencrypt-regru --staging Тестовый Let's Encrypt (БЕЗ лимитов!) + letsencrypt-regru --test-cert Самоподписанный (локально) + letsencrypt-regru --test-api Проверить API reg.ru + letsencrypt-regru --test-dns Проверить DNS записи + +Отладка: + letsencrypt-regru --obtain -v Подробный вывод + letsencrypt-regru --force-cleanup Очистить lock-файлы Certbot + +Работа с NPM: + letsencrypt-regru --list-npm Показать все сертификаты + letsencrypt-regru --upload-npm example.com Загрузить сертификат для example.com + letsencrypt-regru --delete-npm 5 Удалить сертификат ID 5 + +================================================================================ +РЕКОМЕНДУЕМЫЙ WORKFLOW +================================================================================ + +1. Проверка настройки: + letsencrypt-regru --test-api [+] API доступен? + letsencrypt-regru --test-dns [+] DNS работает? + +2. Тестирование (неограниченно): + letsencrypt-regru --staging [+] Полный процесс SSL + +3. Production: + letsencrypt-regru --obtain [+] Боевой сертификат + letsencrypt-regru --upload-npm DOMAIN [+] Загрузить в NPM (если не автоматически) + +================================================================================ +СРАВНЕНИЕ РЕЖИМОВ ТЕСТИРОВАНИЯ +================================================================================ + + --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", + help="Путь к файлу конфигурации (JSON)", + default=None + ) + parser.add_argument( + "--create-config", + help="Создать пример файла конфигурации", + metavar="FILE" + ) + # Основные команды + main_group = parser.add_argument_group('Основные команды') + main_group.add_argument( + "--check", + help="Проверить срок действия сертификата (определяет staging/production)", + action="store_true" + ) + main_group.add_argument( + "--info", + help="Показать полную информацию о сертификате", + action="store_true" + ) + 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" + ) + main_group.add_argument( + "--upload-npm", + help="Загрузить существующий сертификат в Nginx Proxy Manager", + metavar="DOMAIN", + type=str + ) + main_group.add_argument( + "--list-npm", + help="Показать все сертификаты в Nginx Proxy Manager", + action="store_true" + ) + main_group.add_argument( + "--delete-npm", + help="Удалить сертификат из Nginx Proxy Manager по ID", + metavar="CERT_ID", + type=int + ) + + # Команды тестирования + 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="Certbot authentication hook (создание DNS записи)", + action="store_true" + ) + service_group.add_argument( + "--cleanup-hook", + help="Certbot cleanup hook (удаление DNS записи)", + action="store_true" + ) + + # Дополнительные параметры + parser.add_argument( + "-v", "--verbose", + help="Подробный вывод для диагностики", + action="store_true" + ) + parser.add_argument( + "--force-cleanup", + help="Принудительная очистка lock-файлов Certbot (если процесс завис)", + action="store_true" + ) + + args = parser.parse_args() + + # Создание примера конфигурации + if args.create_config: + 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) + + # Настройка логирования + logger = setup_logging(config["log_file"], args.verbose) + + # Разрешаем список доменов (domain + domains) с обратной совместимостью + try: + configured_domains = get_configured_domains(config) + except ValueError as e: + logger.error(str(e)) + return 1 + + # Тестирование DNS записей (полный цикл как при создании SSL) + if args.test_dns: + logger.info("=" * 80) + logger.info("ТЕСТИРОВАНИЕ СОЗДАНИЯ DNS ЗАПИСИ ДЛЯ SSL") + logger.info("=" * 80) + logger.info("Этот тест симулирует процесс создания SSL сертификата:") + logger.info("1. Проверка подключения к API") + logger.info("2. Создание TXT записи _acme-challenge") + logger.info("3. Проверка распространения DNS") + logger.info("4. Удаление тестовой записи") + logger.info("=" * 80) + logger.info("") + + api = RegRuAPI(config["regru_username"], config["regru_password"], logger) + test_subdomain = "_acme-challenge" + + logger.info("📋 ШАГ 1/4: Проверка подключения к API reg.ru") + if not api.test_api_access(): + logger.error("❌ API недоступен. Тест прерван.") + return 1 + logger.info("✅ API доступен") + logger.info("") + + all_domains_passed = True + + for domain in configured_domains: + logger.info("-" * 80) + logger.info(f"ТЕСТ ДОМЕНА: {domain}") + logger.info("-" * 80) + + # Определяем зарегистрированный домен и поддомен для API reg.ru + registrable_domain, subdomain_prefix = extract_registrable_domain(domain, configured_domains) + api_subdomain = f"{test_subdomain}.{subdomain_prefix}" if subdomain_prefix else test_subdomain + + test_value = f"test-value-{domain}-{int(time.time())}" + domain_passed = True + + logger.info("📋 ШАГ 2/4: Создание тестовой TXT записи") + logger.info(f" Домен: {domain}") + logger.info(f" Зарегистрированный домен (для API): {registrable_domain}") + logger.info(f" Поддомен: {api_subdomain}") + logger.info(f" Значение: {test_value}") + + if api.add_txt_record(registrable_domain, api_subdomain, test_value): + logger.info("✅ TXT запись создана успешно") + else: + logger.error("❌ Не удалось создать TXT запись") + domain_passed = False + logger.info("") + + if domain_passed: + logger.info("📋 ШАГ 3/4: Ожидание распространения DNS") + wait_time = config.get("dns_propagation_wait", 60) + logger.info(f" Ожидаем {wait_time} секунд...") + + for i in range(wait_time): + if i % 10 == 0: + logger.info(f" ⏳ Прошло {i}/{wait_time} секунд") + time.sleep(1) + + logger.info("✅ Ожидание завершено") + logger.info("") + + logger.info("📋 ШАГ 3.5/4: Проверка DNS записи через nslookup") + full_domain = f"{api_subdomain}.{registrable_domain}" + try: + result = subprocess.run( + ["nslookup", "-type=TXT", full_domain], + capture_output=True, + text=True, + timeout=10 + ) + + if test_value in result.stdout: + logger.info(f"✅ DNS запись найдена для {full_domain}") + logger.info(" Вывод nslookup:") + for line in result.stdout.split("\n"): + if test_value in line or "text =" in line.lower(): + logger.info(f" {line.strip()}") + else: + logger.warning(f"⚠️ DNS запись НЕ найдена для {full_domain}") + logger.warning(" Это может быть нормально, если DNS ещё не распространился") + logger.warning(" Certbot будет ждать дольше при реальном создании сертификата") + except Exception as e: + logger.warning(f"⚠️ Не удалось проверить DNS: {e}") + + logger.info("") + + logger.info("📋 ШАГ 4/4: Удаление тестовой записи") + if api.remove_txt_record(registrable_domain, api_subdomain, test_value): + logger.info("✅ TXT запись удалена успешно") + else: + logger.warning("⚠️ Не удалось удалить TXT запись (возможно уже удалена)") + + if not domain_passed: + all_domains_passed = False + + logger.info("") + + logger.info("=" * 80) + if all_domains_passed: + logger.info("✅ ВСЕ ТЕСТЫ ПРОЙДЕНЫ УСПЕШНО") + logger.info("=" * 80) + logger.info("") + logger.info("🎉 Система готова для создания SSL сертификата!") + logger.info("") + logger.info("Следующие шаги:") + logger.info("1. Убедитесь что ваш IP добавлен в белый список API reg.ru") + logger.info("2. Запустите: sudo letsencrypt-regru --obtain") + logger.info("3. Или настройте автоматическое обновление:") + logger.info(" sudo systemctl enable letsencrypt-regru.timer") + logger.info(" sudo systemctl start letsencrypt-regru.timer") + return 0 + else: + logger.error("❌ НЕКОТОРЫЕ ТЕСТЫ НЕ ПРОЙДЕНЫ") + logger.error("=" * 80) + logger.error("Исправьте проблемы перед созданием SSL сертификата") + return 1 + + # Тестирование API + if args.test_api: + logger.info("=" * 80) + logger.info("ТЕСТИРОВАНИЕ ПОДКЛЮЧЕНИЯ К API REG.RU") + logger.info("=" * 80) + + api = RegRuAPI(config["regru_username"], config["regru_password"], logger) + + # Тест подключения + if api.test_api_access(): + logger.info("") + logger.info("=" * 80) + logger.info("🧪 ДОПОЛНИТЕЛЬНЫЕ ТЕСТЫ") + logger.info("=" * 80) + + # Тест получения DNS записей + for domain in configured_domains: + try: + records = api.get_zone_records(domain) + logger.info(f"✅ [{domain}] Получение DNS записей: успешно ({len(records)} записей)") + except Exception as e: + logger.error(f"❌ [{domain}] Получение DNS записей: ошибка - {e}") + + logger.info("") + logger.info("=" * 80) + logger.info("✅ ВСЕ ТЕСТЫ ЗАВЕРШЕНЫ") + logger.info("=" * 80) + logger.info("API reg.ru готов к использованию!") + return 0 + else: + logger.error("=" * 80) + logger.error("❌ ТЕСТЫ НЕ ПРОЙДЕНЫ") + logger.error("=" * 80) + logger.error("Исправьте проблемы с API перед использованием скрипта") + return 1 + + # Генерация тестового сертификата + if args.test_cert: + logger.info("=" * 80) + logger.info("РЕЖИМ: Генерация тестового самоподписанного сертификата") + logger.info("=" * 80) + + test_gen = TestCertificateGenerator(logger) + all_success = True + + for domain in configured_domains: + logger.info("-" * 80) + logger.info(f"ГЕНЕРАЦИЯ ТЕСТОВОГО СЕРТИФИКАТА ДЛЯ: {domain}") + logger.info("-" * 80) + + success = test_gen.generate_self_signed_certificate( + domain=domain, + wildcard=config.get("wildcard", False), + output_dir=config["cert_dir"], + validity_days=90 + ) + + if not success: + all_success = False + continue + + # Опционально загружаем в NPM + if config.get("npm_enabled", False): + logger.info("") + logger.info("=" * 80) + logger.info("ЗАГРУЗКА ТЕСТОВОГО СЕРТИФИКАТА В NGINX PROXY MANAGER") + logger.info("=" * 80) + + npm_api = NginxProxyManagerAPI( + config["npm_host"], + config["npm_email"], + config["npm_password"], + logger + ) + + if npm_api.login(): + cert_dir = os.path.join(config["cert_dir"], domain) + cert_path = os.path.join(cert_dir, "fullchain.pem") + key_path = os.path.join(cert_dir, "privkey.pem") + + existing = npm_api.find_certificate_by_domain(domain) + + if existing: + cert_id = existing.get("id") + logger.info(f"Обновление существующего сертификата в NPM (ID: {cert_id})") + if npm_api.update_certificate(cert_id, cert_path, key_path): + logger.info("✅ Тестовый сертификат успешно обновлен в NPM") + else: + logger.warning("⚠️ Не удалось обновить сертификат в NPM") + else: + logger.info("Загрузка нового тестового сертификата в NPM") + if npm_api.upload_certificate(domain, cert_path, key_path): + logger.info("✅ Тестовый сертификат успешно загружен в NPM") + else: + logger.warning("⚠️ Не удалось загрузить сертификат в NPM") + else: + logger.error("Не удалось подключиться к Nginx Proxy Manager") + + logger.info("") + logger.info("=" * 80) + if all_success: + logger.info("✅ ТЕСТОВЫЕ СЕРТИФИКАТЫ УСПЕШНО СОЗДАНЫ") + logger.info("=" * 80) + return 0 + else: + logger.error("❌ Не удалось создать тестовые сертификаты для части доменов") + logger.error("=" * 80) + return 1 + + # Обработка хуков для certbot + if args.auth_hook: + try: + logger.info("=" * 80) + logger.info("🔑 AUTH HOOK ВЫЗВАН") + logger.info("=" * 80) + + # 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") + + 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) + + 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: + try: + logger.info("=" * 80) + logger.info("🧹 CLEANUP HOOK ВЫЗВАН") + logger.info("=" * 80) + + 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") + + 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) + + 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: + logger.error("Скрипт должен быть запущен от имени root (sudo)") + return 1 + + # Инициализация API + api = RegRuAPI(config["regru_username"], config["regru_password"], logger) + + # Проверка certbot (достаточно одного менеджера) + primary_manager = LetsEncryptManager(get_domain_config(config, configured_domains[0]), api, logger) + if not primary_manager.check_certbot_installed(): + logger.error("Установите certbot: apt-get install certbot") + return 1 + + logger.info("=" * 60) + logger.info("СКРИПТ УПРАВЛЕНИЯ SSL СЕРТИФИКАТАМИ LET'S ENCRYPT") + logger.info("=" * 60) + + # Получаем текущий IP + try: + ip_response = requests.get("https://api.ipify.org", timeout=5) + current_ip = ip_response.text + logger.info(f"Текущий IP адрес: {current_ip}") + except: + logger.warning("Не удалось определить IP адрес") + + # Проверка доступности API reg.ru (кроме режимов только проверки) + if not args.check: + logger.info("Проверка доступности API reg.ru...") + if not api.test_api_access(): + logger.error("=" * 80) + logger.error("❌ КРИТИЧЕСКАЯ ОШИБКА: API reg.ru недоступен") + logger.error("=" * 80) + logger.error("Скрипт не может продолжить работу без доступа к API") + logger.error("") + logger.error("Возможные причины:") + logger.error(" 1. Неверные учётные данные reg.ru") + logger.error(" 2. IP адрес не добавлен в белый список API") + logger.error(" 3. Проблемы с интернет-соединением") + logger.error("") + logger.error("Проверьте настройки и запустите скрипт заново") + logger.error("Для диагностики используйте: letsencrypt-regru --test-api -v") + return 1 + logger.info("") + + # Выполнение действий + if args.info: + any_error = False + + for domain in configured_domains: + logger.info("=" * 80) + logger.info(f"ИНФОРМАЦИЯ О СЕРТИФИКАТЕ: {domain}") + logger.info("=" * 80) + + manager = LetsEncryptManager(get_domain_config(config, domain), api, logger) + days_left = manager.check_certificate_expiry() + + if days_left is None: + logger.error(f"Сертификат не найден для домена: {domain}") + any_error = True + continue + + is_staging = manager.is_staging_certificate() + + logger.info("") + logger.info("=" * 80) + if is_staging: + logger.warning("ТИП СЕРТИФИКАТА: STAGING (ТЕСТОВЫЙ)") + logger.warning("=" * 80) + logger.warning("⚠️ Это тестовый сертификат Let's Encrypt") + logger.warning(" • Издатель: Fake LE Intermediate X1 (staging)") + logger.warning(" • Браузеры НЕ доверяют") + logger.warning(" • НЕ загружен в Nginx Proxy Manager") + logger.warning(" • БЕЗ лимитов на получение") + else: + logger.info("ТИП СЕРТИФИКАТА: PRODUCTION (БОЕВОЙ)") + logger.info("=" * 80) + logger.info("✅ Это настоящий сертификат Let's Encrypt") + logger.info(" • Издатель: Let's Encrypt Authority") + logger.info(" • Браузеры доверяют") + logger.info(" • Загружен в Nginx Proxy Manager") + logger.info(" • Лимит: 5 сертификатов/неделю") + + logger.info("") + manager.display_certificate_info() + + if is_staging: + logger.info("") + logger.info("=" * 80) + logger.info("🚀 Для получения PRODUCTION сертификата:") + logger.info(" sudo letsencrypt-regru --obtain") + logger.info("=" * 80) + + return 1 if any_error else 0 + + elif args.check: + # Только проверка срока действия по всем доменам + final_code = 0 + + for domain in configured_domains: + logger.info("=" * 80) + logger.info(f"ПРОВЕРКА СЕРТИФИКАТА: {domain}") + logger.info("=" * 80) + + manager = LetsEncryptManager(get_domain_config(config, domain), api, logger) + days_left = manager.check_certificate_expiry() + is_staging = manager.is_staging_certificate() + + if days_left is None: + logger.info("Сертификат не найден. Требуется создание нового.") + logger.info("") + logger.info("Для получения production сертификата выполните:") + logger.info(" sudo letsencrypt-regru --obtain") + final_code = max(final_code, 2) + elif is_staging: + logger.warning("") + logger.warning("=" * 80) + logger.warning("⚠️ УСТАНОВЛЕН STAGING (ТЕСТОВЫЙ) СЕРТИФИКАТ!") + logger.warning("=" * 80) + logger.warning("Это тестовый сертификат Let's Encrypt из staging окружения") + logger.warning("Браузеры НЕ будут доверять этому сертификату") + logger.warning("Сертификат НЕ загружен в Nginx Proxy Manager") + logger.warning("") + logger.warning("🚀 Для получения PRODUCTION сертификата выполните:") + logger.warning(" sudo letsencrypt-regru --obtain") + logger.warning("=" * 80) + final_code = max(final_code, 3) + elif days_left < 30: + logger.warning(f"Сертификат истекает через {days_left} дней. Требуется обновление!") + logger.info("") + logger.info("Для обновления сертификата выполните:") + logger.info(" sudo letsencrypt-regru --renew") + final_code = max(final_code, 1) + else: + logger.info(f"✅ Сертификат действителен ({days_left} дней)") + logger.info("") + logger.info("Сертификат в норме. Следующая проверка через:") + logger.info(f" {days_left - 30} дней (за 30 дней до истечения)") + + return final_code + + 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("") + + all_success = True + + for domain in configured_domains: + logger.info("=" * 80) + logger.info(f"ПОЛУЧЕНИЕ STAGING СЕРТИФИКАТА: {domain}") + logger.info("=" * 80) + + manager = LetsEncryptManager(get_domain_config(config, domain), api, logger) + success = manager.obtain_certificate(staging=True) + + if success: + logger.info("") + logger.info("=" * 80) + logger.info("✅ ТЕСТОВЫЙ СЕРТИФИКАТ УСПЕШНО ПОЛУЧЕН") + logger.info("=" * 80) + logger.info("") + logger.info(f"📂 Расположение: /etc/letsencrypt/live/{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("") + + if config.get("npm_enabled", False): + logger.warning("⚠️ Staging сертификат НЕ загружается в Nginx Proxy Manager") + logger.warning(" (staging сертификаты не предназначены для production)") + else: + all_success = False + + return 0 if all_success else 1 + + elif args.obtain: + # Принудительное получение новых сертификатов + all_success = True + + for domain in configured_domains: + logger.info("=" * 80) + logger.info(f"ПОЛУЧЕНИЕ PRODUCTION СЕРТИФИКАТА: {domain}") + logger.info("=" * 80) + + manager = LetsEncryptManager(get_domain_config(config, domain), api, logger) + success = manager.obtain_certificate(staging=False) + if success: + manager.display_certificate_info() + + if config.get("npm_enabled", False): + npm_api = NginxProxyManagerAPI( + config["npm_host"], + config["npm_email"], + config["npm_password"], + logger + ) + if manager.sync_with_npm(npm_api): + logger.info("Сертификат успешно добавлен в Nginx Proxy Manager") + else: + logger.warning("Не удалось синхронизировать сертификат с NPM") + else: + logger.error("Не удалось получить сертификат") + all_success = False + + if all_success: + reload_webserver(logger) + logger.info("Новые сертификаты успешно созданы") + return 0 + + return 1 + + elif args.renew: + # Обновление существующих сертификатов + all_success = True + + for domain in configured_domains: + logger.info("=" * 80) + logger.info(f"ОБНОВЛЕНИЕ СЕРТИФИКАТА: {domain}") + logger.info("=" * 80) + + manager = LetsEncryptManager(get_domain_config(config, domain), api, logger) + success = manager.renew_certificate() + if success: + manager.display_certificate_info() + + if config.get("npm_enabled", False): + npm_api = NginxProxyManagerAPI( + config["npm_host"], + config["npm_email"], + config["npm_password"], + logger + ) + if manager.sync_with_npm(npm_api): + logger.info("Сертификат успешно обновлен в Nginx Proxy Manager") + else: + logger.warning("Не удалось синхронизировать сертификат с NPM") + else: + logger.error("Не удалось обновить сертификат") + all_success = False + + if all_success: + reload_webserver(logger) + logger.info("Сертификаты успешно обновлены") + return 0 + + return 1 + + elif args.list_npm: + # Показать все сертификаты в NPM + logger.info("=" * 80) + logger.info("СПИСОК СЕРТИФИКАТОВ В NGINX PROXY MANAGER") + logger.info("=" * 80) + + if not config.get("npm_enabled", False): + logger.error("NPM не настроен в конфигурации!") + return 1 + + npm_api = NginxProxyManagerAPI( + config["npm_host"], + config["npm_email"], + config["npm_password"], + logger + ) + + if not npm_api.login(): + logger.error("Не удалось подключиться к NPM") + return 1 + + certificates = npm_api.get_certificates() + + if not certificates: + logger.info("В NPM нет сертификатов") + return 0 + + logger.info(f"Всего сертификатов: {len(certificates)}") + logger.info("") + + # Группируем дубликаты по domain_names + from collections import defaultdict + duplicates = defaultdict(list) + + for cert in certificates: + domains_key = tuple(sorted(cert.get("domain_names", []))) + duplicates[domains_key].append(cert) + + # Выводим список + for domains_key, certs in sorted(duplicates.items()): + domains_str = ", ".join(domains_key) + + if len(certs) > 1: + logger.warning(f"⚠️ ДУБЛИКАТЫ для {domains_str}:") + for cert in certs: + cert_id = cert.get("id") + created = cert.get("created_on", "Unknown") + expires = cert.get("expires_on", "Unknown") + provider = cert.get("provider", "Unknown") + logger.warning(f" ID {cert_id}: создан {created}, истекает {expires}, тип {provider}") + else: + cert = certs[0] + cert_id = cert.get("id") + created = cert.get("created_on", "Unknown") + expires = cert.get("expires_on", "Unknown") + provider = cert.get("provider", "Unknown") + logger.info(f"ID {cert_id}: {domains_str}") + logger.info(f" Создан: {created}, Истекает: {expires}, Тип: {provider}") + logger.info("") + + # Показываем рекомендации по удалению дубликатов + has_duplicates = any(len(certs) > 1 for certs in duplicates.values()) + if has_duplicates: + logger.warning("=" * 80) + logger.warning("Обнаружены дубликаты сертификатов!") + logger.warning("Для удаления дубликата используйте:") + logger.warning(" letsencrypt-regru --delete-npm CERT_ID") + logger.warning("=" * 80) + + return 0 + + elif args.delete_npm: + # Удалить сертификат из NPM + cert_id = args.delete_npm + + logger.info("=" * 80) + logger.info(f"УДАЛЕНИЕ СЕРТИФИКАТА ID {cert_id} ИЗ NPM") + logger.info("=" * 80) + + if not config.get("npm_enabled", False): + logger.error("NPM не настроен в конфигурации!") + return 1 + + npm_api = NginxProxyManagerAPI( + config["npm_host"], + config["npm_email"], + config["npm_password"], + logger + ) + + if not npm_api.login(): + logger.error("Не удалось подключиться к NPM") + return 1 + + # Получаем информацию о сертификате + certificates = npm_api.get_certificates() + cert_to_delete = None + + for cert in certificates: + if cert.get("id") == cert_id: + cert_to_delete = cert + break + + if not cert_to_delete: + logger.error(f"Сертификат с ID {cert_id} не найден") + logger.info("") + logger.info("Доступные сертификаты:") + for cert in certificates: + logger.info(f" ID {cert.get('id')}: {', '.join(cert.get('domain_names', []))}") + return 1 + + # Показываем информацию о сертификате + domains = cert_to_delete.get("domain_names", []) + logger.info(f"Сертификат: {', '.join(domains)}") + logger.info(f"Создан: {cert_to_delete.get('created_on', 'Unknown')}") + logger.info("") + logger.warning("⚠️ ВНИМАНИЕ: Удаление сертификата нельзя отменить!") + logger.warning("Продолжить удаление? (y/N): ") + + try: + response = input().strip().lower() + if response != 'y': + logger.info("Отменено.") + return 0 + except: + logger.error("Требуется интерактивное подтверждение") + return 1 + + if npm_api.delete_certificate(cert_id): + logger.info("") + logger.info("=" * 80) + logger.info("✅ СЕРТИФИКАТ УСПЕШНО УДАЛЕН") + logger.info("=" * 80) + return 0 + else: + logger.error("Не удалось удалить сертификат") + return 1 + + elif args.upload_npm: + # Загрузка существующего сертификата в NPM + domain = args.upload_npm + + logger.info("=" * 80) + logger.info(f"ЗАГРУЗКА СЕРТИФИКАТА В NGINX PROXY MANAGER") + logger.info("=" * 80) + logger.info(f"Домен: {domain}") + logger.info("") + + # Проверяем настройки NPM + if not config.get("npm_enabled", False): + logger.error("NPM не настроен в конфигурации!") + logger.error("Проверьте параметры npm_enabled, npm_host, npm_email, npm_password") + return 1 + + # Определяем пути к сертификату + cert_dir = os.path.join(config["cert_dir"], domain) + cert_path = os.path.join(cert_dir, "fullchain.pem") + key_path = os.path.join(cert_dir, "privkey.pem") + + # Проверяем существование файлов + if not os.path.exists(cert_path): + logger.error(f"Сертификат не найден: {cert_path}") + logger.error("") + logger.error("Доступные домены в /etc/letsencrypt/live/:") + try: + live_dir = config["cert_dir"] + if os.path.exists(live_dir): + for item in os.listdir(live_dir): + item_path = os.path.join(live_dir, item) + if os.path.isdir(item_path): + logger.error(f" - {item}") + except: + pass + return 1 + + if not os.path.exists(key_path): + logger.error(f"Приватный ключ не найден: {key_path}") + return 1 + + logger.info(f"✅ Найден сертификат: {cert_path}") + logger.info(f"✅ Найден приватный ключ: {key_path}") + + # Анализируем содержимое сертификата + try: + with open(cert_path, 'r') as f: + cert_content = f.read() + cert_count = cert_content.count('-----BEGIN CERTIFICATE-----') + logger.info(f" Сертификатов в файле: {cert_count}") + if cert_count > 1: + logger.info(f" (1 конечный + {cert_count - 1} промежуточных)") + except: + pass + + logger.info("") + + # Проверяем тип сертификата + try: + result = subprocess.run( + ["openssl", "x509", "-in", cert_path, "-text", "-noout"], + capture_output=True, + text=True + ) + is_staging = "fake" in result.stdout.lower() or "staging" in result.stdout.lower() + + # Показываем дату истечения + for line in result.stdout.split('\n'): + if 'Not After' in line: + logger.info(f" Истекает: {line.strip()}") + break + + if is_staging: + logger.warning("⚠️ ВНИМАНИЕ: Это STAGING (тестовый) сертификат!") + logger.warning(" Браузеры не будут доверять этому сертификату") + logger.warning("") + logger.warning("Продолжить загрузку в NPM? (y/N): ") + + try: + response = input().strip().lower() + if response != 'y': + logger.info("Отменено.") + return 0 + except: + logger.warning("Пропускаем подтверждение (неинтерактивный режим)") + except: + pass + + # Подключаемся к NPM + logger.info("Подключение к Nginx Proxy Manager...") + npm_api = NginxProxyManagerAPI( + config["npm_host"], + config["npm_email"], + config["npm_password"], + logger + ) + + if not npm_api.login(): + logger.error("Не удалось подключиться к NPM") + logger.error("Проверьте настройки npm_host, npm_email, npm_password в конфигурации") + return 1 + + logger.info("✅ Подключение к NPM успешно") + logger.info("") + + # Получаем список всех сертификатов для диагностики + all_certs = npm_api.get_certificates() + logger.info(f"Всего сертификатов в NPM: {len(all_certs)}") + + if args.verbose and all_certs: + logger.info("") + logger.info("Список всех сертификатов в NPM:") + for cert in all_certs: + cert_id = cert.get("id") + cert_name = cert.get("nice_name", "Unknown") + domains = cert.get("domain_names", []) + logger.info(f" ID {cert_id}: '{cert_name}' -> {', '.join(domains)}") + logger.info("") + + # Проверяем существующий сертификат + logger.info(f"Поиск сертификата для домена '{domain}'...") + existing = npm_api.find_certificate_by_domain(domain) + + if existing: + cert_id = existing.get("id") + logger.info(f"Найден существующий сертификат (ID: {cert_id})") + logger.info("Обновление сертификата...") + + if npm_api.update_certificate(cert_id, cert_path, key_path): + logger.info("") + logger.info("=" * 80) + logger.info("✅ СЕРТИФИКАТ УСПЕШНО ОБНОВЛЕН В NPM") + logger.info("=" * 80) + logger.info(f"ID сертификата: {cert_id}") + logger.info(f"Домен: {domain}") + logger.info("") + + # Проверяем результат + updated_certs = npm_api.get_certificates() + for cert in updated_certs: + if cert.get("id") == cert_id: + expires = cert.get("expires_on", "Unknown") + logger.info(f"Статус в NPM: {cert.get('provider', 'Unknown')}") + logger.info(f"Истекает: {expires}") + break + + return 0 + else: + logger.error("Не удалось обновить сертификат в NPM") + return 1 + else: + logger.info("Существующий сертификат не найден") + logger.info("Создание нового сертификата в NPM...") + + result = npm_api.upload_certificate(domain, cert_path, key_path) + if result: + cert_id = result.get("id") + logger.info("") + logger.info("=" * 80) + logger.info("✅ СЕРТИФИКАТ УСПЕШНО ЗАГРУЖЕН В NPM") + logger.info("=" * 80) + logger.info(f"ID сертификата: {cert_id}") + logger.info(f"Домен: {domain}") + logger.info("") + + # Проверяем результат (повторно получаем из NPM, если возможно) + try: + final = npm_api.get_certificate_by_id(cert_id) + if final: + provider = final.get('provider', result.get('provider', 'Unknown')) + expires = final.get('expires_on', result.get('expires_on', 'Unknown')) + domains = final.get('domain_names', []) + logger.info(f"Статус в NPM: {provider}") + logger.info(f"Домены: {', '.join(domains) if domains else '[пока не распознаны]'}") + logger.info(f"Истекает: {expires}") + else: + logger.info(f"Статус в NPM: {result.get('provider', 'Unknown')}") + logger.info(f"Истекает: {result.get('expires_on', 'Unknown')}") + except Exception: + logger.info(f"Статус в NPM: {result.get('provider', 'Unknown')}") + logger.info(f"Истекает: {result.get('expires_on', 'Unknown')}") + logger.info("") + logger.info("Теперь вы можете использовать этот сертификат в Proxy Hosts") + return 0 + else: + logger.error("Не удалось загрузить сертификат в NPM") + return 1 + + else: + # Автоматический режим: проверка и обновление по всем доменам + logger.info("=" * 60) + logger.info("АВТОМАТИЧЕСКАЯ ПРОВЕРКА И ОБНОВЛЕНИЕ СЕРТИФИКАТОВ") + logger.info("=" * 60) + + renewal_days = config.get("renewal_days", 30) + logger.info(f"Порог обновления: {renewal_days} дней до истечения") + + any_changed = False + all_success = True + + for domain in configured_domains: + logger.info("=" * 60) + logger.info(f"ДОМЕН: {domain}") + logger.info("=" * 60) + + manager = LetsEncryptManager(get_domain_config(config, domain), api, logger) + days_left = manager.check_certificate_expiry() + + success = True + action = None + + if days_left is None: + logger.info("=" * 60) + logger.info("СТАТУС: Сертификат не найден") + logger.info("ДЕЙСТВИЕ: Создание нового сертификата") + logger.info("=" * 60) + success = manager.obtain_certificate() + action = "создан" + elif days_left < renewal_days: + logger.info("=" * 60) + logger.info(f"СТАТУС: Сертификат истекает через {days_left} дней") + logger.info(f"ДЕЙСТВИЕ: Обновление сертификата (порог: {renewal_days} дней)") + logger.info("=" * 60) + success = manager.renew_certificate() + action = "обновлен" + else: + logger.info("=" * 60) + logger.info(f"СТАТУС: Сертификат действителен ({days_left} дней)") + logger.info("ДЕЙСТВИЕ: Обновление не требуется") + logger.info("=" * 60) + manager.display_certificate_info() + + if config.get("npm_enabled", False): + logger.info("Проверка синхронизации с Nginx Proxy Manager...") + npm_api = NginxProxyManagerAPI( + config["npm_host"], + config["npm_email"], + config["npm_password"], + logger + ) + existing_cert = npm_api.login() and npm_api.find_certificate_by_domain(manager.domain) + if existing_cert: + logger.info(f"Сертификат найден в NPM (ID: {existing_cert.get('id')})") + else: + logger.info("Сертификат не найден в NPM. Синхронизация...") + if manager.sync_with_npm(npm_api): + logger.info("Сертификат успешно синхронизирован с NPM") + + continue + + if success: + any_changed = True + logger.info("=" * 60) + logger.info(f"РЕЗУЛЬТАТ: Сертификат успешно {action}") + logger.info("=" * 60) + + manager.display_certificate_info() + + if config.get("npm_enabled", False): + logger.info("=" * 60) + logger.info("СИНХРОНИЗАЦИЯ С NGINX PROXY MANAGER") + logger.info("=" * 60) + + npm_api = NginxProxyManagerAPI( + config["npm_host"], + config["npm_email"], + config["npm_password"], + logger + ) + if manager.sync_with_npm(npm_api): + logger.info(f"✅ Сертификат успешно {action} в Nginx Proxy Manager") + else: + logger.warning("⚠️ Не удалось синхронизировать сертификат с NPM") + else: + all_success = False + logger.error("Операция завершилась с ошибкой") + + if any_changed and all_success: + reload_webserver(logger) + + if all_success: + logger.info("=" * 60) + logger.info("ОПЕРАЦИЯ ЗАВЕРШЕНА УСПЕШНО") + logger.info("=" * 60) + return 0 + + return 1 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/letsencrypt_regru_dns.sh b/letsencrypt_regru_dns.sh new file mode 100644 index 0000000..9547df7 --- /dev/null +++ b/letsencrypt_regru_dns.sh @@ -0,0 +1,290 @@ +#!/bin/bash + +############################################################################### +# Скрипт для создания и обновления SSL сертификата Let's Encrypt +# с использованием DNS-валидации через API reg.ru +# +# Автор: Фофанов Дмитрий +# Дата: 27.10.2025 +# Описание: Автоматизация получения wildcard сертификата через Certbot +# с использованием DNS-01 challenge и API reg.ru +############################################################################### + +# ============================================================================== +# КОНФИГУРАЦИЯ +# ============================================================================== + +# Учетные данные API reg.ru (получить на https://www.reg.ru/user/account/) +REGRU_USERNAME="your_username" # Имя пользователя reg.ru +REGRU_PASSWORD="your_password" # Пароль от аккаунта reg.ru + +# Параметры домена и сертификата +DOMAIN="dfv24.com" # Основной домен +WILDCARD_DOMAIN="*.dfv24.com" # Wildcard домен +EMAIL="admin@dfv24.com" # Email для уведомлений Let's Encrypt + +# Директории для хранения сертификатов +CERT_DIR="/etc/letsencrypt/live/$DOMAIN" +CREDENTIALS_DIR="/etc/letsencrypt/credentials" +CREDENTIALS_FILE="$CREDENTIALS_DIR/regru.ini" + +# Логирование +LOG_FILE="/var/log/letsencrypt_regru.log" +TIMESTAMP=$(date '+%d.%m.%Y %H:%M:%S') + +# ============================================================================== +# ФУНКЦИИ +# ============================================================================== + +# Логирование сообщений +log() { + echo "[$TIMESTAMP] $1" | tee -a "$LOG_FILE" +} + +# Проверка установки необходимых пакетов +check_dependencies() { + log "Проверка зависимостей..." + + # Проверка certbot + if ! command -v certbot &> /dev/null; then + log "ОШИБКА: certbot не установлен. Установите: apt-get install certbot" + exit 1 + fi + + # Проверка curl + if ! command -v curl &> /dev/null; then + log "ОШИБКА: curl не установлен. Установите: apt-get install curl" + exit 1 + fi + + # Проверка jq для обработки JSON + if ! command -v jq &> /dev/null; then + log "ОШИБКА: jq не установлен. Установите: apt-get install jq" + exit 1 + fi + + log "Все зависимости установлены" +} + +# Создание директории для credentials +setup_credentials_dir() { + log "Настройка директории для учетных данных..." + + if [ ! -d "$CREDENTIALS_DIR" ]; then + mkdir -p "$CREDENTIALS_DIR" + chmod 700 "$CREDENTIALS_DIR" + fi +} + +# Создание файла с учетными данными для certbot-dns-regru +create_credentials_file() { + log "Создание файла с учетными данными reg.ru..." + + cat > "$CREDENTIALS_FILE" < /dev/null; then + CURRENT_NODE_VERSION=$(node --version | cut -d'v' -f2 | cut -d'.' -f1) + if [[ "$CURRENT_NODE_VERSION" != "22" ]]; then + systemctl stop openresty + apt-get purge -y nodejs npm + apt-get autoremove -y + rm -rf /usr/local/bin/node /usr/local/bin/npm + rm -rf /usr/local/lib/node_modules + rm -rf ~/.npm + rm -rf /root/.npm + fi + fi + + NODE_VERSION="22" NODE_MODULE="yarn" setup_nodejs + export NODE_OPTIONS="--openssl-legacy-provider" + + RELEASE=$(curl -fsSL https://api.github.com/repos/NginxProxyManager/nginx-proxy-manager/releases/latest | + grep "tag_name" | + awk '{print substr($2, 3, length($2)-4) }') + + msg_info "Downloading NPM v${RELEASE}" + curl -fsSL "https://codeload.github.com/NginxProxyManager/nginx-proxy-manager/tar.gz/v${RELEASE}" | tar -xz + cd nginx-proxy-manager-"${RELEASE}" || exit + msg_ok "Downloaded NPM v${RELEASE}" + + msg_info "Building Frontend" + ( + sed -i "s|\"version\": \"0.0.0\"|\"version\": \"$RELEASE\"|" backend/package.json + sed -i "s|\"version\": \"0.0.0\"|\"version\": \"$RELEASE\"|" frontend/package.json + cd ./frontend || exit + # Replace node-sass with sass in package.json before installation + sed -i 's/"node-sass".*$/"sass": "^1.92.1",/g' package.json + $STD yarn install --network-timeout 600000 + $STD yarn build + ) + msg_ok "Built Frontend" + + msg_info "Stopping Services" + systemctl stop openresty + systemctl stop npm + msg_ok "Stopped Services" + + msg_info "Cleaning Old Files" + rm -rf /app \ + /var/www/html \ + /etc/nginx \ + /var/log/nginx \ + /var/lib/nginx \ + "$STD" /var/cache/nginx + msg_ok "Cleaned Old Files" + + msg_info "Setting up Environment" + ln -sf /usr/bin/python3 /usr/bin/python + ln -sf /opt/certbot/bin/certbot /usr/local/bin/certbot + ln -sf /usr/local/openresty/nginx/sbin/nginx /usr/sbin/nginx + ln -sf /usr/local/openresty/nginx/ /etc/nginx + sed -i 's+^daemon+#daemon+g' docker/rootfs/etc/nginx/nginx.conf + NGINX_CONFS=$(find "$(pwd)" -type f -name "*.conf") + for NGINX_CONF in $NGINX_CONFS; do + sed -i 's+include conf.d+include /etc/nginx/conf.d+g' "$NGINX_CONF" + done + mkdir -p /var/www/html /etc/nginx/logs + cp -r docker/rootfs/var/www/html/* /var/www/html/ + cp -r docker/rootfs/etc/nginx/* /etc/nginx/ + cp docker/rootfs/etc/letsencrypt.ini /etc/letsencrypt.ini + cp docker/rootfs/etc/logrotate.d/nginx-proxy-manager /etc/logrotate.d/nginx-proxy-manager + ln -sf /etc/nginx/nginx.conf /etc/nginx/conf/nginx.conf + rm -f /etc/nginx/conf.d/dev.conf + mkdir -p /tmp/nginx/body \ + /run/nginx \ + /data/nginx \ + /data/custom_ssl \ + /data/logs \ + /data/access \ + /data/nginx/default_host \ + /data/nginx/default_www \ + /data/nginx/proxy_host \ + /data/nginx/redirection_host \ + /data/nginx/stream \ + /data/nginx/dead_host \ + /data/nginx/temp \ + /var/lib/nginx/cache/public \ + /var/lib/nginx/cache/private \ + /var/cache/nginx/proxy_temp + chmod -R 777 /var/cache/nginx + chown root /tmp/nginx + echo resolver "$(awk 'BEGIN{ORS=" "} $1=="nameserver" {print ($2 ~ ":")? "["$2"]": $2}' /etc/resolv.conf);" >/etc/nginx/conf.d/include/resolvers.conf + if [ ! -f /data/nginx/dummycert.pem ] || [ ! -f /data/nginx/dummykey.pem ]; then + $STD openssl req -new -newkey rsa:2048 -days 3650 -nodes -x509 -subj "/O=Nginx Proxy Manager/OU=Dummy Certificate/CN=localhost" -keyout /data/nginx/dummykey.pem -out /data/nginx/dummycert.pem + fi + mkdir -p /app/global /app/frontend/images + cp -r frontend/dist/* /app/frontend + cp -r frontend/app-images/* /app/frontend/images + cp -r backend/* /app + cp -r global/* /app/global + + # Update Certbot and plugins in virtual environment + if [ -d /opt/certbot ]; then + $STD /opt/certbot/bin/pip install --upgrade pip setuptools wheel + $STD /opt/certbot/bin/pip install --upgrade certbot certbot-dns-cloudflare + fi + msg_ok "Setup Environment" + + msg_info "Initializing Backend" + $STD rm -rf /app/config/default.json + if [ ! -f /app/config/production.json ]; then + cat <<'EOF' >/app/config/production.json +{ + "database": { + "engine": "knex-native", + "knex": { + "client": "sqlite3", + "connection": { + "filename": "/data/database.sqlite" + } + } + } +} +EOF + fi + cd /app || exit + export NODE_OPTIONS="--openssl-legacy-provider" + $STD yarn install --network-timeout 600000 + msg_ok "Initialized Backend" + + msg_info "Starting Services" + sed -i 's/user npm/user root/g; s/^pid/#pid/g' /usr/local/openresty/nginx/conf/nginx.conf + sed -i 's/su npm npm/su root root/g' /etc/logrotate.d/nginx-proxy-manager + sed -i 's/include-system-site-packages = false/include-system-site-packages = true/g' /opt/certbot/pyvenv.cfg + systemctl enable -q --now openresty + systemctl enable -q --now npm + msg_ok "Started Services" + + msg_info "Cleaning up" + rm -rf ~/nginx-proxy-manager-* + msg_ok "Cleaned" + + msg_ok "Updated Successfully" + exit +} + +start +build_container +description + +msg_ok "Completed Successfully!\n" +echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" +echo -e "${INFO}${YW} Access it using the following URL:${CL}" +echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:81${CL}" diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..2a13658 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,13 @@ +# Зависимости для Let's Encrypt RegRu Manager + +# HTTP запросы к API +requests>=2.25.0 + +# Работа с SSL сертификатами +cryptography>=3.4.0 + +# Let's Encrypt клиент +certbot>=1.12.0 + +# Опционально: для сборки исполняемых файлов +pyinstaller>=4.10 diff --git a/systemd/letsencrypt-regru.service b/systemd/letsencrypt-regru.service new file mode 100644 index 0000000..7316ec3 --- /dev/null +++ b/systemd/letsencrypt-regru.service @@ -0,0 +1,16 @@ +[Unit] +Description=Let's Encrypt Certificate Manager for reg.ru +After=network-online.target +Wants=network-online.target + +[Service] +Type=oneshot +User=root +WorkingDirectory=/opt/letsencrypt-regru +ExecStart=/opt/letsencrypt-regru/venv/bin/python /opt/letsencrypt-regru/letsencrypt_regru_api.py --config /etc/letsencrypt-regru/config.json --auto +StandardOutput=journal +StandardError=journal +SyslogIdentifier=letsencrypt-regru + +[Install] +WantedBy=multi-user.target diff --git a/systemd/letsencrypt-regru.timer b/systemd/letsencrypt-regru.timer new file mode 100644 index 0000000..eaff9e0 --- /dev/null +++ b/systemd/letsencrypt-regru.timer @@ -0,0 +1,19 @@ +[Unit] +Description=Let's Encrypt Certificate Auto-Renewal Timer +Requires=letsencrypt-regru.service + +[Timer] +# Запустить через 15 минут после загрузки системы +OnBootSec=15min + +# Запускать каждые 12 часов +OnUnitActiveSec=12h + +# Добавить случайную задержку до 1 часа +RandomizedDelaySec=1h + +# Сохранять информацию о последнем запуске +Persistent=true + +[Install] +WantedBy=timers.target diff --git a/test_certificate.sh b/test_certificate.sh new file mode 100644 index 0000000..80430a4 --- /dev/null +++ b/test_certificate.sh @@ -0,0 +1,143 @@ +#!/bin/bash + +# ============================================================================== +# Скрипт для быстрого создания тестового самоподписанного SSL сертификата +# Использует: openssl (альтернатива Python скрипту) +# ============================================================================== + +set -e + +# Цвета +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Параметры по умолчанию +DOMAIN="${1:-example.com}" +WILDCARD="${2:-yes}" +CERT_DIR="/etc/letsencrypt/live/${DOMAIN}" +VALIDITY_DAYS=90 + +echo -e "${BLUE}╔════════════════════════════════════════════════════════════════╗${NC}" +echo -e "${BLUE}║ Создание тестового самоподписанного SSL сертификата ║${NC}" +echo -e "${BLUE}╚════════════════════════════════════════════════════════════════╝${NC}" +echo "" +echo -e "${YELLOW}Параметры:${NC}" +echo -e " Домен: ${GREEN}${DOMAIN}${NC}" +echo -e " Wildcard: ${GREEN}${WILDCARD}${NC}" +echo -e " Срок действия: ${GREEN}${VALIDITY_DAYS} дней${NC}" +echo -e " Директория: ${GREEN}${CERT_DIR}${NC}" +echo "" +echo -e "${YELLOW}⚠️ ВНИМАНИЕ: Это тестовый сертификат для разработки!${NC}" +echo -e "${YELLOW} Браузеры будут показывать предупреждение безопасности.${NC}" +echo "" + +# Проверка прав root +if [ "$(id -u)" != "0" ]; then + echo -e "${RED}✗ Требуются права root${NC}" + echo -e "Запустите: sudo $0 $@" + exit 1 +fi + +# Создание директории +echo -e "${YELLOW}→ Создание директории...${NC}" +mkdir -p "${CERT_DIR}" +cd "${CERT_DIR}" + +# Подготовка конфигурации для альтернативных имен (SAN) +if [ "${WILDCARD}" = "yes" ]; then + SAN="DNS:${DOMAIN},DNS:*.${DOMAIN}" +else + SAN="DNS:${DOMAIN}" +fi + +# Создание конфигурации OpenSSL +cat > openssl.cnf </dev/null +chmod 600 privkey.pem +echo -e "${GREEN}✓ Приватный ключ сохранен: ${CERT_DIR}/privkey.pem${NC}" + +# Генерация сертификата +echo -e "${YELLOW}→ Генерация самоподписанного сертификата...${NC}" +openssl req \ + -new \ + -x509 \ + -key privkey.pem \ + -out cert.pem \ + -days ${VALIDITY_DAYS} \ + -config openssl.cnf \ + -extensions v3_req \ + 2>/dev/null + +echo -e "${GREEN}✓ Сертификат сохранен: ${CERT_DIR}/cert.pem${NC}" + +# Создание fullchain (копия cert для самоподписанного) +cp cert.pem fullchain.pem +echo -e "${GREEN}✓ Fullchain сохранен: ${CERT_DIR}/fullchain.pem${NC}" + +# Создание пустого chain.pem +touch chain.pem +echo -e "${GREEN}✓ Chain файл создан: ${CERT_DIR}/chain.pem${NC}" + +# Удаление временного файла конфигурации +rm -f openssl.cnf + +echo "" +echo -e "${BLUE}╔════════════════════════════════════════════════════════════════╗${NC}" +echo -e "${BLUE}║ Информация о сертификате ║${NC}" +echo -e "${BLUE}╚════════════════════════════════════════════════════════════════╝${NC}" + +# Вывод информации о сертификате +openssl x509 -in cert.pem -noout -subject -dates -ext subjectAltName + +echo "" +echo -e "${GREEN}╔════════════════════════════════════════════════════════════════╗${NC}" +echo -e "${GREEN}║ ✓ Тестовый сертификат успешно создан ║${NC}" +echo -e "${GREEN}╚════════════════════════════════════════════════════════════════╝${NC}" +echo "" +echo -e "${YELLOW}📁 Файлы сертификата:${NC}" +echo -e " • Приватный ключ: ${CERT_DIR}/privkey.pem" +echo -e " • Сертификат: ${CERT_DIR}/cert.pem" +echo -e " • Fullchain: ${CERT_DIR}/fullchain.pem" +echo -e " • Chain: ${CERT_DIR}/chain.pem" +echo "" +echo -e "${YELLOW}⚠️ ВНИМАНИЕ:${NC}" +echo -e " Это самоподписанный тестовый сертификат!" +echo -e " Браузеры будут показывать предупреждение о безопасности." +echo -e " Используйте ТОЛЬКО для тестирования и разработки!" +echo "" +echo -e "${YELLOW}Использование в Nginx:${NC}" +echo -e " ssl_certificate ${CERT_DIR}/fullchain.pem;" +echo -e " ssl_certificate_key ${CERT_DIR}/privkey.pem;" +echo "" + +# Предложение загрузить в NPM +echo -e "${YELLOW}Загрузить в Nginx Proxy Manager?${NC}" +echo -e " Используйте Python скрипт с опцией --test-cert" +echo -e " или загрузите вручную через веб-интерфейс NPM" +echo ""