| page_title | Domains and HTTPS |
|---|---|
| subcategory | Guides |
| description | Configure custom domains, automatic HTTPS, and URL redirects for Coolify applications. |
This guide covers how to assign a custom domain to your application, how Coolify handles TLS certificates, and how to configure redirects.
Coolify runs a reverse proxy (Traefik by default, Caddy is also supported)
on each server. When a request arrives, the proxy inspects the Host
header and routes it to the correct application container. The proxy is
managed automatically; you do not configure Traefik/Caddy directly.
Internet ──► Server IP ──► Traefik/Caddy ──► Application Container
(port 80/443) (internal port, e.g. 3000)
The ports_exposes attribute tells Coolify which port your application
listens on inside the container. The domains attribute tells the proxy
which hostname(s) should route to that container.
Set the domains attribute on any application resource:
resource "coolify_application" "web" {
name = "my-app"
project_uuid = coolify_project.main.uuid
server_uuid = data.coolify_server.prod.uuid
git_repository = "https://github.com/myorg/myapp"
git_branch = "main"
build_pack = "nixpacks"
ports_exposes = "3000"
domains = "https://app.example.com"
}Before Coolify can route traffic and issue a TLS certificate, you need a DNS record pointing your domain to the server's IP address:
| Record Type | Name | Value |
|---|---|---|
A |
app.example.com |
<server-ip> |
Propagation typically takes 1-5 minutes but can take up to 48 hours depending on your DNS provider.
Coolify uses Let's Encrypt to issue free TLS certificates automatically.
When you set domains = "https://app.example.com":
- Coolify configures the proxy to listen for the domain
- Let's Encrypt issues a certificate via the ACME HTTP-01 challenge
- The proxy serves traffic over HTTPS
- Certificates are renewed automatically before expiry
For this to work:
- The domain's DNS A record must point to the server's public IP
- Port 80 must be open (Let's Encrypt uses HTTP-01 validation)
- Port 443 must be open for HTTPS traffic
~> Use https:// in the domains value. If you write
http://app.example.com, Coolify will NOT issue a TLS certificate.
The https:// prefix signals that you want automatic HTTPS.
The is_force_https_enabled attribute (defaults to true) redirects
all HTTP requests to HTTPS:
resource "coolify_application" "web" {
# ...
domains = "https://app.example.com"
is_force_https_enabled = true # default, HTTP requests redirect to HTTPS
}Leave this enabled unless you have a specific reason to serve HTTP (for example, a health check endpoint behind a load balancer that does TLS termination).
The redirect attribute controls how Coolify handles www vs non-www
versions of your domain:
| Value | Behavior | Example |
|---|---|---|
"www" |
Redirects non-www to www | app.example.com redirects to www.app.example.com |
"non-www" |
Redirects www to non-www | www.app.example.com redirects to app.example.com |
"both" |
Serves both without redirect | Both app.example.com and www.app.example.com work |
resource "coolify_application" "web" {
# ...
domains = "https://app.example.com"
redirect = "non-www" # www.app.example.com → app.example.com
}-> Note: If you use "www" or "both", create a DNS record for
the www subdomain as well (CNAME www → app.example.com or another
A record).
Separate multiple domains with commas:
resource "coolify_application" "web" {
# ...
domains = "https://app.example.com,https://www.example.com,https://example.com"
}All domains receive TLS certificates. Requests to any of them route to the same application container.
On create, Coolify defaults autogenerate_domain to true. If you
omit domains (or leave it blank), Coolify assigns a public FQDN and
installs a Traefik/Caddy host for it:
| Server config | Generated FQDN shape |
|---|---|
| Wildcard domain set | https://{application-uuid}.{wildcard} |
| No wildcard | http://{application-uuid}.{server-ip}.sslip.io |
The provider exposes this as create-only autogenerate_domain
(default true), matching Coolify's $request->boolean('autogenerate_domain', true).
resource "coolify_application_docker_image" "public" {
# ...
# domains omitted + default autogenerate_domain = true
# -> Coolify generates sslip.io or wildcard FQDN
}Servers may also show a read-only wildcard_domain from Coolify UI/API
configuration. Prefer explicit domains = "https://..." for production
hostnames with Let's Encrypt HTTP-01.
-> Wildcard TLS (server-level wildcards) often needs DNS-01 validation. For most setups, explicit per-app domains with HTTP-01 are simpler.
Workers, queues, and sidecars that must not get a Traefik host should
disable generation and leave domains empty:
resource "coolify_application_docker_image" "worker" {
name = "background-worker"
project_uuid = coolify_project.main.uuid
server_uuid = data.coolify_server.prod.uuid
docker_image = "myorg/worker:latest"
ports_exposes = "8080"
autogenerate_domain = false
# domains omitted or domains = ""
}Without autogenerate_domain = false, Coolify still generates a public
sslip/wildcard URL even when you never set domains.
- Verify the DNS record:
dig app.example.comshould return your server's IP - Wait for DNS propagation (check with
dig @8.8.8.8 app.example.com) - Confirm ports 80 and 443 are open on the server's firewall
- Check that you used
https://in thedomainsvalue - Verify port 80 is open (Let's Encrypt HTTP-01 needs it)
- Check Coolify proxy logs: the Coolify UI shows proxy logs under the server
- Confirm the DNS record is correct and propagated
- Let's Encrypt has rate limits: 50 certificates per domain per week
If you get infinite redirect loops:
- Check if another proxy (Cloudflare, nginx) is also doing HTTPS redirect
- If behind Cloudflare, set SSL mode to "Full (strict)" not "Flexible"
- Disable
is_force_https_enabledtemporarily to isolate the issue