Raise a production server
$ grim server:setup 203.0.113.10 --alias=vps1 --email=ssl@example.com --ghcr-token=ghp_xxx
You have a fresh VPS and a project that is ready to go live. Before the first release can land, the machine needs Docker, a database, something to terminate TLS and an account to deploy as. grim server:setup does all of that in one run, once per server. Every project you put there afterwards shares what it built.
It is safe to run again. Each step checks what is already in place, so a second run repairs what is missing and leaves the rest alone.
Usage
$ grim server:setup 203.0.113.10 --alias=vps1 --email=ssl@example.com --ghcr-token=ghp_xxx
$ grim server:setup 203.0.113.10 --alias=vps1 --email=ssl@example.com --user=ubuntu
$ grim server:setup 10.0.0.30 --alias=vps2 --cert=~/certs/shop.pem --key=~/certs/shop-key.pemThe first line is a VPS you reach as root. The second is a cloud image that only lets ubuntu in. The third is a server whose certificates come from your own authority. Run it from anywhere; it needs no project. The alias is the name every later command takes as --host.
Arguments and options
Initialize a VPS server for GRIM deployments (Docker, Traefik, deploy user)
Usage
grim server:setup [--alias ALIAS] [--user USER] [--email EMAIL] [--cert CERT] [--key KEY] [--ghcr-token GHCR-TOKEN] [--] <host>Arguments
| Argument | Description |
|---|---|
host |
Server IP address or hostname (required) |
Options
| Option | Description |
|---|---|
--alias=ALIAS |
Short alias for the server (e.g., vps1) |
--user=USER |
SSH user for initial connection (default: root) |
--email=EMAIL |
Email for Let's Encrypt certificates (not needed with --cert/--key) |
--cert=CERT |
Bring-your-own TLS certificate (PEM: leaf + intermediates) — turns Let's Encrypt off for this server |
--key=KEY |
Private key (PEM) belonging to --cert |
--ghcr-token=GHCR-TOKEN |
Classic PAT with read:packages for GHCR login (if different from auth token) |
What it actually does
Ten steps, each printed with its result. The first one that fails stops the run.
- Checks SSH. Connects as
--user, which isrootunless you say otherwise. - Detects the OS, for the summary at the end.
- Installs Docker from
get.docker.com, when it is not there yet. - Installs MySQL, nginx and certbot with
apt, and starts them. With--certcertbot is left out. - Opens MySQL to the containers. Sets
bind-addressto0.0.0.0and restarts MySQL, so that a container can reach the database on the host. - Creates the
deployuser. In thedockergroup, with/optwritable for it and your public key in itsauthorized_keysunder the labeloperator. - Creates the
traefik-publicnetwork. - Starts Traefik from
/opt/traefik/docker-compose.yml, on ports 8080 and 8443. A Traefik that is already running is left as it is. - Logs the
deployuser in to GHCR, when--ghcr-tokenis given. - Remembers the server in your
~/.grim/servers.json: alias, thedeployuser, the login it bootstrapped with, the Let's Encrypt email and the TLS mode.
How a request travels afterwards
nginx on the host owns ports 80 and 443 and holds the certificates. Each project gets one vhost there, which passes everything to Traefik on 127.0.0.1:8080. Traefik looks at the Host header and hands the request to the right project's containers. MySQL runs on the host, one server for all projects, and the containers reach it as host.docker.internal.
That is the opposite of a shared dev box, where Traefik takes the public ports itself and every project brings its own database. The two are compared side by side in grim server:dev:setup. Do not run both on one machine.
MySQL listening on 0.0.0.0 after setup is deliberate, not a leak. The database users grim server:add-project creates may only connect from localhost and from the Docker address range 172.%. Setup configures no firewall, so keep port 3306 closed to the outside at your provider.
Two ways to get certificates
| Mode | Pass | What changes |
|---|---|---|
| Let's Encrypt | --email |
certbot is installed. Each project's certificate is issued when the project is added. |
| Your own certificate | --cert and --key together |
certbot is not installed at all. The pair is checked on your machine and its paths are remembered for grim server:add-project. |
With neither, setup asks for an email. The check of your own pair happens before the server is touched: PEM format, a key without a passphrase that belongs to the certificate, and an expiry date in the future. A file with the leaf certificate only passes with a warning.
Pitfalls
Cloud images do not let root in
Cannot connect to root@203.0.113.10 on a fresh AWS, GCP or Azure machine is not a firewall. Those images log in as ubuntu, ec2-user or admin. Pass that login as --user. It must have passwordless sudo, because every privileged step runs through sudo -n.
The GHCR step is green whatever happened
Step 9 shows a tick when the login worked, when it failed and when there was no token at all. You find out at the first release, when the server is refused the image. Run grim server:ghcr-login afterwards; it prints the real answer from Docker.
Your key is not where setup looks
Setup installs ~/.ssh/id_ed25519.pub, or ~/.ssh/id_rsa.pub when the first does not exist. With a key under any other name the deploy user is created without one, the step still passes, and the first deploy cannot log in. Add the key yourself with grim server:keys.
A second run does not update Traefik
Setup skips Traefik as soon as it finds it running. Template fixes that came with a newer grim reach an existing server through grim server:upgrade-traefik.
After it finishes
The summary ends with the next command, filled in with your alias. Give the server its first project, then release into it.
$ grim server:add-project shop --host=vps1 --domain=shop.example.com
$ grim releaseWhat the second step expects is in grim server:add-project. The whole path from an empty VPS to a live site is the recipe First deploy to a fresh VPS.
Related spells
grim server:ghcr-login
Let a server pull images
Log a server's deploy user in to the GitHub Container Registry, so the server can pull the project's private images.
grim server:add-project
Give a project a home
Prepare one environment of a project on a production server, with its database, nginx vhost, certificate, compose stack and .env.
grim server:status
Look over a server
List the servers you have registered, or look at one of them: its containers, its disk, Traefik and its projects.
grim server:dev:setup
Raise a shared dev box
Turn a bare VPS or LAN machine into a shared development server with Docker, Traefik, one dev user and grim itself.