-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathdocker-compose.yml
More file actions
104 lines (98 loc) · 4.7 KB
/
Copy pathdocker-compose.yml
File metadata and controls
104 lines (98 loc) · 4.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# ram — Random Agents Memories
# Central shared-brain MCP server + Cloudflare Tunnel ingress.
# See the "Design rationale" section of README.md for the full rationale.
#
# markdown-vault-mcp : the MCP server (managed git, FastEmbed, HTTP transport)
# cloudflared : Cloudflare Tunnel (Method B, locally-managed config)
#
# No container publishes ports to the host. The ONLY ingress is via cloudflared.
name: ram-brain
services:
markdown-vault-mcp:
image: ghcr.io/pvliesdonk/markdown-vault-mcp:latest
restart: unless-stopped
# FastEmbed/onnxruntime sizes its thread pool to the core count, so the
# boot-time reindex pins ALL cores (~800% on the 8-core host) for as long as
# it takes to re-embed whatever changed since the last boot — right when the
# other 30+ containers on that host are starting too. Capped at 2 cores, with
# a low share so it yields under contention. The embed job is background:
# the server accepts requests ~6s after start regardless, so a slower
# catch-up costs nothing visible.
cpus: "2.0"
cpu_shares: 256
# Named volumes arrive root-owned, and the image's own entrypoint fixes only
# /data, never /vault — so a fresh vault-data volume would make the managed
# `git clone` die with "Permission denied". This wrapper runs FIRST, as root
# (the image sets no USER; it drops to appuser itself via gosu at the end of
# docker-entrypoint.sh), chowns /vault only when it is still root-owned, then
# hands over to the stock entrypoint unchanged. Used to be a separate
# one-shot `init-perms` service, which left an Exited container lying around
# in every container list. UID/GID mirror the entrypoint's own PUID/PGID
# defaults, so `user:`-less installs stay consistent.
entrypoint:
- sh
- -c
- |
if [ "$$(stat -c %u /vault)" = 0 ]; then
chown -R "$${PUID:-1000}:$${PGID:-1000}" /vault
fi
exec /usr/local/bin/docker-entrypoint.sh "$$@"
- --
# The app only reads instructions from MARKDOWN_VAULT_MCP_INSTRUCTIONS (env), so
# inject the editable ./instructions.md into it before exec'ing the server.
# ($$ becomes $ after compose interpolation → the shell runs $(cat ...).)
command:
- sh
- -c
- export MARKDOWN_VAULT_MCP_INSTRUCTIONS="$$(cat /etc/ram/instructions.md)"; exec markdown-vault-mcp serve --transport http --host 0.0.0.0 --port 8000
env_file:
- .env
volumes:
- vault-data:/vault # git-managed vault clone (persistent)
- app-data:/data # FTS index + embeddings + session state (NOT in git)
- ./instructions.md:/etc/ram/instructions.md:ro # editable server instructions
networks:
- brain
# NOTE: intentionally no `ports:` — reachable only through cloudflared.
cloudflared:
image: cloudflare/cloudflared:latest
restart: unless-stopped
# Two public hostnames now share this one tunnel, so a single TUNNEL_URL
# origin no longer suffices — routing is done by ingress rules in
# ./cloudflared/config.yml (ram.* → mcp, auth.* → authelia). Credentials
# still come from the environment; only ingress moved into a file.
# CF_TUNNEL_ID which tunnel to run (.env), passed to `run <ID>`
# TUNNEL_CRED_CONTENTS tunnel credentials JSON, inline (.env)
# config.yml per-hostname ingress (mounted; gitignored real file)
# The public hostnames live in Cloudflare DNS + config.yml, not in compose.
command: tunnel --no-autoupdate --config /etc/cloudflared/config.yml run ${CF_TUNNEL_ID:?set CF_TUNNEL_ID in .env}
environment:
TUNNEL_CRED_CONTENTS: ${TUNNEL_CRED_CONTENTS:?set TUNNEL_CRED_CONTENTS in .env}
volumes:
- ./cloudflared/config.yml:/etc/cloudflared/config.yml:ro
depends_on:
- markdown-vault-mcp
- authelia
networks:
- brain
# OIDC identity provider for the OAuth (oidc-proxy) login path. Reachable only
# through cloudflared at <AUTH_DOMAIN> — no `ports:`. Config is mounted
# read-only; all mutable state (SQLite + notifications) is on the authelia-data
# named volume so the CD runner's `git clean` can't wipe it.
authelia:
image: authelia/authelia:latest
restart: unless-stopped
volumes:
- ./authelia/configuration.yml:/config/configuration.yml:ro
- ./authelia/users_database.yml:/config/users_database.yml:ro
- authelia-data:/var/lib/authelia
networks:
- brain
# NOTE: intentionally no `ports:` — reachable only through cloudflared.
networks:
brain:
driver: bridge
volumes:
vault-data:
app-data:
authelia-data: # Authelia SQLite + notifications (must persist across CD git clean)