Changed how all docker images have their version set to use the compose repo
This commit is contained in:
1 parent
8020f416dc
commit
0db6fdf16a
15 files changed
+643
-265
No files matched your search
+98
-68
@@ -8,9 +8,12 @@ systemd:
|
||||
contents: |
|
||||
[Unit]
|
||||
Description=Gitea MCP Server
|
||||
After=docker.service
|
||||
After=docker.service versions-fetch.service
|
||||
Wants=versions-fetch.service
|
||||
Requires=docker.service
|
||||
[Service]
|
||||
# Image tag comes from versions.env; see butane/versions-sync.yaml.
|
||||
EnvironmentFile=/etc/versions.env
|
||||
TimeoutStartSec=0
|
||||
ExecStartPre=-/usr/bin/docker rm --force gitea-mcp
|
||||
# The image ships a broken HEALTHCHECK: it is CMD-SHELL form but the
|
||||
@@ -21,7 +24,7 @@ systemd:
|
||||
ExecStart=/usr/bin/docker run --name gitea-mcp --no-healthcheck \
|
||||
-e GITEA_HOST=https://git.atlashorizon.net \
|
||||
-p 8080:8080 \
|
||||
docker.gitea.com/gitea-mcp-server \
|
||||
$${GITEA_MCP_IMAGE} \
|
||||
/app/gitea-mcp -t http --port 8080
|
||||
ExecStop=/usr/bin/docker stop gitea-mcp
|
||||
Restart=always
|
||||
@@ -33,9 +36,12 @@ systemd:
|
||||
contents: |
|
||||
[Unit]
|
||||
Description=LiteLLM proxy
|
||||
After=docker.service
|
||||
After=docker.service versions-fetch.service
|
||||
Wants=versions-fetch.service
|
||||
Requires=docker.service
|
||||
[Service]
|
||||
# Image tag comes from versions.env; see butane/versions-sync.yaml.
|
||||
EnvironmentFile=/etc/versions.env
|
||||
TimeoutStartSec=0
|
||||
ExecStartPre=-/usr/bin/docker rm --force litellm
|
||||
ExecStart=/usr/bin/docker run --name litellm \
|
||||
@@ -47,7 +53,7 @@ systemd:
|
||||
-e JSON_LOGS=True \
|
||||
-v /etc/litellm/config.yaml:/app/config.yaml:ro \
|
||||
-p 4000:4000 \
|
||||
docker.litellm.ai/berriai/litellm:main-stable \
|
||||
$${LITELLM_IMAGE} \
|
||||
--config /app/config.yaml --port 4000
|
||||
ExecStop=/usr/bin/docker stop litellm
|
||||
Restart=always
|
||||
@@ -77,15 +83,18 @@ systemd:
|
||||
contents: |
|
||||
[Unit]
|
||||
Description=Qdrant vector database
|
||||
After=docker.service
|
||||
After=docker.service versions-fetch.service
|
||||
Wants=versions-fetch.service
|
||||
Requires=docker.service
|
||||
[Service]
|
||||
# Image tag comes from versions.env; see butane/versions-sync.yaml.
|
||||
EnvironmentFile=/etc/versions.env
|
||||
TimeoutStartSec=0
|
||||
# Both containers sit on a private docker network and Qdrant publishes
|
||||
# no ports: it ships with no authentication, and nothing outside this
|
||||
# host needs to reach it. Creation is idempotent, hence the "-".
|
||||
ExecStartPre=-/usr/bin/docker network create openwebui
|
||||
ExecStartPre=/usr/bin/docker pull qdrant/qdrant:v1.19.1
|
||||
ExecStartPre=/usr/bin/docker pull $${QDRANT_IMAGE}
|
||||
ExecStartPre=-/usr/bin/docker rm --force qdrant
|
||||
# Vectors live on the VM disk, so a taint destroys them. That is
|
||||
# deliberate -- they are derived data, rebuildable from the source
|
||||
@@ -95,7 +104,7 @@ systemd:
|
||||
ExecStart=/usr/bin/docker run --name qdrant \
|
||||
--network openwebui \
|
||||
-v /var/lib/qdrant:/qdrant/storage \
|
||||
qdrant/qdrant:v1.19.1
|
||||
$${QDRANT_IMAGE}
|
||||
ExecStop=/usr/bin/docker stop qdrant
|
||||
Restart=always
|
||||
RestartSec=5s
|
||||
@@ -119,12 +128,15 @@ systemd:
|
||||
contents: |
|
||||
[Unit]
|
||||
Description=Open Terminal sandbox
|
||||
After=docker.service
|
||||
After=docker.service versions-fetch.service
|
||||
Wants=versions-fetch.service
|
||||
Requires=docker.service
|
||||
[Service]
|
||||
# Image tag comes from versions.env; see butane/versions-sync.yaml.
|
||||
EnvironmentFile=/etc/versions.env
|
||||
TimeoutStartSec=0
|
||||
ExecStartPre=-/usr/bin/docker network create openwebui
|
||||
ExecStartPre=/usr/bin/docker pull ghcr.io/open-webui/open-terminal:0.14.0
|
||||
ExecStartPre=/usr/bin/docker pull $${OPEN_TERMINAL_IMAGE}
|
||||
ExecStartPre=-/usr/bin/docker rm --force open-terminal
|
||||
# A named volume, not a bind mount: /home/user belongs to the image's
|
||||
# unprivileged user, and a named volume inherits that ownership from
|
||||
@@ -135,7 +147,7 @@ systemd:
|
||||
--network openwebui \
|
||||
-v open-terminal:/home/user \
|
||||
-e OPEN_TERMINAL_API_KEY=${openwebui_terminal_api_key} \
|
||||
ghcr.io/open-webui/open-terminal:0.14.0
|
||||
$${OPEN_TERMINAL_IMAGE}
|
||||
ExecStop=/usr/bin/docker stop open-terminal
|
||||
Restart=always
|
||||
RestartSec=5s
|
||||
@@ -148,13 +160,16 @@ systemd:
|
||||
Description=Open WebUI
|
||||
# After= orders the start only, it does not wait for Qdrant to be
|
||||
# serving. Restart=always covers the gap if Qdrant is still coming up.
|
||||
After=docker.service litellm.service qdrant.service open-terminal.service
|
||||
After=docker.service litellm.service qdrant.service open-terminal.service versions-fetch.service
|
||||
Wants=versions-fetch.service
|
||||
Requires=docker.service
|
||||
[Service]
|
||||
# Image tag comes from versions.env; see butane/versions-sync.yaml.
|
||||
EnvironmentFile=/etc/versions.env
|
||||
TimeoutStartSec=0
|
||||
# Large image, so it is pulled up front: a slow first pull is then not
|
||||
# mistaken for a hung unit.
|
||||
ExecStartPre=/usr/bin/docker pull ghcr.io/open-webui/open-webui:v0.11.4
|
||||
ExecStartPre=/usr/bin/docker pull $${OPEN_WEBUI_IMAGE}
|
||||
ExecStartPre=-/usr/bin/docker network create openwebui
|
||||
ExecStartPre=-/usr/bin/docker rm --force open-webui
|
||||
# No volume is mounted. Every piece of durable state lives off-box --
|
||||
@@ -193,50 +208,64 @@ systemd:
|
||||
-e OAUTH_PICTURE_CLAIM=avatar \
|
||||
-e "OAUTH_SCOPES=openid email profile groups avatar" \
|
||||
-e OAUTH_MERGE_ACCOUNTS_BY_EMAIL=true \
|
||||
-e CORS_ALLOW_ORIGIN=https://llm.atlashorizon.net \
|
||||
-e WEBUI_URL=https://llm.atlashorizon.net \
|
||||
-e 'TERMINAL_SERVER_CONNECTIONS=[{"id":"local","name":"Open Terminal","url":"http://open-terminal:8000","key":"${openwebui_terminal_api_key}","auth_type":"bearer","enabled":true}]' \
|
||||
-p 3000:8080 \
|
||||
ghcr.io/open-webui/open-webui:v0.11.4
|
||||
$${OPEN_WEBUI_IMAGE}
|
||||
ExecStop=/usr/bin/docker stop open-webui
|
||||
Restart=always
|
||||
RestartSec=5s
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
# OpenCode headless server for n8n (and anything else on the LAN).
|
||||
# OpenCode, run headless as a coding agent that n8n drives over HTTP.
|
||||
#
|
||||
# Prerequisites:
|
||||
# - OPENCODE_SERVER_PASSWORD in Infisical (see secrets.tmpl)
|
||||
# - model keys in /etc/opencode/opencode.json matching LiteLLM
|
||||
# model_name values (Admin UI or GET /v1/models). Models live in
|
||||
# the LiteLLM database, so this file cannot discover them.
|
||||
# Prerequisites, all of which must exist before the VM is rebuilt:
|
||||
# - OPENCODE_SERVER_PASSWORD in Infisical (see secrets.tmpl). Every
|
||||
# Butane file is rendered on every plan, so until the secret exists
|
||||
# no plan succeeds -- not just this VM's
|
||||
# - each model listed in /etc/opencode/opencode.json (below) defined
|
||||
# in LiteLLM under the same model_name
|
||||
#
|
||||
# Listens on :4096 with HTTP Basic Auth (user "opencode"). n8n on
|
||||
# oswald-runner reaches it at http://192.168.7.61:4096 -- install the
|
||||
# n8n-nodes-opencode-ai community package, or use HTTP Request nodes
|
||||
# against the OpenAPI at /doc. LLM calls go through LiteLLM on :4000
|
||||
# using the same host-IP pattern as Open WebUI.
|
||||
# Unlike Open Terminal, this publishes a port: n8n runs on oswald-runner,
|
||||
# so the private "openwebui" network is out of its reach. That leaves HTTP
|
||||
# Basic Auth (user "opencode") as the only thing between the LAN and an
|
||||
# agent with a shell, and over plain HTTP. The agent runs as root inside
|
||||
# the container, with the same outbound network access as Open Terminal.
|
||||
#
|
||||
# From n8n: http://192.168.7.61:4096, with the n8n-nodes-opencode-ai
|
||||
# community node or HTTP Request nodes (the OpenAPI spec is at /doc).
|
||||
- name: opencode.service
|
||||
enabled: true
|
||||
contents: |
|
||||
[Unit]
|
||||
Description=OpenCode server
|
||||
After=docker.service litellm.service
|
||||
After=docker.service litellm.service versions-fetch.service
|
||||
Wants=versions-fetch.service
|
||||
Requires=docker.service
|
||||
[Service]
|
||||
# Image tag comes from versions.env; see butane/versions-sync.yaml.
|
||||
EnvironmentFile=/etc/versions.env
|
||||
TimeoutStartSec=0
|
||||
ExecStartPre=/usr/bin/docker pull ghcr.io/anomalyco/opencode:1.18.32
|
||||
ExecStartPre=/usr/bin/docker pull $${OPENCODE_IMAGE}
|
||||
ExecStartPre=-/usr/bin/docker rm --force opencode
|
||||
# /var/lib/opencode is the project workspace the agent edits. It
|
||||
# survives container restarts; a VM taint wipes it (scratch space).
|
||||
# Both directories are on the VM disk, so they survive container
|
||||
# restarts but not a taint. workspace is what the agent edits; data
|
||||
# holds its sessions, which n8n refers to by id across executions.
|
||||
#
|
||||
# The LiteLLM key is passed in the environment and read by the config
|
||||
# file as {env:LITELLM_API_KEY}, which keeps the file free of secrets.
|
||||
ExecStart=/usr/bin/docker run --name opencode \
|
||||
-e OPENCODE_SERVER_USERNAME=opencode \
|
||||
-e OPENCODE_SERVER_PASSWORD=${opencode_server_password} \
|
||||
-e LITELLM_API_KEY=${litellm_master_key} \
|
||||
-e OPENCODE_CONFIG=/etc/opencode/opencode.json \
|
||||
-v /etc/opencode/opencode.json:/etc/opencode/opencode.json:ro \
|
||||
-v /var/lib/opencode:/workspace \
|
||||
-v /var/lib/opencode/workspace:/workspace \
|
||||
-v /var/lib/opencode/data:/root/.local/share/opencode \
|
||||
-w /workspace \
|
||||
-p 4096:4096 \
|
||||
ghcr.io/anomalyco/opencode:1.18.32 \
|
||||
$${OPENCODE_IMAGE} \
|
||||
serve --hostname 0.0.0.0 --port 4096
|
||||
ExecStop=/usr/bin/docker stop opencode
|
||||
Restart=always
|
||||
@@ -267,15 +296,18 @@ systemd:
|
||||
contents: |
|
||||
[Unit]
|
||||
Description=Dozzle Agent
|
||||
After=docker.service
|
||||
After=docker.service versions-fetch.service
|
||||
Wants=versions-fetch.service
|
||||
Requires=docker.service
|
||||
[Service]
|
||||
# Image tag comes from versions.env; see butane/versions-sync.yaml.
|
||||
EnvironmentFile=/etc/versions.env
|
||||
TimeoutStartSec=0
|
||||
ExecStartPre=-/usr/bin/docker rm --force dozzle-agent
|
||||
ExecStart=/usr/bin/docker run --name dozzle-agent \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
-p 7007:7007 \
|
||||
amir20/dozzle:v11.1.1 agent
|
||||
$${DOZZLE_IMAGE} agent
|
||||
ExecStop=/usr/bin/docker stop dozzle-agent
|
||||
Restart=always
|
||||
RestartSec=5s
|
||||
@@ -289,29 +321,13 @@ storage:
|
||||
# root-owned 0700 directory is what it expects.
|
||||
- path: /var/lib/qdrant
|
||||
mode: 0700
|
||||
# OpenCode project workspace. Scratch space: survives container
|
||||
# restarts, not a VM taint.
|
||||
- path: /var/lib/opencode
|
||||
mode: 0755
|
||||
- path: /etc/opencode
|
||||
# OpenCode's workspace and session store; see opencode.service. The
|
||||
# image runs as root.
|
||||
- path: /var/lib/opencode/workspace
|
||||
mode: 0755
|
||||
- path: /var/lib/opencode/data
|
||||
mode: 0700
|
||||
files:
|
||||
# LiteLLM proxy settings. Models stay in the database
|
||||
# (STORE_MODEL_IN_DB), so this file carries general_settings only --
|
||||
# those have no environment equivalent and are readable only from a
|
||||
# config file.
|
||||
#
|
||||
# Requests reach :4000 through a Cloudflare tunnel whose connector runs
|
||||
# on 192.168.0.0/24, so every request arrives from that connector's
|
||||
# address. Without use_x_forwarded_for LiteLLM does MCP access control
|
||||
# against that peer, which sits inside the default internal ranges, and
|
||||
# so treats every caller on the public internet as internal -- exposing
|
||||
# MCP servers marked "available_on_public_internet: false".
|
||||
#
|
||||
# mcp_trusted_proxy_ranges is what keeps that safe: X-Forwarded-For is
|
||||
# honoured only when the direct peer is the connector, so a crafted
|
||||
# header from anywhere else cannot forge a client IP. Widen it if the
|
||||
# tunnel ever moves off that subnet, or the header is ignored again.
|
||||
# Companion to openwebui-reindex.service above.
|
||||
#
|
||||
# Note on quoting: templatefile() substitutes on raw text, so shell
|
||||
@@ -356,6 +372,22 @@ storage:
|
||||
echo "Qdrant empty; reindexing knowledge bases"
|
||||
curl -fsS -X POST -H "Authorization: Bearer $OWUI_KEY" \
|
||||
"$OWUI/api/v1/knowledge/reindex"
|
||||
# LiteLLM proxy settings. Models stay in the database
|
||||
# (STORE_MODEL_IN_DB), so this file carries general_settings only --
|
||||
# those have no environment equivalent and are readable only from a
|
||||
# config file.
|
||||
#
|
||||
# Requests reach :4000 through a Cloudflare tunnel whose connector runs
|
||||
# on 192.168.0.0/24, so every request arrives from that connector's
|
||||
# address. Without use_x_forwarded_for LiteLLM does MCP access control
|
||||
# against that peer, which sits inside the default internal ranges, and
|
||||
# so treats every caller on the public internet as internal -- exposing
|
||||
# MCP servers marked "available_on_public_internet: false".
|
||||
#
|
||||
# mcp_trusted_proxy_ranges is what keeps that safe: X-Forwarded-For is
|
||||
# honoured only when the direct peer is the connector, so a crafted
|
||||
# header from anywhere else cannot forge a client IP. Widen it if the
|
||||
# tunnel ever moves off that subnet, or the header is ignored again.
|
||||
- path: /etc/litellm/config.yaml
|
||||
mode: 0644
|
||||
contents:
|
||||
@@ -364,35 +396,33 @@ storage:
|
||||
use_x_forwarded_for: true
|
||||
mcp_trusted_proxy_ranges:
|
||||
- 192.168.0.0/24
|
||||
# OpenCode provider config. LiteLLM is an OpenAI-compatible proxy, so
|
||||
# we use @ai-sdk/openai-compatible rather than a first-party provider.
|
||||
# OpenCode's provider config. LiteLLM speaks the OpenAI API, so it is
|
||||
# wired in through @ai-sdk/openai-compatible.
|
||||
#
|
||||
# Model keys under "models" must match LiteLLM model_name values exactly
|
||||
# (they are stored in the LiteLLM DB, not in litellm/config.yaml). Edit
|
||||
# this list to match what /v1/models returns, then taint the VM -- or
|
||||
# PATCH http://192.168.7.61:4096/config at runtime. The default model
|
||||
# below is the first key; change "model" when you change the set.
|
||||
#
|
||||
# apiKey is templated from Infisical (LITELLM_MASTER_KEY). Ignition
|
||||
# snippets are plaintext on the node -- same caveat as the other units.
|
||||
# Model keys must match LiteLLM model_name values exactly. Those live in
|
||||
# the LiteLLM database, not in a file here, so check GET :4000/v1/models
|
||||
# when changing this list. "model" is the default for new sessions.
|
||||
- path: /etc/opencode/opencode.json
|
||||
mode: 0600
|
||||
mode: 0644
|
||||
contents:
|
||||
inline: |
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"model": "litellm/claude-sonnet-4",
|
||||
"model": "litellm/claude-sonnet-5",
|
||||
"provider": {
|
||||
"litellm": {
|
||||
"npm": "@ai-sdk/openai-compatible",
|
||||
"name": "LiteLLM",
|
||||
"options": {
|
||||
"baseURL": "http://192.168.7.61:4000/v1",
|
||||
"apiKey": "${litellm_master_key}"
|
||||
"apiKey": "{env:LITELLM_API_KEY}"
|
||||
},
|
||||
"models": {
|
||||
"claude-sonnet-4": {
|
||||
"name": "Claude Sonnet 4"
|
||||
"claude-sonnet-5": {
|
||||
"name": "Claude Sonnet 5"
|
||||
},
|
||||
"qwen3:4b-instruct": {
|
||||
"name": "Qwen3 4B Instruct"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user