- HTML 86.2%
- CSS 12.8%
- JavaScript 0.6%
- Dockerfile 0.4%
| mono | ||
| .DS_Store | ||
| .gitignore | ||
| AGENTS.md | ||
| README.md | ||
| renovate.json | ||
| SETUP.md | ||
CoreBotLabs — Infrastructure Documentation
Repo:
git.corebot.ca/CoreBotLabs/infra
Stack: Docker Compose · Nginx Proxy Manager · Komodo
Table of Contents
- Overview
- Repository Layout
- Server
- Networking & Access
- Service Catalogue
- Monitoring & Observability
- Logging Pipeline
- MysticOS — Internal Home Dashboard
- Legal Pages
- Dependency Management (Renovate)
- Infrastructure Management (Komodo)
- Domain Map
- Environment Variables Reference
- Healthchecks Reference
- Re-Launching Services
- 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:
- Internal tooling — Git hosting, monitoring, password management, DNS, and automation for the CoreBot Labs team.
- 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 —masteranddatabases— that both run on the same host and communicate via the sharedmystic-netDocker 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
80and443are bound to the public interface for HTTP/HTTPS traffic. - Port
81hosts 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 healthcheckbinary (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_PASSover 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/diskread-only.
Loki
- Image:
grafana/loki:3.7.1 - Purpose: Log aggregation backend, queried by Grafana.
- Port:
3100 - Depends on
consulbeing 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/dataand/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.htmland./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, userforgejo_user, passwordFORGEJO_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) andmystic-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-cronsidecar (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
27017is bound to127.0.0.1only — 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 →
containerlabel (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 (
#0d1117background,#58a6ffaccent). - 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.
9. Legal Pages
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.caunder 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
- Hosted as a container in the master stack, port
9120 - API Docs: https://docs.rs/komodo_client/latest/komodo_client/api/index.html
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:
consulmust pass its healthcheck beforelokistarts.uptime-kumamust be running beforekuma-container-syncstarts.
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:
- Go to Proxy Hosts → Add Proxy Host
- Set Domain Names to the public domain (e.g.
git.corebot.ca) - Set Forward Hostname / IP to the container name (e.g.
mystic-forgejo) - Set Forward Port to the container's internal port (e.g.
3000) - 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 -vwill permanently delete named volumes includingprometheus_dataandmodel-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
-
Choose the right compose file. Database or storage services belong in
mono/databases/docker-compose.yml. Everything else goes inmono/master/docker-compose.yml. -
Define the service. Always include
networks: - mystic-net. Add a meaningfulhealthcheck. Store secrets in the stack's.envfile and reference them with${VARIABLE}. -
Add Prometheus scraping if the service exposes metrics. Edit
mono/master/prometheus/prometheus.ymland add a new entry underscrape_configs. -
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. -
Uptime monitoring.
kuma-container-syncauto-detects all running containers. Set akuma.monitor.urlDocker label on the container if a specific URL or check path is needed instead of the default. -
Register with Komodo if the service needs managed rollouts or rollback. Add it via the Komodo web UI.
-
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)