Repository navigation
Expand file tree
/
Copy pathdocker-compose.yml
More file actions
223 lines (210 loc) · 9.3 KB
/
Copy pathdocker-compose.yml
File metadata and controls
223 lines (210 loc) · 9.3 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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
# Local development stack: SurrealDB, the API (hot reload), a job worker, the Next.js frontend and Mailpit (catches the mail).
# cp fastapi_backend/.env.example fastapi_backend/.env (set ACCESS_SECRET_KEY)
# cp nextjs-frontend/.env.example nextjs-frontend/.env.local (set AUTH_SECRET)
# The first-admin setup code is printed in the backend log.
x-backend: &backend
security_opt: ["no-new-privileges:true"] # nothing in Lens needs setuid programs
build:
context: fastapi_backend
target: ${LENS_TARGET:-full} # LibreOffice and Chromium, to read Office files, text, web pages and emails; lean: without
args:
DEV: "true"
EXTRAS: ${EXTRAS:-}
# model servers on this machine (Ollama, LM Studio) as host.docker.internal, on Linux as on a Mac
extra_hosts:
- "host.docker.internal:host-gateway"
env_file:
- path: .env # ARCHIVE_SECRET_KEY: the one native runs use, so both read stored credentials
required: false
- path: fastapi_backend/.env
required: false
environment: &backend-env
ACCESS_SECRET_KEY: ${ACCESS_SECRET_KEY:-dev-only-access-secret-change-me}
SURREAL_URL: ws://surrealdb:8000
SURREAL_USER: ${SURREAL_USER:-root}
SURREAL_PASS: ${SURREAL_PASS:-root}
LENS_NFS_PORT: ${LENS_NFS_PORT:-12049}
ARCHIVE_CONFIG: /app/docker/archive.yaml
RUN_BACKGROUND: "false"
MAIL_SERVER: mail
MAIL_PORT: "1025"
MAIL_FROM: lens@example.com
MAIL_STARTTLS: "False"
USE_CREDENTIALS: "False"
FRONTEND_URL: http://localhost:3000
# where the Cloudflare tunnel (Settings › Remote access) sends visitors: the web app inside this stack
LENS_TUNNEL_ORIGIN: http://frontend:3000
# the web app's container (and the one running the tunnel): their X-Forwarded-For names the visitor, for throttles
LENS_TRUSTED_PROXY_HOSTS: frontend,backend,worker
# the SMB share of the file tree (docs/smb.md): listens on 4445 in the container; LENS_SMB_PORT is where it's
# published, for the address Settings shows
LENS_SMB_LISTEN: 0.0.0.0
LENS_SMB_PORT: ${LENS_SMB_PORT:-1445}
CORS_ORIGINS: '["http://localhost:3000"]'
OPENAPI_OUTPUT_FILE: ./shared-data/openapi.json
# the volume shared with the matterbridge service (its config, written from Settings → Chat rooms)
LENS_MATTERBRIDGE_DIR: /matterbridge
# the MCP runner (the optional `mcp` service, docs/assistant.md): MCP servers that run as a program, sandboxed there
LENS_MCP_RUNNER_URL: http://mcp:8090
LENS_MCP_TOKEN_FILE: /mcp-key/token
volumes:
- ./fastapi_backend:/app
# the image's own packages, not the source tree's: anonymous, so `make dev` (up --build --renew-anon-volumes)
# starts from the rebuilt image's after a dependency changes
- /opt/venv
- archive-data:/data
- ./local-shared-data:/app/shared-data
- ${AUDIO_DIR:-./local-audio}:/audio:ro
- matterbridge-data:/matterbridge
- mcp-key:/mcp-key:ro
depends_on:
surrealdb:
condition: service_healthy
networks: [lens, mcp]
services:
surrealdb:
image: surrealdb/surrealdb:v3.2.4
command: start --log info --user ${SURREAL_USER:-root} --pass ${SURREAL_PASS:-root} surrealkv:/data/lens.db
user: root # the image's default user cannot write to a fresh named volume
ports:
- "127.0.0.1:8001:8000" # lets native workers on this machine (mlx on a Mac) share the database
volumes:
- surreal-data:/data
healthcheck:
test: ["CMD", "/surreal", "is-ready", "--endpoint", "http://localhost:8000"]
interval: 5s
timeout: 3s
retries: 20
networks: [lens]
backend:
<<: *backend
command: ./start.sh
ports:
- "127.0.0.1:8000:8000" # the API, for this machine only (the web app proxies it)
worker:
<<: *backend
command: lens worker
# the sensor hub (docs/sensors.md): MQTT and syslog, listened on only once sensors are turned on in the app.
# Something else on this machine using 1883 or 5514? Set LENS_MQTT_PORT / LENS_SYSLOG_PORT to other ports.
# Only this machine reaches them while developing; LENS_SENSOR_BIND=0.0.0.0 lets devices on the network in.
ports:
- "${LENS_SENSOR_BIND:-127.0.0.1}:${LENS_MQTT_PORT:-1883}:1883"
- "${LENS_SENSOR_BIND:-127.0.0.1}:${LENS_SYSLOG_PORT:-5514}:5514/udp"
- "${LENS_SENSOR_BIND:-127.0.0.1}:${LENS_SYSLOG_PORT:-5514}:5514/tcp"
- "${LENS_SHARE_BIND:-127.0.0.1}:${LENS_NFS_PORT:-12049}:2049" # the file tree over NFS, once turned on
- "${LENS_SHARE_BIND:-127.0.0.1}:${LENS_SMB_PORT:-1445}:4445" # the file tree over SMB, once turned on
# the graph as files over S3 and WebDAV (docs/file-tree.md), once File shares are on; LENS_S3_PORT / LENS_WEBDAV_PORT
- "${LENS_SHARE_BIND:-127.0.0.1}:${LENS_S3_PORT:-9555}:9555"
- "${LENS_SHARE_BIND:-127.0.0.1}:${LENS_WEBDAV_PORT:-9556}:9556"
healthcheck:
disable: true
frontend:
security_opt: ["no-new-privileges:true"]
build:
context: ./nextjs-frontend
user: node
ports:
- "3000:3000"
environment:
NODE_ENV: development
API_BASE_URL: http://backend:8000
AUTH_SECRET: ${AUTH_SECRET:-dev-only-auth-secret-change-me}
AUTH_TRUST_HOST: "true"
# no AUTH_URL: sign-in follows the address the browser is on (its LAN name, https:// address or Cloudflare tunnel)
OPENAPI_OUTPUT_FILE: ./shared-data/openapi.json
volumes:
- ./nextjs-frontend:/app
- /app/node_modules # the image's, renewed with it (see the backend's /opt/venv)
- ./local-shared-data:/app/shared-data
networks: [lens]
# Catches the mail the API sends (password resets, access requests): read it at http://localhost:8025.
# Mailpit has images for arm64 and amd64 (MailHog's is amd64 only).
mail:
image: axllent/mailpit:v1.27
ports:
- "127.0.0.1:1025:1025" # SMTP, for an API run outside Docker (MAIL_SERVER=localhost)
- "127.0.0.1:8025:8025" # the mailbox
networks: [lens]
# Matterbridge run by Lens (docs/chat-rooms.md): the assistant in Slack, Discord, Telegram, Matrix and WhatsApp rooms,
# set up in Settings → Chat rooms → Run Matterbridge here, which writes its config into the volume the two share.
# Opt-in, and it builds Matterbridge from source the first time: `docker compose --profile matterbridge up -d`.
matterbridge:
security_opt: ["no-new-privileges:true"]
image: lens-matterbridge:dev
build: ./matterbridge
profiles: [matterbridge]
volumes:
- matterbridge-data:/matterbridge
networks: [lens]
# Apache Tika (docs/configuration.md#apache-tika): reads the text and description of about a thousand kinds of file where Lens can't make
# them into PDFs itself, and what every document says about itself. Opt-in, about 250 MB of memory:
# `docker compose --profile tika up -d` (or COMPOSE_PROFILES=tika in .env), then Settings → Documents → Tika server:
# http://tika:9998. Reachable only inside Lens's network; it has no sign-in of its own.
tika:
image: apache/tika:${TIKA_VERSION:-4.0.0-1}
profiles: [tika]
security_opt: ["no-new-privileges:true"]
read_only: true
tmpfs: [/tmp]
environment:
JAVA_TOOL_OPTIONS: -Xmx${TIKA_HEAP:-512m}
networks: [lens]
# The MCP runner (mcp-runner/runner.py, docs/assistant.md): MCP servers that run as a program (stdio, usually npx or
# uvx), which admins add as extensions. Opt-in: `docker compose --profile mcp up -d`, or COMPOSE_PROFILES=mcp in .env.
# The sandbox: none of Lens's data or keys, no capabilities, a read-only image, and a network shared only with the
# backend (and the internet).
mcp:
image: lens-mcp:dev
build: ./mcp-runner
profiles: [mcp]
security_opt: ["no-new-privileges:true"]
cap_drop: [ALL]
read_only: true
tmpfs: [/tmp]
mem_limit: 2g
pids_limit: 512
volumes:
- mcp-data:/data
- mcp-key:/key
networks: [mcp]
# StyleTTS2 (docs/speech-providers.md#styletts2): spoken answers and podcasts read on this machine, in a voice like a
# short clip you put in its voices volume. Heavy (PyTorch and a 1 GB model, fetched on first use), so opt-in:
# `docker compose --profile styletts2 up -d`, then Settings → AI assistant → Voice → StyleTTS2.
styletts2:
security_opt: ["no-new-privileges:true"]
image: lens-styletts2:dev
build: ./styletts2
profiles: [styletts2]
volumes:
- styletts2-data:/data
- styletts2-voices:/voices
networks: [lens]
# Fedora 6 (docs/fedora.md), the repository Lens can keep a copy of the archive in. Opt-in, and not needed on small
# machines: `docker compose --profile fedora up`, with LENS_FEDORA_URL=http://fedora:8080/fcrepo/rest (and
# LENS_FEDORA_USER / LENS_FEDORA_PASSWORD) in .env, or set it in Settings → Fedora.
fedora:
image: fcrepo/fcrepo:${FEDORA_VERSION:-6.5.1-tomcat9}
profiles: [fedora]
environment:
CATALINA_OPTS: >-
-Dfcrepo.home=/fcrepo-home -Djava.awt.headless=true -Dfcrepo.autoversioning.enabled=true
ports:
- "127.0.0.1:8081:8080" # its web UI and REST API, for this machine only
volumes:
- fedora-data:/fcrepo-home
networks: [lens]
volumes:
surreal-data:
matterbridge-data:
mcp-data:
mcp-key:
styletts2-data:
styletts2-voices:
archive-data:
fedora-data:
networks:
lens:
driver: bridge
mcp:
driver: bridge