No description
  • HTML 86.2%
  • CSS 12.8%
  • JavaScript 0.6%
  • Dockerfile 0.4%
Find a file
2026-07-29 13:40:36 -04:00
mono add flaresolverr to media stack 2026-07-29 13:40:36 -04:00
.DS_Store chore: remove GEMINI.md 2026-06-22 16:39:17 -04:00
.gitignore chore: remove multi-compose deployment 2026-06-01 15:25:29 -04:00
AGENTS.md fix: add minio cors vars 2026-07-20 11:08:00 -04:00
README.md chore: update comprehensive readme 2026-06-22 16:50:21 -04:00
renovate.json chore: allow renovate to dump all changes 2026-04-23 03:25:57 +00:00
SETUP.md feat: add comprehensive docker healthchecks to all services 2026-04-22 19:53:49 -04:00

CoreBotLabs — Infrastructure Documentation

Repo: git.corebot.ca/CoreBotLabs/infra
Stack: Docker Compose · Nginx Proxy Manager · Komodo


Table of Contents

  1. Overview
  2. Repository Layout
  3. Server
  4. Networking & Access
  5. Service Catalogue
  6. Monitoring & Observability
  7. Logging Pipeline
  8. MysticOS — Internal Home Dashboard
  9. Legal Pages
  10. Dependency Management (Renovate)
  11. Infrastructure Management (Komodo)
  12. Domain Map
  13. Environment Variables Reference
  14. Healthchecks Reference
  15. Re-Launching Services
  16. Adding a New Service

1. Overview

The infra repository contains all Docker Compose configuration and supporting config files for the CoreBotLabs self-hosted infrastructure — codenamed Mystic.

The infrastructure serves two purposes:

  1. Internal tooling — Git hosting, monitoring, password management, DNS, and automation for the CoreBot Labs team.
  2. Public-facing services — The CoreBot Discord bot's backend, blog, CDN, and legal pages.

Everything runs inside Docker containers on a single Ubuntu Server VPS (Primary). All containers share one internal Docker network. Public traffic arrives through Nginx Proxy Manager, which handles TLS termination and reverse-proxying. Komodo is used for deployment management and container lifecycle control.


2. Repository Layout

.
├── README.md
├── SETUP.md
├── renovate.json              # Root Renovate config (no PR hourly limit)
└── mono/
    ├── master/                # Primary application stack
    │   ├── docker-compose.yml
    │   ├── legal/html/        # Privacy & ToS static HTML
    │   ├── loki/              # Loki log aggregation config
    │   ├── mystic-home/       # MysticOS dashboard (Dockerfile + static site)
    │   ├── prometheus/        # Prometheus scrape config
    │   ├── promtail/          # Promtail log-shipping config
    │   └── renovate/          # Renovate runner config
    └── databases/             # Database stack
        ├── docker-compose.yml
        ├── mongo-data/        # MongoDB persistent data
        ├── redis-data/        # Redis RDB snapshot
        └── promtail/          # Promtail log-shipping config

Monorepo note: The mono/ directory contains two independent Docker Compose stacks — master and databases — that both run on the same host and communicate via the shared mystic-net Docker network.


3. Server

All services run on a single Ubuntu Server VPS referred to throughout this documentation as Primary.

Property Value
OS Ubuntu Server (LTS)
Container runtime Docker Engine + Compose plugin
Stacks mono/master, mono/databases
Shared network mystic-net (external Docker bridge)

4. Networking & Access

Docker Network

All containers in both stacks join a single external Docker network named mystic-net. This must be created once on the host before any stack is started:

docker network create mystic-net

Containers communicate with each other by service name (e.g., mystic-mongodb, loki, mystic-postgres). Because both stacks live on the same host, this works transparently across compose files.

Nginx Proxy Manager (NPM)

NPM is the sole public ingress point for all web services.

  • Port 80 and 443 are bound to the public interface for HTTP/HTTPS traffic.
  • Port 81 hosts the NPM admin UI (accessible internally only).
  • Let's Encrypt certificates are managed automatically by NPM.
  • NPM data and certs are stored at /root/docker/mono/master/npm/.
  • API docs: https://npm.corebot.ca/api/schema

