Guides

Custom domains & DNS

Astrodock gives every app its own web address under one base domain. With a single wildcard DNS record and the right TLS mode, your dashboard and every app you deploy get a real, HTTPS-secured URL — no per-app setup.

How subdomains map to apps

You pick one base domain in .env with ASTRODOCK_BASE_DOMAIN (for example apps.example.com). Everything lives under it as a subdomain:

Caddy, the built-in reverse proxy, looks at the hostname of each incoming request and routes it to the matching app. You don't configure this per app — deploying an app registers its route automatically.

Point your own domain at Astrodock

The whole platform needs just one DNS record: a wildcard that sends the base domain and everything beneath it to your server.

  1. Find your server's public IP

    It's the IP your host is reachable at from the internet. Your VPS provider shows it in their dashboard.

  2. Add one wildcard A record

    In your DNS provider, create:

    *.apps.example.com   A   <your server's IP>

    That single * record covers admin.apps.example.com and every app subdomain you'll ever create. You never have to touch DNS again when you add an app.

  3. (IPv6, optional)

    If your server has a public IPv6 address, add a matching wildcard AAAA record pointing at it too.

The wildcard is the whole trick

Because *.apps.example.com matches any name under apps.example.com, a brand-new app's subdomain resolves the moment you deploy it — no DNS change, no waiting.

Let Astrodock create the record for you

If your DNS is hosted at DigitalOcean or Cloudflare, the setup wizard can add the wildcard record itself — choose "or let Astrodock create it" on the domain step and paste an API token. It finds the zone your domain belongs to, creates the record, and re-checks DNS.

The token is used once and never stored. Astrodock has no ongoing need for DNS write access, and keeping a token that can repoint your entire domain would be a bigger prize than anything else on the box. Create one scoped as narrowly as your provider allows, and revoke it afterwards if you like.

Adding the record by hand, per registrar

Every provider words this differently, and the two things people get wrong are always the same: whether the Name field wants the full hostname or just the part in front of your domain, and whether proxying/forwarding has to be off.

Assuming your domain is example.com and you want apps under apps.example.com:

ProviderWhat to enterWatch out for
Cloudflare Type A, Name *.apps, IPv4 address <your IP> Turn the proxy off (grey cloud, not orange). Proxied records terminate TLS at Cloudflare, so Astrodock can never complete the certificate challenge for its own domain.
DigitalOcean Networking → Domains → Type A, Hostname *.apps, Will direct to <your IP> Your registrar's nameservers must point at DigitalOcean first, or this zone is ignored.
Namecheap Advanced DNS → Add New Record → A Record, Host *.apps, Value <your IP> Make sure the domain is on Namecheap BasicDNS, not "Custom DNS" or their web forwarding, which silently ignores A records.
GoDaddy DNS → Add → Type A, Name *.apps, Value <your IP> GoDaddy accepts wildcards but hides them behind "Add More Records". Remove any parked/ forwarding record for the same name first.
AWS Route 53 Hosted zone → Create record → Record name *.apps, Type A, Value <your IP> Route 53 shows the full name as *.apps.example.com — that's the same thing, not a duplicate prefix.
Google Domains / Squarespace DNS → Custom records → Host *.apps, Type A, Data <your IP> Turn off any "forwarding" for the domain, which overrides DNS records.

Using the bare domain (apps at <name>.example.com) instead of a subdomain? Then the Name/Host field is just *.

To check it took effect, from any machine:

dig +short admin.apps.example.com
# should print your server's IP

The admin subdomain

By default the dashboard is at admin.<base-domain>. If admin clashes with something, change it with ASTRODOCK_ADMIN_SUBDOMAIN in .env (for example console would put the dashboard at console.apps.example.com). It's still covered by the same wildcard record — just don't give one of your apps the same subdomain.

Choosing a TLS mode

How Astrodock handles HTTPS is set by ASTRODOCK_TLS_MODE. There are three modes, for three situations.

TLS_MODEUse it when…What happens
autoYou're on a public server with a real domainCaddy fetches free Let's Encrypt certificates and renews them for you. Needs a public domain + the wildcard DNS above.
internalYou're on a LAN or have no public DNSCaddy issues certificates from its own private CA. Traffic is encrypted, but browsers warn until you trust that CA.
offQuick local testing, or you sit behind another proxy that already does HTTPSPlain HTTP, no certificates. Simplest, but never expose it raw to the internet.

Which one is right?

Public box with a domain → auto. Trying it on your laptop → off with ASTRODOCK_BASE_DOMAIN=localhost. Internal server with no public name → internal.

Set the ACME email for auto mode

When ASTRODOCK_TLS_MODE=auto, set ASTRODOCK_ACME_EMAIL to a real address. Let's Encrypt uses it to send expiry and policy notices (Caddy renews automatically, so these are rare, but they should reach someone).

ASTRODOCK_TLS_MODE=auto
ASTRODOCK_ACME_EMAIL=you@example.com

Running locally with no DNS at all

For local development you don't need any DNS records or hosts-file edits. Set the base domain to localhost:

ASTRODOCK_BASE_DOMAIN=localhost
ASTRODOCK_TLS_MODE=off

Browsers automatically resolve any *.localhost name to your own machine, so admin.localhost and notes.localhost just work. See Install & run for the full local walkthrough.

Open ports 80 and 443

For a public install, the host must accept inbound traffic on:

Open both in your firewall and/or cloud security group. Those are the only two ports that need to be public — everything else (the database, object store, runner) stays on the internal Docker network.

Blocked port 80 breaks auto certificates

If port 80 is closed, Let's Encrypt can't verify your domain and certificate issuance fails. Open it even though your real traffic is on 443.

Verify it works

  1. Check DNS resolves

    From any machine, confirm a subdomain points at your server:

    dig +short admin.apps.example.com
    # should print your server's IP
  2. Open the dashboard

    Visit https://admin.apps.example.com. The first visit in auto mode may take a few seconds while Caddy fetches the certificate.

  3. Watch certificates being issued

    If something looks off, tail the proxy logs:

    docker compose logs -f caddy

    You'll see Caddy obtaining and storing certificates per hostname.

Troubleshooting certificates

SymptomLikely cause & fix
Certificate errors or the dashboard won't load in auto modeDNS hasn't propagated. New or changed records can take minutes to hours. Confirm with dig +short admin.<base-domain> until it returns your IP, then retry.
Caddy logs show the ACME challenge timing outPorts blocked. Port 80 (and 443) must be reachable from the internet. Check your firewall / security group.
Browser warns "not secure" on a LAN installExpected with internal mode — that's Caddy's private CA. Trust the CA on your machine, or use auto with a public domain.
You sit behind another reverse proxy or load balancer that already terminates HTTPSUse ASTRODOCK_TLS_MODE=off so Astrodock serves plain HTTP internally and lets the upstream proxy handle TLS. Don't run two layers of certificate management against the same hostnames.

Per-app custom domains are a future item

Today every app lives as a subdomain of your one base domain. Giving a single app a completely separate domain (one that isn't a subdomain of ASTRODOCK_BASE_DOMAIN) is an advanced, planned feature — not yet supported out of the box.

Related