SignetMail docs Open portal →

#Operations

Day-to-day running of a SignetMail server: updating, monitoring, backups, restoring and renewing certificates. All commands run on the server in the folder with docker-compose.yml (for example /opt/signetmail/cloud).

#Daily checks (30 seconds)

curl -s https://<host>/health            # {"status":"ok","lastSyncUtc":"…"} — sync time should be < ~2 h old
sudo docker compose ps                   # both services "running"
sudo docker compose logs --tail 100 signetmail-api

Warning signs: lastSyncUtc stuck in the past (Graph permissions or certificate problem), repeated errors in the log, a container restarting.

#Updating

  1. Back up first (see below).
  2. Pull and restart:
    sudo docker login ghcr.io -u <github-user>      # token with read:packages only
    sudo docker compose pull
    sudo docker compose up -d
    sudo docker logout ghcr.io
    
  3. Verify /health and sign in to the portal.
  4. Pull the repository (git -C /opt/signetmail pull) when release notes mention changes to docker-compose.yml, Caddyfile or .env.example, and compare with your files.

To control versions, set SIGNETMAIL_VERSION=sha-<commit> in .env instead of latest; rolling back is then a matter of setting the previous value and running docker compose up -d.

The operating system patches itself (dnf-automatic). Reboot occasionally when the kernel was updated (sudo dnf needs-restarting -r).

#Backups

What to protect: the data/ folder (SQLite database with organizations, signatures, versions, rules, access, audit log, statistics and the uploads/ images), your .env, and certs/graph.pfx (or be ready to create a new certificate).

#Encrypted backups to a private GitHub repository

backup.sh creates a consistent snapshot (sqlite3 .backup), packs it, encrypts it with AES-256 (PBKDF2, 600 000 iterations) and pushes it to a private repository with a repository-specific deploy key. The last 30 encrypted copies are kept.

One-time setup:

  1. Create an empty private repository, for example signetmail-backups.
  2. On the server create a key used only for it:
    ssh-keygen -t ed25519 -N "" -f ~/.ssh/backup_deploy
    cat ~/.ssh/backup_deploy.pub
    
    Add the public key in the repository under Settings → Deploy keys → Add deploy key, with Allow write access.
  3. Create the encryption passphrase and store a copy in your password manager:
    openssl rand -base64 32 > .backup-passphrase && chmod 600 .backup-passphrase
    echo 'BACKUP_GIT_REMOTE=git@github.com:<user>/signetmail-backups.git' >> .env
    sudo dnf -y install git      # if git is missing
    ./backup.sh
    
  4. Schedule it daily:
    crontab -e
    0 3 * * * /opt/signetmail/cloud/backup.sh
    

Warning. The passphrase is the only way to open a backup. Store it outside the server (password manager). Never paste it into chats or tickets; if it leaked, generate a new one — new backups use it, old ones stay readable with the old one.

Local copies also remain in backups/.

#Restoring

On a clean server (with the stack installed but stopped):

git clone git@github.com:<user>/signetmail-backups.git
openssl enc -d -aes-256-cbc -pbkdf2 -iter 600000 \
  -in signetmail-<timestamp>.tar.gz.enc -pass file:.backup-passphrase | tar -xz

You get signetmail.db and uploads/. Then:

sudo docker compose down
sudo cp signetmail.db data/ && sudo cp -r uploads data/
sudo chown -R 1654 data
sudo docker compose up -d

Test a restore at least once, before you need it.

#Renewing the Graph certificate

certs/graph.cer expires 730 days after creation. Before that date:

  1. Generate a new pair: move the old certs/graph.* away and run ./setup.sh again.
  2. In Entra → Certificates & secrets upload the new graph.cer (keep the old one until the new one works).
  3. Restart: sudo docker compose restart signetmail-api and check /health.
  4. Remove the old certificate from Entra.

If it expires unnoticed the directory sync fails: lastSyncUtc stops advancing and changes in Entra ID (new employees, new titles) no longer reach signatures.

#TLS certificate

Caddy renews the Let's Encrypt certificate automatically. It needs ports 80 and 443 open and the DNS record intact. If the site shows a certificate warning, check sudo docker compose logs caddy.

#Changing configuration

Edit .env and run sudo docker compose up -d; containers whose settings changed are recreated. Examples: changing PORTAL_ALLOWED_IPS, switching the version, rotating GRAPH_CERT_PASSWORD (after re-running setup.sh).

#Moving to another server

  1. Take a backup and restore it on the new server (see above).
  2. Copy .env and certs/.
  3. Switch the DNS record to the new IP. Caddy requests a new certificate for the new server.
  4. Update nothing in Entra if the host name is unchanged.

#Log locations

sudo docker compose logs [service] — rotated automatically (5 × 10 MB per container). The Windows agent logs to %LOCALAPPDATA%\SignetMail\agent.log on each PC.

#Monitoring suggestions

  • An external uptime monitor on https://<host>/health.
  • An alert if lastSyncUtc is older than three hours.
  • A calendar reminder for the Graph certificate expiry.
  • A calendar reminder to test the restore twice a year.
SignetMail documentation · version main