Custom domains
Every Pyvolt app comes with a platform subdomain (e.g. mysite.preview.pyvolt.com) that works out of the box. To serve your app on your own domain - acme.com, app.acme.com, anything - you attach it from the Domains tab.
The platform subdomain never goes away. It stays as your fallback URL for status pages, deploy logs, and health checks, regardless of how many custom domains you attach.
Attaching a domain
-
Open the app in Pyvolt → Domains tab → Add domain.
-
Enter the domain you want to attach. Examples:
acme.com,app.acme.com,staging.acme.com. -
If you entered an apex like
acme.com, you'll see a checkbox:
☑ Also serve www.acme.com (redirect to acme.com)
Leave it checked unless you have a specific reason to want www to fail or to point somewhere else. Pyvolt handles the redirect automatically and includes www in the SSL cert.
- Pyvolt shows you the DNS records to add. The shape depends on what you entered:
Apex (acme.com):
| Record | Name | Value | Required? |
|---|---|---|---|
| A | @ |
<your server IP> |
Yes - for acme.com |
| A | * |
<your server IP> |
Recommended - catches www and any future subdomain |
Subdomain (app.acme.com):
| Record | Name | Value |
|---|---|---|
| A (or CNAME) | app |
<your server IP> |
The wildcard * record is the time-saver: once you've added it, attaching staging.acme.com or any other subdomain later needs zero DNS work - you just hit Add domain in Pyvolt and verify. Most DNS providers (Cloudflare, Route 53, Namecheap, Porkbun) accept it.
The server IP is shown right there on the page - it's whatever your Pyvolt server provisioned to.
-
Go to your DNS provider and add the records. TTL doesn't matter for the attach - set it short (300s) while you're testing, raise it once the cert is live.
-
Back in Pyvolt, click Verify & issue certificate.
-
Pyvolt does the rest:
- Checks the domain (and
www.companion if enabled) resolves to your server's IP. - Adds the domains to your app's nginx vhost - with a 301 redirect from www to apex when applicable.
- Runs
certbot --nginxto fetch a Let's Encrypt cert via HTTP-01 challenge, covering all attached names in one SAN cert. - Installs the cert, reloads nginx.
Typical end-to-end: 10-30 seconds once DNS has propagated.
- The domain shows Live with a green badge. The cert expiry date is on the row; auto-renewal handles the next 90 days transparently.
Setting a primary domain
When you attach acme.com, Pyvolt keeps your platform subdomain as primary by default - that way nothing breaks while you're testing. When you're ready:
- Domains tab → row for
acme.com→ Make primary. - All other domains now
301 Moved Permanentlyredirect toacme.comby default.
The primary domain drives canonical URL generation: OG tags, SEO <link rel="canonical">, email links, and the preview URL shown elsewhere in Pyvolt. Pick the one you want indexed.
(Don't want non-primary domains to redirect? Toggle Always serve, don't redirect on the per-domain row. Useful for keeping www.acme.com and acme.com both reachable as-is.)
Removing a domain
Domains tab → row → Remove.
- The cert is left on disk at
/etc/letsencrypt/live/<domain>/(so you can re-attach without re-issuing if you re-add within the cert's lifetime). - The domain is removed from the nginx vhost on the next nginx reload (immediate).
- DNS still points at your server - you should remove the A/CNAME record yourself once you're done.
You can't remove the platform subdomain. It's tied to the app for life.
What can go wrong
"DNS doesn't resolve to your server yet"
The most common one. Two causes:
- Not propagated yet. Even with a 300s TTL, propagation can take a few minutes the first time. Wait 5 minutes and click verify again.
- Wrong record. Check at your DNS provider that the A or CNAME points at the IP shown in Pyvolt - not some old IP from a previous host, not a Cloudflare proxy address.
Pyvolt uses your server's actual public IP. If you're behind Cloudflare's orange-cloud proxy, turn it off (DNS-only mode) for the verification step. You can turn it back on after the cert is issued - but Cloudflare in proxy mode terminates SSL itself, so Pyvolt's cert won't be the one your visitors see. Most customers either pick Cloudflare end-to-end or Pyvolt-only.
"Let's Encrypt rate limited"
Let's Encrypt limits failures to 5/hour per hostname and successful issuances to 50/week per registered domain. You'll see a cooldown timer; the retry button reactivates when it expires.
If you're testing repeatedly, use the Staging certificate toggle on the attach form - it issues from Let's Encrypt's staging environment, which is rate-limit-free but produces a cert your browser won't trust. Switch to production once the flow works.
"Certbot timed out"
Port 80 needs to be reachable from Let's Encrypt's IPs during the challenge. If you've got a firewall rule blocking inbound 80, the challenge fails. Pyvolt provisions UFW with port 80 open by default, so this only bites if you've tightened the firewall yourself.
Check Server → Firewall to confirm 80 is open. If it isn't, add the rule and retry.
"Cert renewal failed"
Auto-renewal runs daily via certbot's systemd timer. If a renewal fails (DNS changed, port 80 blocked, Let's Encrypt outage), you'll get a notification 7 days before expiry, then again at 3 days. Fix the underlying cause and the next daily run will retry.
You can force a renewal attempt from the Domains tab → row → Renew now at any time.
How auto-renewal works
Certbot drops a systemd timer (certbot.timer) at provision time. It runs twice daily, finds certs nearing expiry (≤30 days), and renews them via the same HTTP-01 challenge that issued them originally. nginx reloads after each renewal.
No action required from you. The cert state shown in Pyvolt is fetched live over SSH on every page load, so the Live badge and expiry date are always current.
What Pyvolt does not do
- We don't proxy your traffic. Your custom domain DNS points at your server directly. Bandwidth, latency, request shaping - all your server, no Pyvolt hop.
- We don't hold your certs. They live at
/etc/letsencrypt/live/<domain>/on your server, owned by root. Pyvolt's UI reads metadata over SSH; the private key never leaves your box. - We don't manage your DNS. You bring the domain, you configure it at your DNS provider. We tell you what record to add but never touch your DNS settings.
If you want Pyvolt to terminate SSL at our edge, proxy your traffic, add a WAF - that's a CDN add-on we don't ship yet. File an issue if it'd help you.
View this page as markdown - handy as context for your AI tools. Full index at /llms.txt.