Fixing Ghost SSL Certificate Issues on YunoHost: A Complete Guide
If you've just installed Ghost on YunoHost and are facing SSL certificate errors, HSTS issues or 502 Bad Gateway messages, you're not alone. This is a common issue that stems from how YunoHost handles SSL certificates and Single Sign-On (SSO) protection. Here's how to fix it properly.
Understanding the Problem
What's Actually Happening?
When you install Ghost on YunoHost, several things need to work together:
Ghost runs as a Node.js application on a local port (typically 26561)
Nginx acts as a reverse proxy, routing web traffic to Ghost
SSOwat (YunoHost's SSO system) protects your apps with authentication
SSL certificates encrypt the connection between visitors and your server
The problem arises because:
Port forwarding issues: YunoHost's default Let's Encrypt method uses HTTP-01 challenge, which requires port 80 to be accessible from the internet. Many home networks or ISPs block this, causing certificate installation to fail.
SSO interference: YunoHost's SSOwat redirects all traffic to the admin login page by default, preventing Ghost from being accessible.
Certificate caching: Even after fixing the certificate, browsers and nginx might serve cached, self-signed certificates.
Why You See These Errors
502 Bad Gateway: This means nginx can't reach Ghost, usually because SSOwat is blocking access or Ghost crashed during startup.
ERR_CERT_AUTHORITY_INVALID: Your browser sees YunoHost's self-signed certificate instead of a trusted Let's Encrypt certificate.
The Solution: DNS Validation
Instead of relying on HTTP-01 validation (which requires open ports), we'll use DNS-01 validation. This method proves domain ownership by adding a TXT record to your DNS, completely bypassing port forwarding issues.
Why This Works Better
No port forwarding required: Works even if port 80/443 are blocked
More reliable: DNS validation rarely fails
Same certificate quality: You get the same trusted Let's Encrypt certificates
Works for subdomains: Perfect for apps installed on subdomains like ghost.yourdomain.com
Step-by-Step Solution
Prerequisites
Before starting, make sure you have:
SSH access to your YunoHost server
Access to your domain's DNS settings
Ghost installed on YunoHost (even if it's not working yet)
Step 1: Request Certificate via DNS Challenge
SSH into your server and run:
Replace ghost.yourdomain.com with your actual Ghost subdomain.
What happens: Certbot will generate a unique validation string and ask you to add it as a DNS TXT record.
Step 2: Add DNS TXT Record
You'll see instructions like:
Log into your DNS provider (Cloudflare, Namecheap, etc.) and add:
Type: TXT
Name:
_acme-challenge.ghost(or_acme-challenge.ghost.yourdomain.comdepending on your provider)Value: The string certbot provided
TTL: 300 (5 minutes) or Auto
Important: Don't press Enter in certbot yet!
Step 3: Verify DNS Propagation
DNS changes take time to spread across the internet. Verify your record is live:
Look for your validation string in the output. If you don't see it, wait 2-5 minutes and try again.
Why this matters: If you continue before DNS propagates, certbot will fail validation and you'll have to start over.
Step 4: Complete Certificate Issuance
Once you see your TXT record, go back to the certbot terminal and press Enter. Certbot will:
Verify the DNS record
Request the certificate from Let's Encrypt
Save the certificate to
/etc/letsencrypt/live/ghost.yourdomain.com/
You should see: "Successfully received certificate"
Step 5: Install Certificate in YunoHost
YunoHost stores certificates in its own directory structure. Copy your new Let's Encrypt certificate there:
What this does:
Copies the full certificate chain (needed for browsers to trust it)
Copies the private key
Sets correct ownership (nginx needs to read these)
Sets secure permissions (only root and ssl-cert group can access)
Step 6: Configure SSOwat to Allow Public Access
Ghost is a public blog platform, so it shouldn't be behind YunoHost's login page:
What this does:
Marks Ghost's root path (/) as "unprotected"
Regenerates SSOwat configuration to apply changes
Allows visitors to access Ghost without YunoHost login
Note: The Ghost admin panel (ghost.yourdomain.com/ghost) still has its own secure login.
Step 7: Force Nginx to Use New Certificate
Sometimes nginx caches SSL sessions. Force a complete reload:
Why stop/start instead of reload: This ensures nginx completely releases the old certificate from memory.
Step 8: Verify and Access
Check that the new certificate is being served:
You should see: issuer=C = US, O = Let's Encrypt, CN = E7
If you still see issuer=CN = yunohost.org, nginx hasn't fully reloaded. Try:
Step 9: Clear Browser Cache
Your browser might have cached the old certificate:
Clear cache: Press Ctrl+Shift+Delete, select "Cached images and files"
Or use incognito mode: Open a private/incognito window
Or use mobile data: Access from your phone (not on WiFi)
Visit https://ghost.yourdomain.com - you should see Ghost with a valid SSL certificate! 🎉
Troubleshooting Common Issues
Ghost Shows 502 Bad Gateway
Check if Ghost is actually running:
If it's stopped or failed, restart it:
View recent logs to see what went wrong:
Still Getting Certificate Warnings
Verify what certificate is actually being served:
If it shows "yunohost.org" instead of "Let's Encrypt":
Double-check you copied the certificates correctly
Restart nginx:
sudo systemctl restart nginxClear your browser's SSL cache completely
DNS Record Not Propagating
Some DNS providers are slower than others. If dig doesn't show your TXT record after 10 minutes:
Check you added it to the correct domain
Verify the record name format (some providers want just
_acme-challenge.ghost, others want the full_acme-challenge.ghost.yourdomain.com)Try using your provider's DNS checker tool
Certificate Expires in 90 Days
Let's Encrypt certificates are valid for 90 days. To renew:
You'll need to update the DNS TXT record with a new value each time. Consider setting a calendar reminder for 60 days from now.
For automatic renewal, you'd need to use your DNS provider's API with certbot plugins (more advanced setup).
Understanding the Technical Details
Why DNS Validation Works
HTTP-01 Challenge (YunoHost's default):
Let's Encrypt connects to
http://yourdomain.com/.well-known/acme-challenge/Requires port 80 accessible from internet
Fails if firewall/ISP blocks port 80
Fails if port forwarding misconfigured
DNS-01 Challenge (our solution):
Let's Encrypt queries DNS for TXT record
No ports needed
Works from anywhere
Only requires DNS control
How SSOwat Works
SSOwat is YunoHost's Single Sign-On system that:
Intercepts all HTTP requests via Lua scripts in nginx
Checks if the user is authenticated
Redirects to login page if not
Allows access if the URI is marked "unprotected"
For Ghost, we need the entire site unprotected because:
Blog content should be publicly accessible
Ghost has its own admin authentication
Readers shouldn't need a YunoHost account
The nginx Proxy Chain
When someone visits your Ghost blog:
Browser connects to nginx (port 443)
nginx terminates SSL using the certificate
SSOwat Lua script checks authentication
Request passes to Ghost (port 26561)
Ghost generates the page
Response travels back through nginx to browser
If any step fails, you get errors.
Applying This to Other YunoHost Apps
This same approach works for any YunoHost app with certificate issues:
For n8n:
For Nextcloud:
The key steps remain the same:
Request certificate with DNS validation
Copy to YunoHost cert directory
Configure app visibility (unprotected if needed)
Reload nginx
Best Practices
Security Considerations
Keep certificates renewed: Set calendar reminders
Secure your DNS account: Use 2FA on your DNS provider
Monitor expiration: Check certificate status monthly
Backup your config: Save your nginx and YunoHost configs
When to Use This Method
Use DNS validation when:
Port forwarding is complex or unavailable
Behind CGNAT (Carrier-Grade NAT)
ISP blocks ports 80/443
Using IPv6 without proper forwarding
Want more reliable certificate issuance
Use HTTP validation when:
Ports 80/443 are reliably forwarded
Want automatic renewal (with certbot renewal hooks)
Have simple network setup
Conclusion
SSL certificate issues on YunoHost often stem from network configuration challenges that HTTP-01 validation can't overcome. By using DNS-01 validation, you bypass these limitations entirely while getting the same trusted Let's Encrypt certificates.
The key takeaways:
DNS validation works without open ports
SSOwat needs configuration for public apps
Nginx caching can cause confusion
The same method works for any YunoHost app
Once you've done this process once, it becomes straightforward for future apps. Keep this guide handy for when you install your next YunoHost application!
Additional Resources
Have questions or run into issues not covered here? The YunoHost forum and Ghost community are great places to get help. Include your error messages and what you've already tried for the best assistance.