Port Reference

Container Host Port Notes
NPM 80, 443, 81 Public ingress + admin
MongoDB 27017 Bound to localhost only — not public
PgAdmin 8084 Internal
MinIO API 9000 Public (S3 endpoint)
MinIO Console 9001 Public (web UI)
Pocket-ID 1411 SSO
Vaultwarden 8081 Behind NPM
Grafana 3002 Behind NPM
Prometheus 9090 Behind NPM
Uptime Kuma 3001 Behind NPM
Node Exporter 9102 Internal
Docker Exporter 8082 Internal
Loki 3100 Internal
Code Server 8443 Internal
Ghost 2368 Behind NPM
Forgejo HTTP 3000 Bound to ${GIT_IP}
Forgejo SSH 2222 Bound to ${GIT_IP}
Immich 2283 Behind NPM
Nextcloud 8083 Behind NPM
n8n 5678 (internal) Behind NPM

5. Service Catalogue

5.1 Master Stack — mono/master

Located at mono/master/docker-compose.yml.


Authentication

Pocket-ID

  • Image: ghcr.io/pocket-id/pocket-id:v2
  • Purpose: OpenID Connect / SSO provider for internal services.
  • Port: 1411
  • Data: ./data
  • Healthcheck: built-in pocket-id healthcheck binary (1m30s interval).

Vaultwarden

  • Image: vaultwarden/server:1.36.0
  • Purpose: Self-hosted Bitwarden-compatible password manager. Public at https://vault.corebot.ca.
  • Port: 8081 → 80
  • SSO enabled via Pocket-ID. Signups disabled (invite-only).
  • SMTP: configured via SMTP_HOST, SMTP_USER, SMTP_PASS over forced TLS on port 465.
  • Data: ./data

Monitoring

Grafana

  • Image: grafana/grafana-enterprise
  • Purpose: Metrics and log dashboards. Public at https://grafana.corebot.ca.
  • Port: 3002 → 3000
  • Admin credentials set via GRAFANA_ADMIN_PASSWORD.

Prometheus

  • Image: prom/prometheus:latest
  • Purpose: Time-series metrics collection. Public at https://prometheus.corebot.ca.
  • Port: 9090
  • Config: ./prometheus/prometheus.yml (see Section 6).
  • Data volume: prometheus_data

Uptime Kuma

  • Image: louislam/uptime-kuma:2
  • Purpose: Service uptime monitoring with public and internal status pages.
  • Port: 3001
  • Timezone: America/Toronto

Kuma-Container-Sync

  • Image: ghcr.io/benrhughes/kuma-container-sync:latest
  • Purpose: Automatically registers running Docker containers as monitors in Uptime Kuma.
  • Depends on: uptime-kuma
  • Group name: Mystic

Node Exporter

  • Image: prom/node-exporter:v1.11.1
  • Purpose: Host system metrics (CPU, memory, disk, network) for Prometheus.
  • Port: 9102 → 9100

Docker Exporter

  • Image: ghcr.io/davidborzek/docker-exporter:v0.3.0
  • Purpose: Docker engine metrics for Prometheus.
  • Port: 8082 → 8080

cAdvisor

  • Image: gcr.io/cadvisor/cadvisor:v0.55.1
  • Purpose: Per-container resource usage metrics.
  • Mounts /, /var/run, /sys, /var/lib/docker, /dev/disk read-only.

Loki

  • Image: grafana/loki:3.7.1
  • Purpose: Log aggregation backend, queried by Grafana.
  • Port: 3100
  • Depends on consul being healthy before starting.
  • Config: ./loki/local-config.yaml
  • Data: ./loki-data

Consul

  • Image: hashicorp/consul:latest
  • Purpose: Memberlist KV store used by Loki's internal ring.
  • Runs in dev mode (agent -dev -client 0.0.0.0).

Promtail (master)

  • Image: grafana/promtail:3.6.8
  • Purpose: Ships logs from this host's containers to Loki.
  • Config: ./promtail/config.yml

Networking

