From daf76b49582699c3820412ab3dcab42958397f09 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 30 Nov 2025 07:54:16 +0000 Subject: [PATCH 1/4] Initial plan From 8070e4b05a787aef7f82bfb75cf57a51e74e4a0a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 30 Nov 2025 08:04:52 +0000 Subject: [PATCH 2/4] Add Hostinger DNS provider support Co-authored-by: SmartCodeJunctionInfinity <166026244+SmartCodeJunctionInfinity@users.noreply.github.com> --- DNS_PROVIDERS.md | 24 ++++++++++++++++----- modules/core/certificates.py | 14 ++++++++---- modules/core/settings.py | 5 +++-- modules/core/utils.py | 11 ++++++++-- requirements.txt | 1 + templates/settings.html | 42 +++++++++++++++++++++++++++++++++--- 6 files changed, 81 insertions(+), 16 deletions(-) diff --git a/DNS_PROVIDERS.md b/DNS_PROVIDERS.md index cb32db5..817c6bc 100644 --- a/DNS_PROVIDERS.md +++ b/DNS_PROVIDERS.md @@ -1,6 +1,6 @@ # DNS Providers Support -CertMate now supports **22 DNS providers** for Let's Encrypt DNS challenges through individual certbot plugins that provide reliable, well-tested DNS challenge support. +CertMate now supports **23 DNS providers** for Let's Encrypt DNS challenges through individual certbot plugins that provide reliable, well-tested DNS challenge support. ## 🎯 Supported Providers @@ -30,6 +30,7 @@ All providers are supported through individual, well-maintained certbot plugins: | **Dynu** | `certbot-dns-dynudns` | API Token | Dynamic DNS service | | **ArvanCloud** | `certbot-dns-arvancloud` | API Key | Iranian cloud provider | | **ACME-DNS** | `certbot-acme-dns` | API URL, Username, Password, Subdomain | Generic ACME-DNS server | +| **Hostinger** | `certbot-dns-hostinger` | API Token | Web hosting provider | ## 🛠 Configuration @@ -224,6 +225,19 @@ curl -X POST http://localhost:5000/api/settings \ } ``` +### Hostinger +```bash +# Get API token from Hostinger Control Panel +{ + "dns_provider": "hostinger", + "dns_providers": { + "hostinger": { + "api_token": "your_hostinger_api_token" + } + } +} +``` + ## Creating Certificates ### Using Default Provider @@ -247,7 +261,7 @@ curl -X POST http://localhost:5000/api/certificates/create \ ## 🚀 How Provider Support Works -CertMate uses individual, well-maintained certbot plugins for maximum reliability. All 19 supported providers use dedicated certbot plugins, ensuring stability and consistent behavior across all DNS providers. +CertMate uses individual, well-maintained certbot plugins for maximum reliability. All 23 supported providers use dedicated certbot plugins, ensuring stability and consistent behavior across all DNS providers. ## 🔍 Provider Detection Logic @@ -258,7 +272,7 @@ supported_providers = [ 'digitalocean', 'linode', 'gandi', 'ovh', 'namecheap', 'vultr', 'dnsmadeeasy', 'nsone', 'rfc2136', 'hetzner', 'porkbun', 'godaddy', 'he-ddns', 'dynudns', - 'arvancloud', 'acme-dns' + 'arvancloud', 'acme-dns', 'hostinger' ] if dns_provider in supported_providers: @@ -343,11 +357,11 @@ curl -X GET http://localhost:5000/api/settings/dns-providers \ ## 📊 Provider Statistics -- **Total Supported**: 21 providers +- **Total Supported**: 23 providers - **Geographic Coverage**: Global (all continents) - **Enterprise Providers**: AWS, Azure, GCP, Cloudflare, PowerDNS, DNS Made Easy, NS1 - **European Providers**: OVH, Gandi, Hetzner -- **Budget Providers**: Namecheap, DigitalOcean, Linode, Vultr, Porkbun +- **Budget Providers**: Namecheap, DigitalOcean, Linode, Vultr, Porkbun, Hostinger - **Free Providers**: Hurricane Electric, Dynu, ACME-DNS --- diff --git a/modules/core/certificates.py b/modules/core/certificates.py index b309cbc..dd6cdfa 100644 --- a/modules/core/certificates.py +++ b/modules/core/certificates.py @@ -17,7 +17,7 @@ create_powerdns_config, create_digitalocean_config, create_linode_config, create_gandi_config, create_ovh_config, create_namecheap_config, create_arvancloud_config, create_infomaniak_config, create_acme_dns_config, - create_multi_provider_config + create_hostinger_config, create_multi_provider_config ) logger = logging.getLogger(__name__) @@ -83,7 +83,8 @@ def _create_dns_config_compat(self, dns_provider, dns_config): 'namecheap': 'create_namecheap_config', 'arvancloud': 'create_arvancloud_config', 'infomaniak': 'create_infomaniak_config', - 'acme-dns': 'create_acme_dns_config' + 'acme-dns': 'create_acme_dns_config', + 'hostinger': 'create_hostinger_config' } # Try to get function from app module for test compatibility @@ -144,6 +145,8 @@ def _create_dns_config_compat(self, dns_provider, dns_config): dns_config.get('password', ''), dns_config.get('subdomain', ''), ) + elif dns_provider == 'hostinger': + return config_func(dns_config.get('api_token', '')) else: # Multi-provider config: (provider, config_dict) return config_func(dns_provider, dns_config) @@ -201,6 +204,8 @@ def _create_dns_config_compat(self, dns_provider, dns_config): dns_config.get('password', ''), dns_config.get('subdomain', ''), ) + elif dns_provider == 'hostinger': + return create_hostinger_config(dns_config.get('api_token', '')) else: return create_multi_provider_config(dns_provider, dns_config) @@ -446,7 +451,7 @@ def create_certificate(self, domain, email, dns_provider=None, dns_config=None, route53_env_set = True plugin_name = 'dns-route53' - elif dns_provider in ['azure', 'google', 'powerdns', 'digitalocean', 'linode', 'gandi', 'ovh', 'namecheap', 'arvancloud', 'infomaniak', 'acme-dns']: + elif dns_provider in ['azure', 'google', 'powerdns', 'digitalocean', 'linode', 'gandi', 'ovh', 'namecheap', 'arvancloud', 'infomaniak', 'acme-dns', 'hostinger']: # Use compatibility function for config creation credentials_file = self._create_dns_config_compat(dns_provider, dns_config) plugin_name = f'dns-{dns_provider}' @@ -501,7 +506,8 @@ def create_certificate(self, domain, email, dns_provider=None, dns_config=None, 'namecheap': 300, 'arvancloud': 120, 'infomaniak': 300, - 'acme-dns': 30 + 'acme-dns': 30, + 'hostinger': 120 } propagation_time = int(propagation_map.get(dns_provider, default_map.get(dns_provider, 120))) certbot_cmd.extend([f'--{plugin_name}-propagation-seconds', str(propagation_time)]) diff --git a/modules/core/settings.py b/modules/core/settings.py index 17afaeb..7760dfb 100644 --- a/modules/core/settings.py +++ b/modules/core/settings.py @@ -257,7 +257,7 @@ def save_settings(self, settings, backup_reason="auto_save"): return False # Validate dns_provider against supported set - supported_providers = {'cloudflare','route53','azure','google','powerdns','digitalocean','linode','gandi','ovh','namecheap','vultr','dnsmadeeasy','nsone','rfc2136','hetzner','porkbun','godaddy','he-ddns','dynudns','arvancloud','infomaniak','acme-dns'} + supported_providers = {'cloudflare','route53','azure','google','powerdns','digitalocean','linode','gandi','ovh','namecheap','vultr','dnsmadeeasy','nsone','rfc2136','hetzner','porkbun','godaddy','he-ddns','dynudns','arvancloud','infomaniak','acme-dns','hostinger'} if 'dns_provider' in settings and settings['dns_provider'] not in supported_providers: logger.error(f"Invalid dns_provider: {settings['dns_provider']}") return False @@ -323,7 +323,8 @@ def save_settings(self, settings, backup_reason="auto_save"): 'namecheap': 300, 'arvancloud': 120, 'infomaniak': 300, - 'acme-dns': 30 + 'acme-dns': 30, + 'hostinger': 120 } if 'dns_propagation_seconds' not in settings or not isinstance(settings['dns_propagation_seconds'], dict): settings['dns_propagation_seconds'] = defaults diff --git a/modules/core/utils.py b/modules/core/utils.py index 87f7449..63adf1e 100644 --- a/modules/core/utils.py +++ b/modules/core/utils.py @@ -52,14 +52,16 @@ 'porkbun': ['api_key', 'secret_key'], 'godaddy': ['api_key', 'secret'], 'he-ddns': ['username', 'password'], - 'dynudns': ['token'] + 'dynudns': ['token'], + 'hostinger': ['api_token'] } # A mapping of multi-provider names to their certbot plugin .ini filename. _MULTI_PROVIDER_PLUGIN_FILES = { 'vultr': 'vultr.ini', 'dnsmadeeasy': 'dnsmadeeasy.ini', 'nsone': 'nsone.ini', 'rfc2136': 'rfc2136.ini', 'hetzner': 'hetzner.ini', 'porkbun': 'porkbun.ini', - 'godaddy': 'godaddy.ini', 'he-ddns': 'he-ddns.ini', 'dynudns': 'dynudns.ini' + 'godaddy': 'godaddy.ini', 'he-ddns': 'he-ddns.ini', 'dynudns': 'dynudns.ini', + 'hostinger': 'hostinger.ini' } # A data-driven template for building multi-provider config files. @@ -80,6 +82,7 @@ 'godaddy': {'dns_godaddy_key': 'api_key', 'dns_godaddy_secret': 'secret'}, 'he-ddns': {'dns_he_ddns_username': 'username', 'dns_he_ddns_password': 'password'}, 'dynudns': {'dns_dynudns_token': 'token'}, + 'hostinger': {'dns_hostinger_api_token': 'api_token'}, } @@ -359,6 +362,10 @@ def create_acme_dns_config(api_url: str, username: str, password: str, subdomain }}""" return _create_config_file("acme-dns", content) +def create_hostinger_config(api_token: str) -> Path: + """Create Hostinger DNS credentials file.""" + return _create_config_file("hostinger", f"dns_hostinger_api_token = {api_token}\n") + def create_multi_provider_config(provider: str, config_data: Dict[str, Any]) -> Optional[Path]: """ Creates a certbot DNS plugin configuration file from a provider and data. diff --git a/requirements.txt b/requirements.txt index 391e278..04290e3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -31,6 +31,7 @@ certbot-dns-porkbun certbot-dns-godaddy certbot-dns-arvancloud certbot-acme-dns +certbot-dns-hostinger # Cloud SDK dependencies boto3==1.34.144 # AWS support diff --git a/templates/settings.html b/templates/settings.html index ef6cb3b..c5eb37a 100644 --- a/templates/settings.html +++ b/templates/settings.html @@ -342,6 +342,16 @@
- Generate an API token from your Hostinger Control Panel under Account Settings > API. + Generate an API token from your Hostinger Control Panel under Account Settings > API.
From f0d72fd449207d49f1e5305043b1df4f643a448f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 30 Nov 2025 08:24:08 +0000 Subject: [PATCH 4/4] Add Hostinger to all locations matching GoDaddy for consistency Co-authored-by: SmartCodeJunctionInfinity <166026244+SmartCodeJunctionInfinity@users.noreply.github.com> --- DNS_ANALYSIS_INDEX.md | 7 ++++--- DNS_PROVIDERS_QUICK_REFERENCE.txt | 6 ++++++ DNS_PROVIDER_ARCHITECTURE.md | 16 ++++++++++------ README.md | 6 ++++-- modules/api/models.py | 10 ++++++++-- modules/core/settings.py | 3 ++- requirements-extended.txt | 3 +++ templates/help.html | 4 ++++ templates/index.html | 1 + 9 files changed, 42 insertions(+), 14 deletions(-) diff --git a/DNS_ANALYSIS_INDEX.md b/DNS_ANALYSIS_INDEX.md index 25f7f34..de29f0b 100644 --- a/DNS_ANALYSIS_INDEX.md +++ b/DNS_ANALYSIS_INDEX.md @@ -124,18 +124,19 @@ DNS_ANALYSIS_INDEX.md (You are here) ## Supported Providers Summary -**Total:** 21 DNS Providers +**Total:** 23 DNS Providers ### By Category - **Major Cloud:** Cloudflare, AWS Route53, Google Cloud, Azure (4) - **Enterprise:** PowerDNS, DNS Made Easy, NS1 (3) - **Cloud Infrastructure:** DigitalOcean, Linode, Vultr, Hetzner (4) - **Registrars:** Gandi, Namecheap, Porkbun, GoDaddy (4) +- **Web Hosting:** Hostinger (1) - **Regional:** OVH, ArvanCloud (2) -- **Specialized:** RFC2136, ACME-DNS, Hurricane Electric, Dynu (4) +- **Specialized:** RFC2136, ACME-DNS, Hurricane Electric, Dynu, Infomaniak (5) ### By Features -- **Single-field credentials:** Cloudflare, DigitalOcean, Linode, Gandi, Vultr, Hetzner, NS1, ArvanCloud +- **Single-field credentials:** Cloudflare, DigitalOcean, Linode, Gandi, Vultr, Hetzner, NS1, ArvanCloud, Hostinger - **Multi-field credentials:** Route53, Azure, Google Cloud, PowerDNS, OVH, Namecheap, RFC2136, ACME-DNS, etc. - **Environment variables:** Route53 (AWS_*), Azure (AZURE_*), Google (GOOGLE_*) - **Environment-only:** PowerDNS (POWERDNS_*), Cloudflare (CLOUDFLARE_TOKEN) diff --git a/DNS_PROVIDERS_QUICK_REFERENCE.txt b/DNS_PROVIDERS_QUICK_REFERENCE.txt index efe5bd7..3d640b9 100644 --- a/DNS_PROVIDERS_QUICK_REFERENCE.txt +++ b/DNS_PROVIDERS_QUICK_REFERENCE.txt @@ -28,6 +28,9 @@ DOMAIN REGISTRARS: 14. Porkbun certbot-dns-porkbun 15. GoDaddy certbot-dns-godaddy +WEB HOSTING PROVIDERS: + 16. Hostinger certbot-dns-hostinger + REGIONAL PROVIDERS: 16. OVH certbot-dns-ovh 17. ArvanCloud certbot-dns-arvancloud @@ -70,6 +73,9 @@ Single-field providers: • nsone: api_key • arvancloud: api_key +Single-field providers (continued): + • hostinger: api_token + Two-field providers: • route53: access_key_id, secret_access_key (+ region) • dnsmadeeasy: api_key, secret_key diff --git a/DNS_PROVIDER_ARCHITECTURE.md b/DNS_PROVIDER_ARCHITECTURE.md index fb54c3b..94136e3 100644 --- a/DNS_PROVIDER_ARCHITECTURE.md +++ b/DNS_PROVIDER_ARCHITECTURE.md @@ -38,15 +38,18 @@ CertMate implements a **modular, extensible DNS provider architecture** supporti 14. **Porkbun** - `certbot-dns-porkbun` - Domain registrar with DNS 15. **GoDaddy** - `certbot-dns-godaddy` - Domain registrar +### Web Hosting Providers +16. **Hostinger** - `certbot-dns-hostinger` - Web hosting provider + ### Regional Providers -16. **OVH** - `certbot-dns-ovh` - European hosting -17. **ArvanCloud** - `certbot-dns-arvancloud` - Iranian cloud provider +17. **OVH** - `certbot-dns-ovh` - European hosting +18. **ArvanCloud** - `certbot-dns-arvancloud` - Iranian cloud provider ### Specialized Providers -18. **RFC2136** - `certbot-dns-rfc2136` - Standard DNS update protocol (BIND-compatible) -19. **ACME-DNS** - `certbot-acme-dns` - Generic ACME-DNS server -20. **Hurricane Electric** - `certbot-dns-he-ddns` - Free DNS hosting -21. **Dynu** - `certbot-dns-dynudns` - Dynamic DNS service +19. **RFC2136** - `certbot-dns-rfc2136` - Standard DNS update protocol (BIND-compatible) +20. **ACME-DNS** - `certbot-acme-dns` - Generic ACME-DNS server +21. **Hurricane Electric** - `certbot-dns-he-ddns` - Free DNS hosting +22. **Dynu** - `certbot-dns-dynudns` - Dynamic DNS service --- @@ -202,6 +205,7 @@ POWERDNS_API_KEY=your_key | **dynudns** | `token` | | **arvancloud** | `api_key` | | **acme-dns** | `api_url`, `username`, `password`, `subdomain` | +| **hostinger** | `api_token` | --- diff --git a/README.md b/README.md index 98cc4c4..0f74396 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ CertMate solves the complexity of SSL certificate management in modern distributed architectures. Whether you're running a single application or managing certificates across multiple datacenters, CertMate provides: - **🔄 Zero-Downtime Automation** - Certificates renew automatically 30 days before expiry -- **🌐 Multi-Cloud Support** - Works with 19 DNS providers (Cloudflare, AWS, Azure, GCP, Hetzner, Porkbun, GoDaddy, and more) +- **🌐 Multi-Cloud Support** - Works with 23 DNS providers (Cloudflare, AWS, Azure, GCP, Hetzner, Porkbun, GoDaddy, Hostinger, and more) - **🚀 Enterprise-Ready** - Docker, Kubernetes, REST API, and monitoring built-in - **📦 Simple Integration** - One-URL certificate downloads for easy automation - **🔒 Security-First** - Bearer token authentication, secure file permissions, audit logging @@ -118,6 +118,7 @@ CertMate supports **19 DNS providers** through Let's Encrypt DNS-01 challenge vi | ** Hetzner** | API Token | ➖ Single | European cloud hosting | ✅ **Stable** | | **🟡 Porkbun** | API Key, Secret Key | ➖ Single | Domain registrar with DNS | ✅ **Stable** | | **🟢 GoDaddy** | API Key, Secret | ➖ Single | Popular domain registrar | ✅ **Stable** | +| **🟣 Hostinger** | API Token | ➖ Single | Web hosting provider | ✅ **Stable** | | **🔵 Hurricane Electric** | Username, Password | ➖ Single | Free DNS hosting | ✅ **Stable** | | **🔶 Dynu** | API Token | ➖ Single | Dynamic DNS service | ✅ **Stable** | @@ -126,7 +127,8 @@ CertMate supports **19 DNS providers** through Let's Encrypt DNS-01 challenge vi - **Enterprise Multi-Account**: Cloudflare, AWS Route53, Azure DNS, Google Cloud DNS, DigitalOcean, PowerDNS, RFC2136 - **Cloud Providers**: AWS Route53, Azure DNS, Google Cloud DNS, DigitalOcean, Linode, Vultr, Hetzner - **Enterprise DNS**: Cloudflare, DNS Made Easy, NS1, PowerDNS -- **Domain Registrars**: Gandi, OVH, Namecheap, Porkbun, GoDaddy +- **Domain Registrars**: Gandi, OVH, Namecheap, Porkbun, GoDaddy +- **Web Hosting**: Hostinger - **European Providers**: OVH, Gandi, Hetzner - **Free Services**: Hurricane Electric, Dynu - **Standard Protocols**: RFC2136 (for BIND and compatible servers) diff --git a/modules/api/models.py b/modules/api/models.py index 558dd66..ca7853f 100644 --- a/modules/api/models.py +++ b/modules/api/models.py @@ -90,6 +90,10 @@ def create_api_models(api): 'api_key': fields.String(description='ArvanCloud API key') }) + hostinger_model = api.model('HostingerConfig', { + 'api_token': fields.String(description='Hostinger API token') + }) + acme_dns_model = api.model('ACMEDNSConfig', { 'api_url': fields.String(description='ACME-DNS server URL'), 'username': fields.String(description='ACME-DNS username'), @@ -124,6 +128,7 @@ def create_api_models(api): 'he-ddns': fields.Nested(he_ddns_model), 'dynudns': fields.Nested(dynudns_model), 'arvancloud': fields.Nested(arvancloud_model), + 'hostinger': fields.Nested(hostinger_model), 'acme-dns': fields.Nested(acme_dns_model), # Support for any other provider via certbot-dns-multi 'multi': fields.Raw(description='Configuration for any DNS provider via certbot-dns-multi') @@ -145,13 +150,13 @@ def create_api_models(api): 'email': fields.String(description='Email for Let\'s Encrypt'), 'auto_renew': fields.Boolean(description='Enable auto-renewal'), 'api_bearer_token': fields.String(description='API bearer token for authentication'), - 'dns_provider': fields.String(description='Active DNS provider', enum=['cloudflare', 'route53', 'azure', 'google', 'powerdns', 'digitalocean', 'linode', 'gandi', 'ovh', 'namecheap', 'vultr', 'dnsmadeeasy', 'nsone', 'rfc2136', 'hetzner', 'porkbun', 'godaddy', 'he-ddns', 'dynudns', 'arvancloud', 'acme-dns']), + 'dns_provider': fields.String(description='Active DNS provider', enum=['cloudflare', 'route53', 'azure', 'google', 'powerdns', 'digitalocean', 'linode', 'gandi', 'ovh', 'namecheap', 'vultr', 'dnsmadeeasy', 'nsone', 'rfc2136', 'hetzner', 'porkbun', 'godaddy', 'he-ddns', 'dynudns', 'arvancloud', 'acme-dns', 'hostinger']), 'dns_providers': fields.Nested(dns_providers_model, description='DNS provider configurations') }) create_cert_model = api.model('CreateCertificate', { 'domain': fields.String(required=True, description='Domain name to create certificate for'), - 'dns_provider': fields.String(description='DNS provider to use (optional, uses default from settings)', enum=['cloudflare', 'route53', 'azure', 'google', 'powerdns', 'digitalocean', 'linode', 'gandi', 'ovh', 'namecheap', 'vultr', 'dnsmadeeasy', 'nsone', 'rfc2136', 'hetzner', 'porkbun', 'godaddy', 'he-ddns', 'dynudns', 'arvancloud', 'acme-dns']), + 'dns_provider': fields.String(description='DNS provider to use (optional, uses default from settings)', enum=['cloudflare', 'route53', 'azure', 'google', 'powerdns', 'digitalocean', 'linode', 'gandi', 'ovh', 'namecheap', 'vultr', 'dnsmadeeasy', 'nsone', 'rfc2136', 'hetzner', 'porkbun', 'godaddy', 'he-ddns', 'dynudns', 'arvancloud', 'acme-dns', 'hostinger']), 'account_id': fields.String(description='DNS provider account ID to use (optional, uses default account if not specified)'), 'ca_provider': fields.String(description='Certificate Authority provider to use (optional, uses default from settings)', enum=['letsencrypt', 'digicert', 'private_ca']) }) @@ -299,6 +304,7 @@ def create_api_models(api): 'he_ddns_model': he_ddns_model, 'dynudns_model': dynudns_model, 'arvancloud_model': arvancloud_model, + 'hostinger_model': hostinger_model, 'acme_dns_model': acme_dns_model, 'multi_provider_model': multi_provider_model, # Storage backend models diff --git a/modules/core/settings.py b/modules/core/settings.py index 7760dfb..55d2da5 100644 --- a/modules/core/settings.py +++ b/modules/core/settings.py @@ -419,7 +419,8 @@ def migrate_dns_providers_to_multi_account(self, settings): 'he-ddns': ['username', 'password'], 'arvancloud': ['api_key'], 'infomaniak': ['api_token'], - 'acme-dns': ['api_url', 'username', 'password', 'subdomain'] + 'acme-dns': ['api_url', 'username', 'password', 'subdomain'], + 'hostinger': ['api_token'] } # Check if migration is needed diff --git a/requirements-extended.txt b/requirements-extended.txt index fce93c7..bec61d1 100644 --- a/requirements-extended.txt +++ b/requirements-extended.txt @@ -17,6 +17,9 @@ certbot-dns-namecheap==2.11.0 certbot-dns-porkbun==2.11.0 certbot-dns-godaddy==2.11.0 +# Web hosting providers +certbot-dns-hostinger + # Specialized DNS services certbot-dns-dnsmadeeasy==2.11.0 certbot-dns-nsone==2.11.0 diff --git a/templates/help.html b/templates/help.html index c454ea3..8d5fcaa 100644 --- a/templates/help.html +++ b/templates/help.html @@ -406,6 +406,10 @@