Skip to content

Add a second domain

$ grim server:add-domain shop www.shop.example.com

The shop is live on shop.example.com and now it should answer on www.shop.example.com too, or on the .cz the client bought last week. A second domain has to be known in three places: the host's nginx, Traefik's routing rule and the certificate. Editing one of them by hand gives you a 404 from Traefik or a certificate warning. grim server:add-domain changes all three together.

Usage

$ grim server:add-domain shop www.shop.example.com          # vhost, routing and certificate
$ grim server:add-domain shop shop.example.cz --force-dns   # DNS sits behind a proxy

Run it from anywhere. The project must have been added with grim server:add-project from this machine, because the primary domain and the host are read from your ~/.grim/servers.json. Point the new domain's DNS at the server before you start.

Arguments and options

Attach an additional domain (alias) to an existing project — same upstream, expanded SSL cert

Usage

grim server:add-domain [--host HOST] [--env ENV] [--no-ssl] [--force-vhost] [--force-dns] [--] <project> <domain>

Arguments

Argument Description
project Project name (as registered in servers.json) (required)
domain New domain to add as an alias (required)

Options

Option Description
--host=HOST Server host or alias (auto-resolved from servers.json when omitted)
--env=ENV Environment (production, staging, …) (default: production)
--no-ssl Skip certbot — render the vhost only
--force-vhost Bypass the "domain already on another vhost" pre-flight
--force-dns Skip the DNS A-record check (split-horizon / proxy DNS)

What it actually does

Two checks come first, and either can stop the run before the server is changed.

  1. Checks DNS from your machine. The new domain must resolve, and to an address the server also has. Skipped with --no-ssl and --force-dns.
  2. Looks for the domain in other vhosts on the server, the same check grim server:add-project makes.
  3. Rewrites the stack's nginx vhost with the new name next to the primary one, and reloads nginx.
  4. Rewrites the Traefik rule in the project's docker-compose.yml so that it matches every domain, and recreates the project's nginx container only. The app, the queue and the scheduler keep running.
  5. Widens the certificate. Runs certbot --expand for the primary domain and every alias, so one certificate covers them all. Skipped with --no-ssl.
  6. Saves the alias in servers.json. From there grim server:add-project, grim server:upgrade and grim server:sync-compose pick it up, so a later run of those does not drop it.

The summary lists the primary domain, every alias and the state of the certificate.

Pitfalls

Staging is its own stack

--env=staging works on /opt/<project>-staging and on the vhost grim-<project>-staging.conf, the stack that grim server:add-project --env=staging made. The production vhost is not read and not written. Without --env the command means production, also when staging is the only environment you registered; then it stops with Project "shop" not found in env "production". Run `grim server:add-project` first.

DNS behind a proxy fails the check

shop.example.cz resolves to 198.51.100.7 but the host 203.0.113.10 resolves to 203.0.113.10 — they need to share an IP. is the right answer for a typo in the record and the wrong one for a domain behind Cloudflare or split DNS. When you know the traffic arrives at the server, pass --force-dns. A domain with no record at all stops with shop.example.cz has no A record. Check DNS, or pass --force-dns to bypass.

It is built for Let's Encrypt

The vhost this command writes has no place for a certificate of your own. On a project added with --cert and --key it leaves the site on plain HTTP. Run grim server:add-project again afterwards, without --cert: it keeps the installed certificate, writes the HTTPS block back and includes the new alias. The certificate itself must already cover the new name.

A second domain is served, not redirected

Both names reach the same app, and APP_URL in the server's .env still names the primary one. If the alias should redirect to the primary domain, that is the app's job.

A failed certificate does not fail the run

Read the SSL row of the summary. The vhost is rewritten before certbot runs, and it is certbot that writes the HTTPS block into it. On failed the primary domain is without that block as well, until the certbot command printed below the table succeeds. Repeat it at once.

--no-ssl takes HTTPS off the whole project

For the same reason. With --no-ssl the vhost is rewritten and certbot never runs, so a project that had a certificate is left on plain HTTP. Use the flag only on a project that was added with --no-ssl itself.

After it finishes

Open the new domain in a browser. Running the command again with a domain that is already attached is safe: it writes the same vhost and asks certbot for the same list of names.

Recipes that use it