Nginx Proxy Manager (NPM)

  • Image: jc21/nginx-proxy-manager:2.14.0
  • Purpose: Reverse proxy, TLS termination, Let's Encrypt certificate management.
  • Ports: 80, 443 (public), 81 (admin UI).
  • Persistent data: /root/docker/mono/master/npm/data and /root/docker/mono/master/npm/letsencrypt.

Web Applications

Mystic Home

  • Image: nginx:alpine
  • Purpose: Internal homepage dashboard ("MysticOS"). See Section 8.
  • Serves static files from ./mystic-home/www.

Code Server

  • Image: lscr.io/linuxserver/code-server:latest
  • Purpose: Browser-based VS Code instance for remote development.
  • Port: 8443
  • Credentials: CODE_SERVER_PASSWORD, CODE_SUDO_PASSWORD.
  • Workspace: ./code-server/workspace.

Mystic Privacy / Mystic ToS

  • Image: nginx:alpine
  • Purpose: Static pages serving the Privacy Policy and Terms of Service.
  • Source: ./legal/html/privacy.html and ./legal/html/tos.html.

Ghost

  • Image: ghost:6-alpine
  • Purpose: Blog platform. Public at https://blog.corebot.ca.
  • Port: 2368
  • Database: SQLite3 (./ghost/content/data/ghost.db).
  • SMTP: PurelyMail via PURELYMAIL_USER / PURELYMAIL_PASS.

Forgejo

  • Image: codeberg.org/forgejo/forgejo:15
  • Purpose: Self-hosted Git forge. Public at https://git.corebot.ca.
  • Ports: ${GIT_IP}:3000 (HTTP), ${GIT_IP}:2222 (SSH).
  • Backend database: PostgreSQL (forgejo_db, user forgejo_user, password FORGEJO_DB_PASS).
  • Prometheus metrics enabled, protected by FORGEJO_METRICS_TOKEN.
  • Data: ./data

Renovate

  • Image: renovate/renovate:38.25.0
  • Purpose: Automated dependency update PRs across all repos on Forgejo.
  • Resource limits: 0.5 CPU, 1 GB RAM.
  • Runs every 3 hours via a shell loop — no external cron needed.
  • Config: ./renovate/config.js — see Section 10.

Immich

  • Images: ghcr.io/immich-app/immich-server + immich-machine-learning
  • Purpose: Self-hosted photo and video management.
  • Port: 2283
  • Uses mystic-postgres (database stack) and mystic-redis (database stack).
  • ML model cache volume: model-cache.

Nextcloud

  • Image: nextcloud:stable-apache
  • Purpose: Self-hosted file storage and collaboration.
  • Port: 8083 → 80
  • Data: ./data/nextcloud
  • Background jobs handled by the nextcloud-cron sidecar (runs /cron.sh).

n8n

  • Image: docker.n8n.io/n8nio/n8n
  • Purpose: No-code workflow automation. Public at https://n8n.corebot.ca.
  • Data: ./n8n_data

5.2 Database Stack — mono/databases

Located at mono/databases/docker-compose.yml. Runs on the same host as the master stack and communicates over mystic-net.


Databases

MongoDB

  • Image: mongo:7
  • Container: mystic-mongodb
  • Auth enabled (--auth --bind_ip_all).
  • Port 27017 is bound to 127.0.0.1 only — never publicly exposed.
  • Credentials: MONGO_ROOT_USER / MONGO_ROOT_PASS.
  • Persistent data: ./mongo-data.

PostgreSQL (with pgvector)

  • Image: pgvector/pgvector:pg16
  • Container: mystic-postgres
  • No host port binding — accessible only within mystic-net.
  • Credentials: DB_ROOT_USER / DB_ROOT_PASS.
  • Used by: Forgejo, Immich, and other application services.

PgAdmin

  • Image: dpage/pgadmin4
  • Container: pgadmin
  • Port: 8084 → 80
  • Credentials: PGADMIN_EMAIL / PGADMIN_PASS.

Redis

  • Image: redis:alpine
  • Container: mystic-redis
  • Password-protected via REDIS_PASS.
  • Persistence: saves to disk every 60s if ≥1 key changed (--save 60 1).
  • Used by: Immich.

