How the stack is deployed, configured, updated, and verified.
~/supplyshore-stack/
├── docker-compose.yml # full stack definition (single file)
├── .env # all secrets + config (DO NOT COMMIT)
├── docs/ # the documentation pack (see docs/README.md)
└── (postgres/, traefik/) # legacy scratch dirs, unused
Deployed copy on the node: /opt/supplyshore/ (same two files).
.envis the source of truth for all passwords/secrets. It exists in two
places (local + server) and must be kept in sync. Full values in
credentials.md.
docker-compose.yml OverviewCompose project name: supplyshore (top-level name: key).
Top-level sections:
name: supplyshore
networks:
web: {} # single shared network
volumes: # named volumes (persistent)
traefik-cert: {}
twenty-db: {} # Postgres data (name is historical)
n8n-data: {}
espocrm-db: {} # MariaDB data
espocrm-data: {}
espocrm-custom: {}
espocrm-custom-client: {}
services:
traefik: ...
espocrm-db: ...
espocrm: ...
espocrm-daemon: ...
n8n: ...
postgres: ...
Services that are reachable from the internet get Traefik labels (see
architecture.md §3.2).
.env Reference| Variable | Used by | Purpose |
|---|---|---|
DOMAIN |
all | base domain supplyshoreltd.com |
LETSENCRYPT_EMAIL |
traefik | ACME account email |
PG_PASSWORD |
postgres, n8n | Postgres + n8n DB password |
MARIADB_ROOT_PASSWORD |
espocrm-db | MariaDB root password |
MARIADB_PASSWORD |
espocrm-db, espocrm | CRM DB app-user password |
N8N_ENCRYPTION_KEY |
n8n | encrypt n8n stored credentials |
N8N_TAG |
n8n | image tag (default latest) |
DASHBOARD_USER |
traefik | dashboard basic-auth user |
ESPOCRM_ADMIN_USER |
espocrm | initial admin username |
ESPOCRM_ADMIN_PASSWORD |
espocrm | initial admin password |
# 1. Edit locally: ~/supplyshore-stack/docker-compose.yml and/or .env
# 2. Validate locally
docker compose -f ~/supplyshore-stack/docker-compose.yml config >/dev/null
# 3. Sync to node
scp ~/supplyshore-stack/docker-compose.yml ~/supplyshore-stack/.env \
root@139.162.176.234:/opt/supplyshore/
# 4. Apply (recreates changed containers only)
ssh root@139.162.176.234 "cd /opt/supplyshore && docker compose up -d --remove-orphans"
# 5. Verify
ssh root@139.162.176.234 "cd /opt/supplyshore && docker compose ps"
--remove-orphans is important: it deletes containers that were removed from
the compose file (e.g. when swapping apps).
# e.g. bump n8n to a specific version
sed -i 's/^N8N_TAG=.*/N8N_TAG=v2.33.5/' ~/supplyshore-stack/.env
# then repeat steps 3–5 above
docker compose pull # run on node before up -d to fetch the new image
All data is in named volumes, so rolling back = restoring the previous compose
.env and redeploying. Containers themselves are disposable.ssh root@139.162.176.234
cd /opt/supplyshore
docker compose ps # status
docker compose logs -f <svc> # follow logs (espocrm, n8n, traefik…)
docker compose restart <svc> # restart one service
docker compose up -d # apply/start
docker compose down # stop everything (keeps volumes)
docker compose down -v # ⚠️ stop + DELETE volumes/data
docker stats # live resource usage
Service names usable with docker compose: traefik, espocrm,
espocrm-db, espocrm-daemon, n8n, postgres.
linode-cli linodes create \
--type g6-standard-2 --region eu-central \
--image linode/ubuntu24.04 --label supplyshore-stack \
--root_pass <temp> --authorized_keys ~/.ssh/id_ed25519.pub
curl -fsSL https://get.docker.com | bash
docker exec -it espocrm-db mariadb -uroot -p$MARIADB_ROOT_PASSWORD
# MariaDB auto-creates `espocrm` + user via env on first boot; n8n's
# postgres DB is created by the POSTGRES_DB env.
docker compose up -d --remove-orphans.infrastructure.md §4).139.162.176.234.docker-compose.yml with:
web network,traefik.enable, router rule Host(\sub.${DOMAIN}`), websecure, letsencrypt`, loadbalancer port)..env.https://sub.supplyshoreltd.com.$ in the apr1 hash MUST be$$ (e.g. $$apr1$$...), otherwise Compose tries to substitute it.MARIADB_ROOT_PASSWORD /POSTGRES_PASSWORD in .env does NOT change an already-initialized volume.ALTER USER) and update .env.twenty-db volume name is a leftover from Twenty CRM; it currently backs/install/ path).