# Domains
URL: https://synquic.tech/docs/dashboard/domains.md

The Domains & SSL page lists every domain across your projects with its route, live DNS check, certificate state and renewal, and adds new domains with a three-step wizard.

import { Step, Steps } from 'fumadocs-ui/components/steps';

The **Domains** page is the one place to see every web address your server answers on. Each project also
has its own **Domains & Routes** tab (see [Custom domains](/docs/guides/custom-domains)); this page shows the
same domains for all projects at once, checks their DNS live, and tells you which certificates are healthy,
which are about to renew and which need you.

<Callout title="Where this lives">
Open **Domains** in the **Infrastructure** section of the sidebar, or go to **`/domains`**. The page header
reads **Domains & SSL** with the subtitle "Every domain across your projects, with its DNS and HTTPS status in
one place." It has two tabs: **Domains** (`/domains`) and **Certificates** (`/domains?tab=certificates`).
**Settings → Certificates** links to the second tab.
</Callout>

You see the domains of every project you have access to. Adding, verifying and renewing needs write access to
the project; removing a domain needs admin access to it (see [Permissions](/docs/security/permissions)).

## The Domains tab

### Summary tiles

Four tiles sit at the top. Each one is also a filter: click it to show only those rows, click it again to show
everything.

| Tile | What it counts |
| --- | --- |
| **Domains** | Every domain row. |
| **HTTPS active** | Domains serving a valid certificate, plus domains whose HTTPS is handled by your own proxy or CDN. |
| **Need attention** | Domains with a failed or expired certificate, domains that are not verified or have no certificate yet, and certificates in their last 7 days that should already have renewed. A domain waiting for its first deploy is not counted. |
| **Renewal due** | Certificates that Synq renews itself and that have fewer than 14 days left. |

### Search and filters

Under the tiles:

- **Search domains, projects or services** matches the hostname, the project name or slug, and the service name.
- The **Project** picker narrows the list to one project (**All projects** by default).
- The **Status** picker offers **All statuses**, **Needs attention**, **HTTPS active**, **Issuing**,
  **Failed or expired**, **Expiring soon** and **No certificate**.
- When any certificates are due, a **Renew \{n\} due** button appears. It renews every due certificate in one go
  and reports "Renewed X of Y certificates.", followed by the reason for each one that failed.

**Clear filters** resets all three when nothing matches. The refresh button at the top right reloads the list.

Rows are sorted with problems first, then by project and hostname, with each project's primary domain first.

### The table

On a wide screen the list is a table; on a phone each domain is a card with the same fields.