MinIO

  • Image: minio/minio:latest
  • Container: mystic-minio
  • Purpose: S3-compatible object storage.
  • Ports: 9000 (S3 API), 9001 (web console).
  • Credentials: MINIO_ROOT_USER / MINIO_ROOT_PASSWORD.
  • Data: ./minio/data

Database Exporters (for Prometheus)

Container Image Metrics For
mongodb-exporter percona/mongodb_exporter:0.51 MongoDB
postgres-exporter prometheuscommunity/postgres-exporter:v0.19.1 PostgreSQL
redis-exporter oliver006/redis_exporter:v1.86.0 Redis
node-exporter prom/node-exporter:v1.11.1 Host system
cadvisor gcr.io/cadvisor/cadvisor:v0.55.1 Containers
promtail grafana/promtail:3.6.8 Log shipping

6. Monitoring & Observability

Prometheus is configured at mono/master/prometheus/prometheus.yml with a 15-second global scrape interval. Grafana connects to both Prometheus (metrics) and Loki (logs) to provide unified dashboards.

Scrape Targets

Job Target What it monitors
prometheus localhost:9090 Prometheus self-metrics
node-exporter mystic-node-exporter:9100, mystic-db-node-exporter:9100 Host CPU, memory, disk, network
cadvisor mystic-cadvisor:8080, mystic-db-cadvisor:8080 Per-container resource usage
docker-exporter mystic-docker-exporter:8080 Docker engine metrics
postgres databases-postgres-exporter-1:9187 PostgreSQL queries, connections
mongodb databases-mongodb-exporter-1:9216 MongoDB ops, connections
redis databases-redis-exporter-1:9121 Redis memory, keyspace, commands
pihole mystic-dns-pihole-exporter:9617 DNS query stats, blocklist hits

All targets are reachable by container name because every service is on the same mystic-net network.


7. Logging Pipeline

All containers ship logs to a central Loki instance via Promtail, then visualised in Grafana.

[Docker containers]
        │  (Docker socket — automatic discovery)
        ▼
   [Promtail]  ──► pushes to ──►  [Loki :3100]  ──► queried by ──►  [Grafana]
                                        │
                                   [Consul :7946]
                                  (memberlist ring)

Promtail Config (mono/master/promtail/config.yml and mono/databases/promtail/config.yml)

