Skip to content

SSL / TLS Guide ​

AidiPanel uses Let's Encrypt (via Certbot) for free SSL certificates with automatic renewal.


Quick Start ​

bash
# Install SSL for a domain
aidipanel ssl:install --domain example.com --email admin@example.com

# Check SSL status
aidipanel ssl:status

# Renew all certificates
aidipanel ssl:renew

Prerequisites ​

Before installing SSL:

  1. Domain must point to your server — example.com A record → server IP
  2. Port 80 must be open — Let's Encrypt verifies via HTTP challenge
  3. Site must exist — aidipanel site:add --domain example.com first

Check DNS:

bash
dig +short example.com
# Should return your server's public IP

Installing a Certificate ​

Via CLI ​

bash
aidipanel ssl:install --domain example.com --email admin@example.com

This:

  1. Runs certbot --nginx -d example.com -d www.example.com
  2. Obtains Let's Encrypt certificate
  3. Updates the Nginx vhost to use the new cert
  4. Reloads Nginx
  5. Sets up auto-renewal

Via Web Panel ​

  1. Go to Sites and open the domain
  2. Open the SSL tab
  3. Enter your email
  4. Click Install Certificate

Certificate Location ​

Let's Encrypt certificates are stored in:

/etc/letsencrypt/live/example.com/
├── fullchain.pem   ← Certificate + chain (use this in Nginx)
├── privkey.pem     ← Private key
├── cert.pem        ← Certificate only
└── chain.pem       ← Intermediate chain only

Nginx config references:

nginx
ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

Auto-Renewal ​

AidiPanel configures automatic renewal via cron:

text
# /etc/cron.d/aidipanel
30 2 * * * root certbot renew --quiet --nginx >> /var/log/aidipanel-certbot.log 2>&1

Certbot renews certificates automatically when they are within 30 days of expiry.

Check renewal logs:

bash
tail -f /var/log/aidipanel-certbot.log

Test renewal manually:

bash
certbot renew --dry-run

SSL Status ​

bash
aidipanel ssl:status

Output example:

  SSL Certificates
  ────────────────────────────────────────────────────────────
  example.com       Let's Encrypt   Expires: 2025-08-12  ✓ Valid
  shop.example.com  Let's Encrypt   Expires: 2025-07-30  ✓ Valid
  old.example.com   Self-signed     Expires: 2034-01-01  ⚠ Self-signed

Self-Signed Certificate (Initial Setup) ​

Before you have a domain pointing to your server, AidiPanel uses a self-signed certificate for the panel UI itself:

/etc/ssl/aidipanel/aidipanel.crt
/etc/ssl/aidipanel/aidipanel.key

The panel uses this certificate on port 8443, and new site vhosts use it as a temporary fallback until a trusted certificate is installed. It is not intended as the final public certificate for user sites.

Your browser will show a warning for self-signed certs — this is expected. Click "Advanced" → "Proceed" to access the panel.


HTTPS Redirect and HSTS ​

New sites initially serve HTTP and use a self-signed HTTPS certificate so DNS and content can be prepared without forcing visitors through a certificate warning. After installing a trusted certificate, enable Force HTTPS from the site's SSL tab or CLI:

bash
aidipanel ssl:force-https --domain example.com --action on

The resulting HTTP redirect is:

nginx
server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://$host$request_uri;
}

HSTS is also off by default. Enable it only after HTTPS is trusted and stable:

bash
aidipanel ssl:hsts --domain example.com --action on

SSL Security Configuration ​

AidiPanel configures TLS 1.2/1.3, OCSP stapling, and common security headers. HSTS is shown below as an optional line rather than a new-site default:

nginx
ssl_protocols       TLSv1.2 TLSv1.3;
ssl_ciphers         ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:
                    ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_session_cache   shared:SSL:10m;
ssl_session_timeout 1d;
ssl_stapling        on;
ssl_stapling_verify on;

# Optional after a trusted certificate is active:
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;

TLS results depend on the active certificate, DNS, Nginx build, and any manual vhost changes. Validate public sites with a current external TLS scanner rather than relying on a fixed grade claim.


Wildcard Certificates ​

For wildcard certs (*.example.com), you need DNS challenge instead of HTTP challenge:

bash
certbot certonly \
  --manual \
  --preferred-challenges dns \
  -d example.com \
  -d "*.example.com" \
  --email admin@example.com \
  --agree-tos

Follow the prompts to add a DNS TXT record. Then update your Nginx vhost to use the new cert path.


Multiple Domains on One Certificate ​

bash
certbot --nginx \
  -d example.com \
  -d www.example.com \
  -d shop.example.com \
  --email admin@example.com

Revoking / Deleting a Certificate ​

bash
# Delete certificate for a domain
certbot delete --cert-name example.com

# List all certificates
certbot certificates

Troubleshooting ​

"Challenge failed" / Port 80 not accessible ​

bash
# Check UFW allows port 80
ufw status
ufw allow 80/tcp

# Check Nginx is running and port 80 is active
systemctl status nginx
ss -tlnp | grep :80

"Too many certificates" (Let's Encrypt rate limit) ​

Let's Encrypt allows 5 certificates per domain per week. If you hit the limit, wait a week or use --staging for testing:

bash
certbot --nginx --staging -d example.com

Certificate not renewing ​

bash
# Check certbot can access your domain
certbot renew --dry-run

# Check cron is running
systemctl status cron
cat /etc/cron.d/aidipanel

# Manual renewal
certbot renew --force-renewal --nginx

"Name or service not known" during renewal ​

Your domain's DNS is not resolving. Check DNS records and TTL.