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:
- The dashboard sits at
admin.apps.example.com(the admin subdomain — more below). - Each app gets its own subdomain, taken from the
subdomainfield in itsapp.json. An app with"subdomain": "notes"is served atnotes.apps.example.com.
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.
-
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.
-
Add one wildcard A record
In your DNS provider, create:
*.apps.example.com A <your server's IP>That single
*record coversadmin.apps.example.comand every app subdomain you'll ever create. You never have to touch DNS again when you add an app. -
(IPv6, optional)
If your server has a public IPv6 address, add a matching wildcard
AAAArecord 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:
| Provider | What to enter | Watch 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_MODE | Use it when… | What happens |
|---|---|---|
auto | You're on a public server with a real domain | Caddy fetches free Let's Encrypt certificates and renews them for you. Needs a public domain + the wildcard DNS above. |
internal | You're on a LAN or have no public DNS | Caddy issues certificates from its own private CA. Traffic is encrypted, but browsers warn until you trust that CA. |
off | Quick local testing, or you sit behind another proxy that already does HTTPS | Plain 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:
- Port 80 (HTTP) — needed for the Let's Encrypt challenge in
automode, and to redirect visitors to HTTPS. - Port 443 (HTTPS) — where your dashboard and apps are actually served.
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
-
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 -
Open the dashboard
Visit
https://admin.apps.example.com. The first visit inautomode may take a few seconds while Caddy fetches the certificate. -
Watch certificates being issued
If something looks off, tail the proxy logs:
docker compose logs -f caddyYou'll see Caddy obtaining and storing certificates per hostname.
Troubleshooting certificates
| Symptom | Likely cause & fix |
|---|---|
Certificate errors or the dashboard won't load in auto mode | DNS 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 out | Ports blocked. Port 80 (and 443) must be reachable from the internet. Check your firewall / security group. |
| Browser warns "not secure" on a LAN install | Expected 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 HTTPS | Use 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
- First-time setup, including the wildcard step: Install & run
- Take an app live: Deploy your first app
- Get notified when an app goes down: Email notifications