Both configs share the same structure:

  • HTTP server on port 9080
  • Positions file: /tmp/positions.yaml
  • Push target: http://loki:3100/loki/api/v1/push
  • Discovery: Docker socket (unix:///var/run/docker.sock, refresh every 5s)
  • Relabelling: container name → container label (leading / stripped)

Loki Config (mono/master/loki/local-config.yaml)

  • Auth: disabled (internal-only)
  • HTTP: 3100, gRPC: 9095
  • Storage: filesystem at /loki/chunks (chunks) and /loki/rules (rules)
  • Index: TSDB schema v13, 24h period, prefix index_
  • Ring KV store: Consul memberlist on port 7946
  • Replication factor: 1 (single node)
  • Old sample rejection: enabled — max age 168 hours (7 days)

8. MysticOS — Internal Home Dashboard

mono/master/mystic-home/ contains a custom internal dashboard served by Nginx.

Structure

mystic-home/
├── Dockerfile        # FROM nginx:alpine, COPY www/ /usr/share/nginx/html/
└── www/
    ├── index.html    # Dashboard page
    └── style.css     # Dark theme styles

Features

  • Dark themed launcher — GitHub-dark colour scheme (#0d1117 background, #58a6ff accent).
  • Service dock — Icon links to Forgejo, Vault, Pi-hole, Grafana, and Prometheus.
  • Live health indicators — Each service icon is polled every 30 seconds. Green border = reachable, red border = no response within 5s.
  • Google search bar — Integrated search form.
  • Icons — Lucide icon library loaded via unpkg CDN.

Health Check Method

Uses an <img> favicon probe to avoid CORS restrictions:

img.src = `${service.url}/favicon.ico?t=${Date.now()}`;
// onload and onerror both count as "up" — a CORS/security error still means the server responded
// No response within 5s = "down"

Adding a Service to the Dock

Edit mono/master/mystic-home/www/index.html. Add an entry to both the HTML dock and the JavaScript services array:

<!-- In the .dock div -->
<a href="https://yourservice.corebot.ca" class="icon-link">
    <div class="icon-box"><i data-lucide="icon-name"></i></div>
    <div class="label">Service Name</div>
</a>
// In the services array
{ name: 'Service Name', url: 'https://yourservice.corebot.ca' },

Browse available icon names at lucide.dev.


Located at mono/master/legal/html/. Both pages are served as static HTML via separate nginx:alpine containers.

Effective date: April 1, 2026

Privacy Policy Highlights

  • Collects: Discord User IDs, Server IDs, Channel IDs, message-length metrics — not message content.
  • Infrastructure metrics logged for service health and stability.
  • Data stored in Canada and Google Cloud (USA).
  • User data deleted on verified request: data@corebot.ca.
  • No sale of data; not shared with affiliates (swvn.io, Nexus).
  • GDPR-compliant — users have the right to access, rectify, delete, and export their data.

Terms of Service Highlights

  • CoreBot source available at git.corebot.ca under its open-source licence.
  • The "CoreBot Labs" name, branding, and hosted instances remain property of CoreBot Labs.
  • Prohibited: spam, self-botting, reverse-engineering internal APIs.
  • Affiliates: swvn.io, Nexus (separate entities with their own terms).
  • Services provided "as-is."

10. Dependency Management (Renovate)

Renovate runs as a long-lived Docker container, polling Forgejo every 3 hours for outdated image tags and package versions across all repos.

Root Config (renovate.json)

{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "prHourlyLimit": 0
}

prHourlyLimit: 0 disables the default PR rate cap, allowing Renovate to open as many update PRs as needed in a single run.

Runner Config (mono/master/renovate/config.js)

module.exports = {
  endpoint: process.env.RENOVATE_ENDPOINT || 'http://mystic-forgejo:3000/api/v1',
  platform: 'gitea',        // Forgejo is Gitea-compatible
  autodiscover: true,        // Scans all repos on the Forgejo instance
  gitAuthor: 'Renovate Bot <noreply@corebot.ca>',
  onboarding: true,
  printConfig: true,
  ignorePaths: ["**/.old/**", "**/.dev/**"],
};

Schedule

The container runs an internal shell loop — no external cron or scheduler needed:

while true; do renovate; sleep 10800; done  # every 3 hours

11. Infrastructure Management (Komodo)

Komodo provides centralised container lifecycle management, deployment control, and health visibility from a single web UI.

Core

Periphery Agent

The Periphery agent runs alongside the core on Primary and gives Komodo visibility and control over the host's containers.

Key environment variables for the periphery container:

Variable Description
PERIPHERY_CORE_ADDRESS URL of the Komodo Core container (e.g. http://komodo-core:9120)
PERIPHERY_CONNECT_AS Display name for this host in the Core UI (e.g. Primary)
PERIPHERY_ONBOARDING_KEY Shared secret used to authenticate the agent with Core on first connect

Example API Call

curl --header "Content-Type: application/json" \
     --header "X-Api-Key: <YOUR_KEY>" \
     --header "X-Api-Secret: <YOUR_SECRET>" \
     --data '{ "id": "my-build", "config": { "version": "2.0.0" } }' \
     http://localhost:9120/write/UpdateBuild

API credentials are generated inside the Komodo Core web UI.


12. Domain Map

All domains use HTTPS via Let's Encrypt certificates managed by NPM.

Domain Service
git.corebot.ca Forgejo
vault.corebot.ca Vaultwarden
dns.corebot.ca Pi-hole
grafana.corebot.ca Grafana
prometheus.corebot.ca Prometheus
blog.corebot.ca Ghost
n8n.corebot.ca n8n
npm.corebot.ca Nginx Proxy Manager admin UI
vault.corebot.services Vaultwarden (alternate domain)

13. Environment Variables Reference

Each stack reads from a .env file in its directory. Never commit .env files to version control.


Database Stack — mono/databases/.env

#-------------
# PostgreSQL
#-------------
DB_ROOT_USER=
DB_ROOT_PASS=

#-------------
# pgAdmin
#-------------
PGADMIN_EMAIL=
PGADMIN_PASS=

#-------------
# MongoDB
#-------------
MONGO_ROOT_USER=
MONGO_ROOT_PASS=

#-------------
# Redis
#-------------
REDIS_PASS=

#-------------
# MinIO
#-------------
MINIO_ROOT_USER=
MINIO_ROOT_PASSWORD=
Variable Used By Description
DB_ROOT_USER PostgreSQL, postgres-exporter PostgreSQL superuser username
DB_ROOT_PASS PostgreSQL, postgres-exporter PostgreSQL superuser password
PGADMIN_EMAIL PgAdmin Login email for the PgAdmin web UI
PGADMIN_PASS PgAdmin Login password for the PgAdmin web UI
MONGO_ROOT_USER MongoDB, mongodb-exporter MongoDB root username
MONGO_ROOT_PASS MongoDB, mongodb-exporter MongoDB root password
REDIS_PASS Redis, redis-exporter Redis AUTH password
MINIO_ROOT_USER MinIO MinIO admin username (acts as S3 access key)
MINIO_ROOT_PASSWORD MinIO MinIO admin password (acts as S3 secret key)

Master Stack — mono/master/.env

#-------------
# Database / Shared
#-------------
DB_IP=host.docker.internal

#-------------
# Authentication (Vaultwarden & PocketID)
#-------------
ADMIN_TOKEN=
SMTP_HOST=
SMTP_PORT=465
SMTP_USER=
SMTP_PASS=
ENCRYPTION_KEY=
APP_URL=

#-------------
# Networking / PiHole
#-------------
PIHOLE_PASS=

#-------------
# Webapps / Ghost
#-------------
PURELYMAIL_USER=
PURELYMAIL_PASS=

#-------------
# Forgejo
#-------------
FORGEJO_DB_PASS=
FORGEJO_METRICS_TOKEN=
GIT_IP=

#-------------
# Renovate
#-------------
RENO_TOKEN=
GITHUB_COM_TOKEN=

#-------------
# Immich
#-------------
IMMICH_VERSION=release
UPLOAD_LOCATION=
DB_PASSWORD=
DB_USERNAME=
DB_DATABASE_NAME=
DB_DATA_LOCATION=
REDIS_PASSWORD=
REDIS_HOSTNAME=

#-------------
# Nextcloud
#-------------
NEXTCLOUD_DB_USER=
NEXTCLOUD_DB_PASS=
NEXTCLOUD_ADMIN=
NEXTCLOUD_ADMIN_PASS=

#-------------
# Grafana
#-------------
GRAFANA_ADMIN_PASSWORD=

#-------------
# n8n
#-------------
N8N_HOST=
N8N_PORT=5678
N8N_PROTOCOL=https
WEBHOOK_URL=
GENERIC_TIMEZONE=America/New_York
N8N_ENCRYPTION_KEY=

#-------------
# Uptime Kuma
#-------------
KUMA_SYNC_USER=
KUMA_SYNC_PASS=

#-------------
# VSCode Code Server
#-------------
CODE_SERVER_PASSWORD=
CODE_SUDO_PASSWORD=
Variable Used By Description
DB_IP Services connecting to the DB stack Hostname of the database containers on mystic-net. Use host.docker.internal for local dev; use the container name (e.g. mystic-postgres) in production.
ADMIN_TOKEN Vaultwarden Hashed admin panel token — generate with argon2 or the Vaultwarden CLI
SMTP_HOST Vaultwarden SMTP server hostname (e.g. smtp.purelymail.com)
SMTP_PORT Vaultwarden SMTP port — default 465 for forced TLS
SMTP_USER Vaultwarden SMTP username / sender address
SMTP_PASS Vaultwarden SMTP password
ENCRYPTION_KEY Pocket-ID Secret key used to encrypt OIDC session tokens
APP_URL Pocket-ID Public base URL of the Pocket-ID instance (e.g. https://auth.corebot.ca)
PIHOLE_PASS Pi-hole Web UI admin password
PURELYMAIL_USER Ghost PurelyMail sender email address
PURELYMAIL_PASS Ghost PurelyMail SMTP password
FORGEJO_DB_PASS Forgejo Password for the forgejo_user PostgreSQL account
FORGEJO_METRICS_TOKEN Forgejo Bearer token to protect the /metrics Prometheus endpoint
GIT_IP Forgejo IP to bind Forgejo's HTTP and SSH ports to (keeps them off the public interface)
RENO_TOKEN Renovate Forgejo personal access token with repo read/write scope
GITHUB_COM_TOKEN Renovate GitHub token used for fetching changelogs from public GitHub packages
IMMICH_VERSION Immich Docker image tag — default release
UPLOAD_LOCATION Immich Host path where uploaded photos and videos are stored
DB_PASSWORD Immich Password for Immich's PostgreSQL user
DB_USERNAME Immich Immich's PostgreSQL username
DB_DATABASE_NAME Immich Immich's PostgreSQL database name
DB_DATA_LOCATION Immich Host path for Immich's PostgreSQL data directory
REDIS_PASSWORD Immich Redis AUTH password — must match REDIS_PASS in the database stack
REDIS_HOSTNAME Immich Container name of the Redis instance (e.g. mystic-redis)
NEXTCLOUD_DB_USER Nextcloud Nextcloud's database username
NEXTCLOUD_DB_PASS Nextcloud Nextcloud's database password
NEXTCLOUD_ADMIN Nextcloud Initial admin account username
NEXTCLOUD_ADMIN_PASS Nextcloud Initial admin account password
GRAFANA_ADMIN_PASSWORD Grafana Password for the built-in admin Grafana account
N8N_HOST n8n Public hostname (e.g. n8n.corebot.ca)
N8N_PORT n8n Internal port n8n listens on — default 5678
N8N_PROTOCOL n8n Protocol for webhook URL generation — https in production
WEBHOOK_URL n8n Full public URL for incoming webhooks (e.g. https://n8n.corebot.ca/)
GENERIC_TIMEZONE n8n TZ identifier for workflow scheduling (e.g. America/New_York)
N8N_ENCRYPTION_KEY n8n Secret key for encrypting stored credentials in n8n
KUMA_SYNC_USER kuma-container-sync Uptime Kuma username for the sync agent
KUMA_SYNC_PASS kuma-container-sync Uptime Kuma password for the sync agent
CODE_SERVER_PASSWORD code-server Password to access the browser-based IDE
CODE_SUDO_PASSWORD code-server Sudo password available in the browser IDE terminal

14. Healthchecks Reference

Every service has a Docker healthcheck. The standard pattern is: 30s interval, 5s timeout, 3 retries.

Service Healthcheck Command Start Period
Pocket-ID /app/pocket-id healthcheck 10s
Vaultwarden curl -f http://localhost:80/alive 20s
Grafana curl -f http://localhost:3000/api/health 30s
Prometheus wget --spider http://localhost:9090/-/healthy
Uptime Kuma node extra/healthcheck.js 10s
NPM curl -f http://localhost:81/ 30s
Consul consul members
Loki NONE (declared but disabled)
Mystic Home curl -f http://localhost/
Mystic Privacy / ToS wget --spider http://localhost/
Ghost pgrep -f node 90s
Forgejo curl -f http://localhost:3000/api/v1/version 60s
Immich Server curl -f http://localhost:2283/api/server-info/ping 90s
Nextcloud curl -f http://localhost/status.php 90s
n8n curl -f http://localhost:5678/healthz 60s
MinIO curl -f http://localhost:9000/minio/health/live

Services using ["CMD", "/bin/true"] as their check (Node Exporter, Docker Exporter, cAdvisor, Promtail, nextcloud-cron, immich-machine-learning, Renovate) have no meaningful HTTP endpoint but are treated as always-healthy by the Docker daemon.


15. Re-Launching Services

Use this section to bring the full stack back up on a fresh server or after downtime.

Prerequisites

Ensure the following are installed on the host:

# Docker Engine + Compose plugin
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER && newgrp docker

Verify the installation:

docker version
docker compose version

Step 1 — Clone the Repo

git clone https://git.corebot.ca/CoreBotLabs/infra.git
cd infra

Step 2 — Create the Shared Docker Network

This must be done once before any stack is started. Both compose files declare mystic-net as external, so Docker will error on startup if it does not exist.

docker network create mystic-net

Step 3 — Create Environment Files

The .env files are not committed to the repo. Create them manually in each stack directory and fill in all required values — refer to Section 13 for a description of every variable.

# Database stack
nano mono/databases/.env

# Master stack
nano mono/master/.env

Step 4 — Launch the Database Stack

The master stack depends on databases being available. Always start mono/databases first.

cd mono/databases
docker compose up -d

Wait for all containers to become healthy (typically within 60 seconds):

docker compose ps

All services should show healthy or running. If any are stuck in starting, check their logs:

docker compose logs <service-name>

Step 5 — Launch the Master Stack

cd ../master
docker compose up -d

Check status:

docker compose ps

Watch startup logs across all services:

docker compose logs -f --tail=50

Key startup ordering enforced by depends_on:

  • consul must pass its healthcheck before loki starts.
  • uptime-kuma must be running before kuma-container-sync starts.

Everything else starts in parallel.

Step 6 — Configure Nginx Proxy Manager

On first launch, NPM uses default credentials:

  • URL: http://<server-ip>:81
  • Default email: admin@example.com
  • Default password: changeme

Log in, change the admin credentials immediately, then add a proxy host for each public domain:

  1. Go to Proxy Hosts → Add Proxy Host
  2. Set Domain Names to the public domain (e.g. git.corebot.ca)
  3. Set Forward Hostname / IP to the container name (e.g. mystic-forgejo)
  4. Set Forward Port to the container's internal port (e.g. 3000)
  5. On the SSL tab, request a Let's Encrypt certificate and enable Force SSL

Repeat for every entry in Section 12.

Step 7 — Verify Services

Spot-check key services directly on the host:

# Forgejo
curl -s http://localhost:3000/api/v1/version

# Prometheus
curl -s http://localhost:9090/-/healthy

# Loki
curl -s http://localhost:3100/ready

# MinIO
curl -s http://localhost:9000/minio/health/live

# Uptime Kuma
curl -s http://localhost:3001

Day-to-Day Operations

Restart a single service:

cd mono/master   # or mono/databases
docker compose restart <service-name>

Pull updated images and redeploy:

cd mono/databases
docker compose pull && docker compose up -d

cd ../master
docker compose pull && docker compose up -d

Tear down a stack (preserves data volumes):

docker compose down

Tear down a stack and delete all volumes — destructive, data loss:

docker compose down -v

docker compose down -v will permanently delete named volumes including prometheus_data and model-cache. Only use this when starting completely fresh.

View logs for a specific service:

docker compose logs -f <service-name>

Check overall container health across both stacks:

docker ps --format "table {{.Names}}\t{{.Status}}"

16. Adding a New Service

  1. Choose the right compose file. Database or storage services belong in mono/databases/docker-compose.yml. Everything else goes in mono/master/docker-compose.yml.

  2. Define the service. Always include networks: - mystic-net. Add a meaningful healthcheck. Store secrets in the stack's .env file and reference them with ${VARIABLE}.

  3. Add Prometheus scraping if the service exposes metrics. Edit mono/master/prometheus/prometheus.yml and add a new entry under scrape_configs.

  4. Configure NPM. Add a proxy host in the NPM admin UI (npm.corebot.ca), pointing to <container-name>:<internal-port>. Enable Let's Encrypt SSL. Update Section 12 in these docs.

  5. Uptime monitoring. kuma-container-sync auto-detects all running containers. Set a kuma.monitor.url Docker label on the container if a specific URL or check path is needed instead of the default.

  6. Register with Komodo if the service needs managed rollouts or rollback. Add it via the Komodo web UI.

  7. Update the home dashboard if the service should appear in the MysticOS dock. See Section 8 for instructions.


Last updated from repo state: 2026-06-22 · commit 6914e013 (feat: add MinIO)