Domains & TLS

Point a real domain at an app, get automatic Let's Encrypt HTTPS, and cut over from an old host with zero downtime using DNS-01.

Domains & TLS

HostSSH runs a managed proxy (Traefik) on each Node that terminates HTTPS and gets Let's Encrypt certificates for you. You never edit a proxy config or run certbot. This guide covers attaching a domain, how certificates are issued, and how to cut over from an existing host without an HTTPS gap.


1. Attach a domain to an App

When you deploy, set the domain and the port your app listens on:

$ hostssh deploy --name shop --source ./shop --domain shop.example.com --port 3000

or in the dashboard's Deploy drawer, fill Domain and Port. That's it — the Agent:

  1. ensures the managed proxy (hostssh-proxy) is running,
  2. stamps routing labels on your container (Host(shop.example.com) → :3000),
  3. and the proxy requests a certificate and starts serving HTTPS.

Point your DNS at the Node's public IP (an A record) and the site is live over HTTPS.


2. How certificates are issued

The managed proxy supports two ACME challenge types. HostSSH picks automatically:

HTTP-01 (default)

The proxy proves control of the domain by answering a challenge on port 80. This works out of the box and needs nothing but DNS already pointing at the Node and port 80 reachable.

  • Requirement: the domain's A record must resolve to this Node before the certificate can issue. If it doesn't, Let's Encrypt returns NXDOMAIN and the proxy backs off.
  • If a cert is stuck self-signed: point the DNS at the box, then run hostssh proxy up --force to clear the backoff and force a fresh challenge. The cert issues in ~10–30s. (This is guard G10; see Troubleshooting.)

DNS-01 (for zero-downtime cutovers and wildcards)

The proxy proves control by creating a temporary DNS TXT record via your DNS provider's API. This is the production path because it can issue a certificate before the domain points at the Node — so there's no HTTPS gap during a migration — and it can issue wildcard certificates (*.example.com).

Enable it by giving the proxy a scoped Cloudflare token:

  • HOSTSSH_ACME_DNS_PROVIDER=cloudflare
  • HOSTSSH_ACME_DNS_TOKEN=<a Cloudflare Zone:DNS:Edit token>

Set these in the dashboard (the token is held server-side and sealed — a cutover becomes a dashboard action, and the token never appears on a command line) or in the Agent's systemd environment. With DNS-01 configured, the proxy issues via the DNS challenge and falls back to HTTP-01 automatically if the token is missing, so nothing regresses.

Recommended production posture: put the domain behind Cloudflare (orange-cloud, proxied), set SSL mode to Full (strict), and let DNS-01 supply the trusted origin certificate. This is orange-cloud-safe and supports wildcards. For many client custom domains at scale, use Cloudflare for SaaS (edge certs per client via CNAME).


3. Zero-downtime cutover from an old host

The whole point of DNS-01 is that you can prepare the new box completely before flipping any traffic. The safe sequence:

  1. Deploy the App to the HostSSH Node with its real domain and env, while DNS still points at your old host. It's running and gated, just not receiving public traffic yet.
  2. Pre-issue the certificate via DNS-01 while DNS still points away. Verify it's real and trusted without changing DNS:
    $ curl --resolve shop.example.com:443:<node-ip> https://shop.example.com -I
    HTTP/2 200
    
    The --resolve flag makes curl talk to the new Node as if DNS already pointed there.
  3. Cut over the DNS — change the A record to the Node's IP (TTL 300). Because the cert is already issued, HTTPS works from the first request. HostSSH also lights up an uptime monitor for the domain automatically.
  4. Watch, then decommission. Keep the old host running (stopped, not deleted) for a soak window so rollback is instant — just flip the A record back. Once you're confident, remove the old app.

The dashboard's cutover action does the DNS flip for you (when you've connected a Cloudflare token), records the previous record for rollback, and health-checks the domain after the flip — rolling DNS back automatically if the new target fails its check.


4. Multiple domains and subdomains

  • www + apex: deploy with the apex domain, then add the www host as an additional route (or a CNAME to the apex). Both get certificates.
  • App subdomains / multi-tenant: HostSSH supports wildcard routing for multi-tenant apps (*.yourapp.com) — the DNS-01 wildcard cert covers every tenant subdomain. See your app's tenant settings.
  • Public expose (quick tunnels): to expose a port publicly without a full DNS setup — for a demo or an internal tool — use the Expose feature, which provisions a Cloudflare tunnel and a *.apps.hostssh.com hostname. See the Access page in the dashboard.

5. Managing the proxy directly

On the box, a few commands help when debugging:

CommandWhat it does
hostssh proxy statusIs the managed proxy running?
hostssh proxy upEnsure the proxy is running (idempotent).
hostssh proxy up --forceRecreate the proxy — clears a stuck ACME backoff.
hostssh proxy downStop the managed proxy.

Issued certificates persist in a Docker volume (hostssh-acme), so restarting or recreating the proxy never loses them, and that volume is included in backups.


6. Common questions

Do I need to open ports? The managed proxy needs 80 and 443 reachable. HTTP-01 needs 80; DNS-01 doesn't, but 80/443 still serve traffic. The Agent's firewall opens these by default.

My cert is self-signed / browser warns. DNS isn't pointing at the box yet (HTTP-01 can't validate), or the token is missing (DNS-01 can't run). Fix DNS or add the token, then hostssh proxy up --force. See Troubleshooting.

Can I bring my own certificate? The managed proxy is built around automatic Let's Encrypt. For a custom cert, terminate TLS at Cloudflare (Full strict) with a HostSSH origin cert, which is the recommended posture anyway.

Renewals? Automatic. The proxy renews before expiry. HostSSH also auto-creates TLS-expiry monitors so a silent renewal failure surfaces as an alert rather than an outage.


Next steps