Skip to content

Commit 8f8e9a6

Browse files
committed
docs: update CLAUDE.md, README, readme.ru.md for acme.sh and DNS-01 support
1 parent 6342617 commit 8f8e9a6

File tree

3 files changed

+107
-32
lines changed

3 files changed

+107
-32
lines changed

CLAUDE.md

Lines changed: 50 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
44

55
## Overview
66

7-
MikoPBX extension module for automated SSL certificate management via Let's Encrypt (ACME v2). Uses the `getssl` bash script as the ACME client with HTTP-01 validation, and provides real-time certificate request progress via nchan Pub/Sub or polling fallback.
7+
MikoPBX extension module for automated SSL certificate management via Let's Encrypt (ACME v2). Uses `acme.sh` as the primary ACME client with support for both **HTTP-01** and **DNS-01** validation methods. Provides real-time certificate request progress via nchan Pub/Sub or polling fallback.
8+
9+
**DNS-01 support** enables certificate issuance without opening port 80, using DNS provider APIs (Cloudflare, AWS Route53, Hetzner, Yandex Cloud, and 150+ others). Also supports wildcard certificates (`*.domain.com`).
10+
11+
Legacy `getssl` client files are retained for one transition release cycle.
812

913
## Build Commands
1014

@@ -23,59 +27,84 @@ Repeat for each source file (`module-get-ssl-index.js`, `module-get-ssl-status-w
2327
```bash
2428
phpstan analyse
2529
```
26-
Config in `phpstan.neon`: level 0, scans `Lib/`, `Models/`, `bin/`, `App/`, `Setup/`. Requires MikoPBX Core sources at `../../Core/src` for class resolution. Ignores Phalcon 4/5 compatibility class-not-found errors.
30+
Config in `phpstan.neon`: level 0, scans `Lib/`, `Models/`, `bin/`, `App/`, `Setup/`. Requires MikoPBX Core sources at `../../Core/src` for class resolution. Ignores Phalcon 4/5 compatibility class-not-found errors. The `bin/` scripts report `Globals.php` not found — this is expected (runtime file from MikoPBX DI container).
2731

2832
## Architecture
2933

3034
### PSR-4 Namespace
3135
Root namespace `Modules\ModuleGetSsl\` maps to repository root (see `composer.json`).
3236

3337
### Module Lifecycle
34-
1. **Installation** (`Setup/PbxExtensionSetup.php`): Creates DB table `m_ModuleGetSsl`, sets defaults, detects domain from internet interface
38+
1. **Installation** (`Setup/PbxExtensionSetup.php`): Creates DB table `m_ModuleGetSsl`, sets defaults (including `challengeType='http'` for migration), detects domain from internet interface
3539
2. **Runtime** (`Lib/GetSslConf.php`): Registers REST API callbacks, cron tasks, reacts to model changes and PBX lifecycle events
36-
3. **Certificate Request** (`Lib/GetSslMain.php`): Generates getssl config, launches async certificate request, streams progress to browser
37-
4. **Port 80 Management** (`Lib/AcmeHttpPort.php`): Temporarily opens port 80 for ACME HTTP-01 validation — creates nginx server block at `/etc/nginx/mikopbx/modules_servers/ModuleGetSsl_acme80.conf`, adds iptables rules when firewall is active, uses a lock file at `/var/run/custom_modules/ModuleGetSsl/acme_port80.lock` with 300s max open time and automatic stale cleanup
38-
5. **Uninstall**: Removes symlinks from `/usr/bin/getssl`, `/usr/share/getssl`, `/usr/www/sites/.well-known`
40+
3. **Certificate Request** (`Lib/GetSslMain.php`): Prepares acme.sh environment, launches async certificate request (HTTP-01 via `--webroot` or DNS-01 via `--dns`), streams progress to browser
41+
4. **Port 80 Management** (`Lib/AcmeHttpPort.php`): Temporarily opens port 80 for ACME HTTP-01 validation only — creates nginx server block at `/etc/nginx/mikopbx/modules_servers/ModuleGetSsl_acme80.conf`, adds iptables rules when firewall is active, uses a lock file at `/var/run/custom_modules/ModuleGetSsl/acme_port80.lock` with 300s max open time and automatic stale cleanup. **Skipped entirely for DNS-01.**
42+
5. **Uninstall**: Removes symlinks `/usr/bin/acme.sh`, `/usr/bin/getssl`, `/usr/share/getssl`, `/usr/www/sites/.well-known`
3943

4044
### Key Classes
4145

42-
- **`Lib/GetSslConf.php`** — Module configuration hook (extends `ConfigClass`). Handles REST API routing (`GET-CERT`, `CHECK-RESULT`), cron task registration, and PBX lifecycle events (`onAfterPbxStarted`, `onAfterModuleEnable`). Wraps cert requests in `AcmeHttpPort::openPort()`/`closePort()` via try/finally
43-
- **`Lib/GetSslMain.php`** — Core orchestrator. Manages directories, generates getssl config file, launches certificate requests, monitors process completion (120s timeout), pushes real-time updates via nchan, updates SSL keys in PbxSettings DB
44-
- **`Lib/AcmeHttpPort.php`** — Port 80 lifecycle manager. Opens/closes nginx + iptables for ACME validation. Includes stale lock cleanup (cron watchdog + PBX startup)
46+
- **`Lib/GetSslMain.php`** — Core orchestrator. Manages directories, prepares acme.sh environment (`prepareAcmeEnvironment()`), builds acme.sh commands for HTTP-01 or DNS-01, launches certificate requests, monitors process completion (120s for HTTP-01 / 300s for DNS-01), pushes real-time updates via nchan, updates SSL keys in PbxSettings DB. Finds certificates in acme.sh paths first, falls back to legacy getssl paths
47+
- **`Lib/GetSslConf.php`** — Module configuration hook (extends `ConfigClass`). Handles REST API routing (`GET-CERT`, `CHECK-RESULT`), cron task registration, and PBX lifecycle events (`onAfterPbxStarted`, `onAfterModuleEnable`). Conditionally wraps cert requests in `AcmeHttpPort::openPort()`/`closePort()` only for HTTP-01
48+
- **`Lib/AcmeHttpPort.php`** — Port 80 lifecycle manager. Opens/closes nginx + iptables for ACME HTTP-01 validation. Includes stale lock cleanup (cron watchdog + PBX startup)
49+
- **`Lib/DnsProviderRegistry.php`** — Static registry of 23 popular DNS providers with env variable definitions. Single source of truth for backend (form select options) and frontend (dynamic credential fields). Methods: `getProviders()`, `getProviderById()`, `getProviderSelectOptions()`
4550
- **`Lib/MikoPBXVersion.php`** — Compatibility layer for Phalcon 4 vs 5 class names. Version cutoff at PBX 2024.2.30
46-
- **`Models/ModuleGetSsl.php`** — Phalcon ORM model for `m_ModuleGetSsl` table (fields: `id`, `domainName`, `autoUpdate`). Source table: `m_ModuleGetSsl`
47-
- **`App/Controllers/ModuleGetSslController.php`** — Web UI controller: renders form, handles save, triggers certificate request on save
48-
- **`App/Forms/ModuleGetSslForm.php`** — Phalcon form definition. Note: `addCheckBox()` helper exists for backward compat and can be removed when `min_pbx_version` ≥ 2024.3.0
51+
- **`Models/ModuleGetSsl.php`** — Phalcon ORM model for `m_ModuleGetSsl` table. Fields: `id`, `domainName`, `autoUpdate`, `challengeType` ('http'|'dns'), `dnsProvider` (e.g. 'dns_cf'), `dnsCredentials` (base64-encoded JSON)
52+
- **`App/Controllers/ModuleGetSslController.php`** — Web UI controller: renders form with DNS provider options, passes `dnsProvidersJson` to view for JS, handles save including `dnsCredentials`
53+
- **`App/Forms/ModuleGetSslForm.php`** — Phalcon form definition with Select for `challengeType`, Select for `dnsProvider` (with search), Hidden for `dnsCredentials`. Note: `addCheckBox()` helper exists for backward compat and can be removed when `min_pbx_version` ≥ 2024.3.0
54+
55+
### ACME Client (`bin/acme/`)
56+
57+
- **`bin/acme/acme.sh`** — acme.sh ACME client (primary)
58+
- **`bin/acme/dnsapi/`** — 168 DNS provider hook scripts for DNS-01 validation
59+
- **`bin/getssl`** — Legacy getssl client (retained for transition)
60+
- **`bin/utils/`** — Legacy getssl utilities (retained for transition)
4961

5062
### CLI Scripts (`bin/`)
5163

5264
All scripts bootstrap via `require_once('Globals.php')` which loads the MikoPBX DI container.
5365

54-
- **`cronRenewCert.php`** — Cron entry point: opens port 80, runs `getssl -a -U -q`, installs cert, closes port 80
55-
- **`reloadCmd.php`** — Called by getssl after successful cert issuance; installs cert/key into PbxSettings
66+
- **`cronRenewCert.php`** — Cron entry point: conditionally opens port 80 (HTTP-01 only), runs `acme.sh --cron`, installs cert, closes port 80
67+
- **`reloadCmd.php`** — Called by acme.sh `--reloadcmd` after successful cert issuance; installs cert/key into PbxSettings
5668
- **`reloadCron.php`** — Reloads cron configuration when module settings change
5769
- **`cleanupPort80.php`** — Cron watchdog (runs every minute): calls `AcmeHttpPort::cleanupStale()`
5870
- **`updateCert.php`** — Manual cert request without nchan (runs synchronously)
5971

6072
### Frontend (ES6 → Babel → ES5)
6173

62-
- **`public/assets/js/src/module-get-ssl-index.js`** — Form controller: validation, module status toggle, triggers API call to start certificate request, handles async response channel
74+
- **`public/assets/js/src/module-get-ssl-index.js`** — Form controller: validation, module status toggle, challenge type switching (HTTP-01/DNS-01), dynamic DNS provider credential fields based on `dnsProvidersMeta`, credential collection/restoration (base64 JSON), triggers API call to start certificate request
6375
- **`public/assets/js/src/module-get-ssl-status-worker.js`** — Real-time progress: EventSource (PBX ≥2024.2.30) or polling fallback, Ace editor for log display, 4-stage processing pipeline (STAGE_1–4)
6476

6577
### Real-time Updates Flow
6678

6779
1. Browser sends `POST /pbxcore/api/modules/ModuleGetSsl/get-cert` with `X-Async-Response-Channel-Id: module-get-ssl-pub`
68-
2. Backend opens port 80, generates config, launches getssl, monitors process (120s timeout)
80+
2. Backend conditionally opens port 80 (HTTP-01 only), prepares acme.sh environment, launches acme.sh, monitors process (120s HTTP-01 / 300s DNS-01)
6981
3. Progress pushed to nchan channel `module-get-ssl-pub` as JSON with `moduleUniqueId`, `stage`, `stageDetails`, `pid`
7082
4. Browser subscribes via EventSource (PBX ≥2024.2.30) or polls `check-result` endpoint
71-
5. Backend closes port 80 in `finally` block
83+
5. Backend closes port 80 in `finally` block (HTTP-01 only)
84+
85+
### DNS-01 Challenge Flow
86+
87+
1. User selects DNS-01 in the UI, picks a DNS provider, enters API credentials
88+
2. Credentials stored as base64-encoded JSON in `dnsCredentials` model field
89+
3. On cert request: credentials decoded to `export VAR='val'; ...` prefix before acme.sh command
90+
4. acme.sh creates `_acme-challenge` TXT record via DNS provider API, validates, cleans up
91+
5. No port 80 required — works behind firewalls and NAT
7292

7393
### Symlinks Created at Runtime
74-
- `/usr/bin/getssl``{moduleDir}/bin/getssl`
75-
- `/usr/share/getssl``{moduleDir}/bin/utils`
76-
- `/usr/www/sites/.well-known``{moduleDir}/db/getssl/.well-known`
94+
- `/usr/bin/acme.sh``{moduleDir}/bin/acme/acme.sh`
95+
- `/usr/bin/getssl``{moduleDir}/bin/getssl` (legacy)
96+
- `/usr/share/getssl``{moduleDir}/bin/utils` (legacy)
97+
- `/usr/www/sites/.well-known``{moduleDir}/db/getssl/.well-known` (HTTP-01 only)
7798
- `/usr/bin/nslookup` → busybox
7899

100+
### Certificate Storage Paths
101+
102+
acme.sh stores certificates in `{moduleDir}/db/acme/{domain}/`:
103+
- `fullchain.cer` — full certificate chain
104+
- `{domain}.key` — private key
105+
106+
Legacy getssl paths (`{moduleDir}/db/getssl/{domain}/`) are checked as fallback.
107+
79108
## Phalcon Version Compatibility
80109

81110
Always use `MikoPBXVersion` for version-dependent class imports (Di, Validation, Uniqueness, Text, Logger). PBX versions ≥2024.2.30 use Phalcon 5; older versions use Phalcon 4. Do not hardcode Phalcon namespace paths.
@@ -89,5 +118,5 @@ Language files in `Messages/`. Translation keys prefixed with `module_getssl_`.
89118
- PHP 7.4+ / 8.0+, Phalcon 4 or 5
90119
- MikoPBX Core framework (`MikoPBX\Common`, `MikoPBX\Core`, `MikoPBX\Modules`, `MikoPBX\AdminCabinet`)
91120
- jQuery, Semantic UI, Ace Editor (from MikoPBX core frontend)
92-
- `getssl` ACME client (`bin/getssl`, embedded bash script)
121+
- `acme.sh` ACME client (`bin/acme/acme.sh`, embedded bash script)
93122
- Minimum PBX version: 2024.1.114 (from `module.json`)

README.md

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,43 @@
66

77
This module automates obtaining and renewing free SSL certificates from [Let's Encrypt](https://letsencrypt.org/) for your MikoPBX web interface. After setup, the HTTPS certificate is issued automatically and renewed on schedule — no manual steps required.
88

9+
## Verification Methods
10+
11+
The module supports two verification methods:
12+
13+
### HTTP-01 (default)
14+
The classic method — Let's Encrypt verifies domain ownership by making an HTTP request to your server on port 80. Simple setup: just enter your domain name and click save.
15+
16+
**Requirements:** port 80 accessible from the internet. The module opens it temporarily during verification and closes it immediately after.
17+
18+
### DNS-01
19+
Certificate issuance via your DNS provider's API. No need to open port 80 — works behind firewalls, NAT, and in private networks. Also supports **wildcard certificates** (`*.domain.com`).
20+
21+
**Supported providers (20+):** Cloudflare, Amazon Route53, GoDaddy, DigitalOcean, Hetzner, Yandex Cloud, OVH, Selectel, reg.ru, Beget, Namecheap, Azure DNS, Vultr, DuckDNS, Linode, INWX, DreamHost, deSEC, PowerDNS, ISPConfig, Google Cloud DNS, and any custom provider.
22+
23+
**Setup:** select DNS-01 in the verification method dropdown, choose your DNS provider, enter API credentials, and click save.
24+
925
## How It Works
1026

11-
1. You install the module from the MikoPBX module marketplace
12-
2. Enter your domain name in the module settings and click save
13-
3. The module requests a certificate from Let's Encrypt, and the progress is shown in real time
14-
4. Once issued, the certificate is automatically applied to the MikoPBX web interface
27+
1. Install the module from the MikoPBX module marketplace
28+
2. Enter your domain name in the module settings
29+
3. Choose a verification method (HTTP-01 or DNS-01)
30+
4. For DNS-01 — select your DNS provider and enter API credentials
31+
5. Click save — the module requests a certificate from Let's Encrypt, progress is shown in real time
32+
6. Once issued, the certificate is automatically applied to the MikoPBX web interface
1533

1634
Auto-renewal runs on the 1st and 15th of each month. If the certificate is due for renewal, it will be updated automatically.
1735

1836
## Requirements
1937

2038
- MikoPBX **2024.1.114** or newer
21-
- A domain name pointing to your PBX public IP address (A record)
22-
- Port **80** accessible from the internet (required for Let's Encrypt HTTP-01 validation)
39+
- A domain name pointing to your PBX (A record)
40+
- **For HTTP-01:** port **80** accessible from the internet
41+
- **For DNS-01:** API credentials from your DNS provider (no open ports required)
42+
43+
## Technical Details
44+
45+
The module uses [acme.sh](https://github.com/acmesh-official/acme.sh) as the ACME client — a widely used, zero-dependency bash script supporting the full ACME v2 protocol and 150+ DNS providers.
2346

2447
## Documentation
2548

readme.ru.md

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,43 @@
66

77
Модуль автоматически получает и обновляет бесплатные SSL-сертификаты от [Let's Encrypt](https://letsencrypt.org/) для веб-интерфейса MikoPBX. После настройки HTTPS-сертификат выпускается автоматически и продлевается по расписанию — никаких ручных действий не требуется.
88

9+
## Способы проверки
10+
11+
Модуль поддерживает два способа проверки владения доменом:
12+
13+
### HTTP-01 (по умолчанию)
14+
Классический способ — Let's Encrypt проверяет владение доменом, отправляя HTTP-запрос на ваш сервер на порт 80. Простая настройка: достаточно указать доменное имя и нажать сохранить.
15+
16+
**Требование:** порт 80 должен быть доступен из интернета. Модуль открывает его временно на время проверки и закрывает сразу после.
17+
18+
### DNS-01
19+
Выпуск сертификата через API вашего DNS-провайдера. Не нужно открывать порт 80 — работает за файрволами, NAT и в закрытых сетях. Также поддерживает **wildcard-сертификаты** (`*.domain.com`).
20+
21+
**Поддерживаемые провайдеры (20+):** Cloudflare, Amazon Route53, GoDaddy, DigitalOcean, Hetzner, Yandex Cloud, OVH, Selectel, reg.ru, Beget, Namecheap, Azure DNS, Vultr, DuckDNS, Linode, INWX, DreamHost, deSEC, PowerDNS, ISPConfig, Google Cloud DNS и любой пользовательский провайдер.
22+
23+
**Настройка:** выберите DNS-01 в выпадающем списке способа проверки, выберите DNS-провайдера, введите API-ключи и нажмите сохранить.
24+
925
## Как это работает
1026

1127
1. Установите модуль из маркетплейса модулей MikoPBX
12-
2. Укажите доменное имя в настройках модуля и нажмите сохранить
13-
3. Модуль запросит сертификат у Let's Encrypt, прогресс отображается в реальном времени
14-
4. После выпуска сертификат автоматически применяется к веб-интерфейсу MikoPBX
28+
2. Укажите доменное имя в настройках модуля
29+
3. Выберите способ проверки (HTTP-01 или DNS-01)
30+
4. Для DNS-01 — выберите DNS-провайдера и введите API-ключи
31+
5. Нажмите сохранить — модуль запросит сертификат у Let's Encrypt, прогресс отображается в реальном времени
32+
6. После выпуска сертификат автоматически применяется к веб-интерфейсу MikoPBX
1533

1634
Автоматическое продление запускается 1-го и 15-го числа каждого месяца. Если сертификат подлежит обновлению, он будет продлён автоматически.
1735

1836
## Требования
1937

2038
- MikoPBX версии **2024.1.114** или новее
21-
- Доменное имя, указывающее на публичный IP-адрес АТС (A-запись)
22-
- Порт **80**, доступный из интернета (необходим для HTTP-01 валидации Let's Encrypt)
39+
- Доменное имя, указывающее на вашу АТС (A-запись)
40+
- **Для HTTP-01:** порт **80**, доступный из интернета
41+
- **Для DNS-01:** API-ключи от вашего DNS-провайдера (открытые порты не нужны)
42+
43+
## Технические детали
44+
45+
Модуль использует [acme.sh](https://github.com/acmesh-official/acme.sh) в качестве ACME-клиента — широко используемый bash-скрипт без зависимостей, поддерживающий полный протокол ACME v2 и более 150 DNS-провайдеров.
2346

2447
## Документация
2548

0 commit comments

Comments
 (0)