| Column | What it shows |
| --- | --- |
| **Domain** | The hostname (a link to the site), a **Primary** badge for the project's main address, and a **Custom** or **Free subdomain** tag. Underneath is the **internal target**: where the edge forwards the traffic inside the project, for example `https://app.example.com -> http://web:3000`. A static site shows the folder it serves instead, for example `https://docs.example.com -> /`. |
| **Project** | The project (a link to its Domains & Routes tab) and, under it, the service that receives the traffic, or **Main app** for a single-app project. |
| **DNS** | The result of a live DNS lookup (below) and the address the record should point at, for example **Expects 203.0.113.10**. |
| **HTTPS certificate** | The certificate state, who issued it, and the expiry countdown. |
| **HTTP to HTTPS** | Whether plain `http://` requests are redirected: **On**, **After certificate** or **Upstream**. See [HTTPS redirect](/docs/guides/https-certificates#https-redirect). |

If the last verification or certificate attempt failed, a red line under the domain gives the reason in plain
words, for example "Last attempt 5 minutes ago: ...".

#### What the internal target means

The internal target is the address the edge proxies to on the project's private network:

- a service route goes to the service's network alias (its name, or the custom alias set on the service) and
  the container port you chose, for example `http://api:8080`;
- a single-app route goes to the project's own alias (its slug) and port;
- an app running directly on the host (not in Docker) goes to `127.0.0.1` and its port.

If the port shown is not the one your app listens on, visitors get a `502`. Fix it from the project's
**Domains & Routes** tab with **Edit domains** or **Edit route**.

#### Live DNS check

When the page opens, Synq looks up every custom domain in public DNS (a few at a time) and compares the answer
with the record it expects. You can re-run it for one domain with **Check DNS** in the row menu.

| Result | Meaning |
| --- | --- |
| **Points here** | The `A` record answers with this server's IP. |
| **Points elsewhere** | The name resolves, but to another address. This is expected when a CDN proxy (for example Cloudflare's orange cloud) sits in front: the CDN's address is what DNS returns. |
| **No record yet** | Nothing answers for the name. Add the record at your DNS provider. |
| **Resolves** | The name resolves, but Synq doesn't know this server's public IP, so compare the address yourself. |
| **External** | The domain uses **External ingress & TLS**; your own proxy owns DNS, so there is nothing to check. |
| **Checking…** / **Not checked** | The lookup is running, or hasn't run yet. |

The lookup asks Google's public DNS-over-HTTPS resolver first, so it usually sees what the rest of the internet
sees, not a cached answer on your laptop. If Google can't be reached it falls back to the server's own resolver,
and a lookup that fails or times out also shows **No record yet**, so run **Check DNS** again before acting on
it. It is only advice: on a Synq server, verification is decided by whether a
certificate can be issued, not by this lookup.

#### Certificate states

| State | Meaning |
| --- | --- |
| **Active** | A valid certificate is served. The issuer is shown next to it: **Let's Encrypt**, **ZeroSSL**, or **Uploaded** for a certificate you installed yourself. |
| **Issuing** | A certificate order is in progress. |
| **Failed** | The last issuance or check failed and nothing valid is served. The red line under the domain says why. |
| **Expired** | The certificate on record is past its expiry date. |
| **Not issued** | No certificate yet, usually because DNS doesn't point here yet or the project has never deployed. |
| **Handled upstream** | TLS ends at your own proxy or CDN (**Your proxy or CDN**), so there is no certificate on this server. |

The countdown turns amber inside the 14-day renewal window and red in the last 7 days.

### Row actions

Open the **⋯** menu (**Domain actions**) at the end of a row. Only the actions that make sense for that domain
are listed:

| Action | What it does |
| --- | --- |
| **Open site** | Opens `https://<hostname>` in a new tab. Not shown for a wildcard. |
| **Check DNS** | Runs the live DNS lookup again and shows the result in a toast. |
| **Verify and issue certificate** / **Issue certificate** | Requests a certificate and streams certbot's log live in a dialog. The first label is used for a domain that isn't verified yet. See [Issue a certificate](/docs/guides/https-certificates#issue-a-certificate). |
| **Renew certificate** | Forces a renewal of an active certificate that Synq manages. |
| **Recheck certificate** | Reads the certificate on the server without requesting a new one, and updates the state. Useful after a manual fix. |
| **Upload certificate** | Installs your own certificate and key. See [Upload your own certificate](/docs/guides/https-certificates#upload-your-own-certificate). |
| **Set as primary** | Makes this the project's main address (the one the project card and **Visit** link use). |
| **Custom config** | Opens the per-domain OpenResty config editor. See [Custom proxy config](/docs/guides/custom-proxy-config). |
| **Manage in project** | Opens the project's **Domains & Routes** tab. |
| **Remove domain** | Asks "Remove \{hostname\}?", then removes the route and its certificate from the edge. The app keeps running and stays reachable on its other domains. |

A spinner replaces the menu while an action runs on that row.

## Add a domain with the wizard

**Add domain** (top right, and on the empty page) opens a three-step wizard: **Route**, **DNS**, **HTTPS**.
It saves the domain exactly as the project's own Domains & Routes tab would, so you can use either.

<Steps>

<Step>

### Route

- **Project**: choose the project. If you opened the wizard with the project filter set, that project is
  preselected. With no projects yet, the wizard says "Create a project first, then connect a domain to it."
- **Send traffic to**: shown when the project has more than one target. Pick **Main app** or one of the
  project's services.
- **Container port**: the port your app listens on inside the container, prefilled from the project or
  service. A static site has no port; the wizard notes "Static site: the domain serves the project's built
  files."
- **My domain** / **Free subdomain**: type a hostname such as `app.example.com`, or, when your install has a
  base domain, pick **Free subdomain** and type just the label (`my-app` becomes `my-app.<base>`). See
  [Free subdomains](/docs/guides/custom-domains#free-subdomains).

Press **Continue**.

</Step>

<Step>

### DNS

The wizard shows **Create this DNS record**: an `A` record for the hostname pointing at **Your server's IP**,
with a copy button. Add it at your DNS provider (your registrar, Cloudflare, Route 53 and so on). With
Cloudflare, keep the proxy off (**DNS only**) until the certificate is issued.

Press **Check DNS** to look the name up. The answer is one of:

- "DNS is ready: app.example.com points at 203.0.113.10."
- "No record found for app.example.com yet. Add it, then check again."
- "app.example.com resolves to ..., not 203.0.113.10." Update the record, or make sure a CDN in front forwards
  HTTP on port 80.

It also warns about two things that break Let's Encrypt even when the `A` record is right: an `AAAA` (IPv6)
record pointing somewhere else (Let's Encrypt tries IPv6 first), and extra `A` records for other servers.

For a free subdomain the wizard reminds you that the wildcard record `*.<base>` already covers it.

You can press **Add domain** even if DNS isn't ready: "You can add the domain now. The certificate is issued
once DNS points here, and you can retry it from the Domains list."

</Step>

<Step>

### HTTPS

The wizard saves the route and then, depending on the project:

- **Project not deployed yet** (checked first): it stops with "\{hostname\} was added. Its certificate is
  issued after the project is deployed."
- **First domain of the project**: it first runs **Set up routing on the server**, which installs the edge on
  ports 80 and 443 if needed, with a live log.
- **No DNS record found**: it stops with the DNS record and the fixes list, and offers **Issue certificate**
  (try again now) or **Finish without HTTPS**. It pauses only when the live check found no record: a record
  that points elsewhere still goes ahead with issuance, which then fails with the reason in the log.
- Otherwise it requests the certificate right away and streams certbot's log. Let's Encrypt fetches a
  challenge from `http://<hostname>` on port 80, then the certificate is installed.

On success you see "HTTPS is live at https://app.example.com." and an **Open site** button. If it fails, the
log ends with the reason, and a checklist names the usual causes: the `A` record, port 80 in the firewall and
cloud security group, a stray `AAAA` record, and a CDN proxy that doesn't forward port 80.

</Step>

</Steps>

<Callout title="What the wizard doesn't set" type="info">
The wizard adds one hostname with Let's Encrypt over HTTP. For **Include www**, **External ingress & TLS**
(Cloudflare Tunnel or your own proxy) or **Use DNS-01 challenge**, add the domain from the project's
**Domains & Routes** tab instead. A wildcard hostname such as `*.example.com` typed into the wizard always
uses DNS-01, which needs a connected DNS provider.
</Callout>

## The Certificates tab

The **Certificates** tab (`/domains?tab=certificates`) is about the certificates themselves.

### How HTTPS works here

A short explainer card states the rules this server follows: every custom domain gets a free Let's Encrypt
certificate without Cloudflare or a DNS provider account; Synq proves control with an HTTP-01 challenge, so the
domain needs an `A` record pointing here and port 80 open; wildcard certificates use DNS-01, which needs a
connected DNS provider. It also says whether a DNS provider is connected, with a **Manage DNS providers** link
to **Settings → Credentials**.

### Certificate list

One row per certificate that was issued or installed on this server (domains handled by your own proxy are
left out). Each row shows the domain and the name the certificate covers, the state and issuer, the expiry, **Auto-renew** and
**Last check**:

| Auto-renew | Meaning |
| --- | --- |
| **On** | The renewal job renews it. |
| **Job off** | Synq could renew it, but the renewal job is turned off. |
| **Manual** | An uploaded certificate. Upload a new one before it expires. |

The row buttons are **Renew certificate** (or **Issue certificate** when it isn't active), **Upload
certificate** for manual ones, and a recheck button.

### Automatic renewal

The **Automatic renewal** card reports the **SSL certificate renewal** job: "Certificates renew automatically
when fewer than 14 days remain.", the next run, and the result of the last run. **Open renewal job** goes to
the job at `/jobs/ssl:renew`, where you can see its history, run it now or change its schedule. By default it
runs once a day at 03:17 server time.

If the job is off, the card warns: "The renewal job is turned off. Certificates will expire unless you renew
them by hand."

### Certificate authority

The **Certificate authority** card shows what certbot uses when it requests certificates: **Provider**
(Let's Encrypt, Let's Encrypt staging, ZeroSSL or a custom ACME server), **Directory URL**, **Contact email**,
**Staging mode**, **External account binding**, **Key type** and **Custom trust root**.

Only the contact email can be changed here, and only by an instance administrator: press **Change**, enter an
address and **Save**. It overrides `SYNQ_ACME_EMAIL` for new registrations and renewals; **Use the environment
value** removes the override. The certificate authority sends expiry notices to this address.

Everything else comes from environment variables on the server. See
[Certificate authority settings](/docs/guides/https-certificates#certificate-authority-settings).

## Related

<Cards>
  <Card title="Custom domains" href="/docs/guides/custom-domains" description="Add a domain from the project's Domains & Routes tab, with www, redirects and external ingress." />
  <Card title="HTTPS and certificates" href="/docs/guides/https-certificates" description="HTTP-01, wildcard certificates, uploads, redirects and renewal in detail." />
  <Card title="Custom proxy config" href="/docs/guides/custom-proxy-config" description="Extra OpenResty directives for one domain." />
  <Card title="Domains, DNS & SSL troubleshooting" href="/docs/troubleshooting/domains-ssl" description="What each failure message means and how to fix it." />
</Cards>
