Deploy with root docker-compose files, like the other repos
docker-compose.yml runs HODA on the main host, published on one address (10.20.30.10:10040 in .env.example) for the Pangolin resource. The agent settings are optional, so a single host needs nothing else. docker-compose.agent.yml is for a second Docker host. Both follow FiMa's layout: required values fail with a clear message, pull_policy always, memory limits, capped logs, a read-only root filesystem. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
9d6a921c34
commit
c58cc329b0
9 files changed
+200
-85
No files matched your search
+1
-1
@@ -1,6 +1,6 @@
|
||||
.git
|
||||
.gitea
|
||||
deploy
|
||||
docker-compose*.yml
|
||||
data
|
||||
*.md
|
||||
.env
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
# HODA on a second Docker host (the agent). Copy to .env next to docker-compose.agent.yml.
|
||||
# The main host then sets HODA_AGENT_URL=http://<HODA_AGENT_BIND_IP>:<HODA_AGENT_PORT>.
|
||||
|
||||
# Secret shared with the main host: the same value as its HODA_PEER_TOKEN.
|
||||
HODA_PEER_TOKEN=
|
||||
|
||||
# This host's LAN IP. The agent's port is published on it only, e.g. 10.20.30.11
|
||||
HODA_AGENT_BIND_IP=
|
||||
|
||||
# Port the main host reaches the agent on.
|
||||
HODA_AGENT_PORT=8081
|
||||
|
||||
# Name of this host on tiles and in search.
|
||||
HODA_NODE_NAME=host-2
|
||||
|
||||
# Image tag: latest, a release such as 1.0.0, or a build such as sha-9d6a921.
|
||||
HODA_TAG=latest
|
||||
|
||||
# Bind-mount the icon cache to a host directory instead of a named volume
|
||||
# (sudo chown -R 65532:65532 the directory first).
|
||||
# HODA_DATA_DIR=/home/msemes/AppData/hoda-agent
|
||||
|
||||
# debug logs every icon lookup.
|
||||
HODA_LOG_LEVEL=info
|
||||
@@ -0,0 +1,31 @@
|
||||
# HODA on the main host. Copy to .env next to docker-compose.yml.
|
||||
|
||||
# Where HODA listens, and where the Pangolin resource for apps.mariosem.es points:
|
||||
# http://10.20.30.10:10040. Use 127.0.0.1 to keep it off the LAN when Pangolin runs on this host.
|
||||
HODA_BIND_IP=10.20.30.10
|
||||
HODA_PORT=10040
|
||||
|
||||
# Name of this host on tiles and in search.
|
||||
HODA_NODE_NAME=main
|
||||
|
||||
# Page header and browser tab title.
|
||||
HODA_TITLE=apps.mariosem.es
|
||||
|
||||
# --- Only with a second Docker host (it runs docker-compose.agent.yml) -------------------
|
||||
# Leave both empty while there is one host.
|
||||
# The agent's address on the second host: http://<its HODA_AGENT_BIND_IP>:<its HODA_AGENT_PORT>,
|
||||
# e.g. http://10.20.30.11:8081
|
||||
HODA_AGENT_URL=
|
||||
# Secret the two hosts share, the same value on both: openssl rand -hex 32
|
||||
HODA_PEER_TOKEN=
|
||||
# ----------------------------------------------------------------------------------------
|
||||
|
||||
# Image tag: latest, a release such as 1.0.0, or a build such as sha-9d6a921.
|
||||
HODA_TAG=latest
|
||||
|
||||
# Bind-mount the icon cache to a host directory instead of a named volume
|
||||
# (sudo chown -R 65532:65532 the directory first).
|
||||
# HODA_DATA_DIR=/home/msemes/AppData/hoda
|
||||
|
||||
# debug logs every icon lookup.
|
||||
HODA_LOG_LEVEL=info
|
||||
@@ -5,6 +5,7 @@
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
!.env.agent.example
|
||||
|
||||
# local builds
|
||||
/hoda
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
# Copy to .env next to each compose.yml. Both hosts need the same token;
|
||||
# generate one with: openssl rand -hex 32
|
||||
HODA_PEER_TOKEN=
|
||||
# Pin a version instead of latest, e.g. 1.0.0 or sha-abc1234.
|
||||
HODA_TAG=latest
|
||||
@@ -1,34 +0,0 @@
|
||||
# HODA agent, on Docker host 2. Reports this host's labeled apps and their icons
|
||||
# to the primary on host 1; it serves no dashboard of its own.
|
||||
#
|
||||
# Set HODA_PEER_TOKEN in a .env file next to this one (the same value as on host 1),
|
||||
# and replace <host-2-lan-ip> so the port is only reachable on the LAN.
|
||||
services:
|
||||
hoda-agent:
|
||||
image: git.mariosem.es/msemes/hoda:${HODA_TAG:-latest}
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
MODE: agent
|
||||
DOCKER_HOST: tcp://socket-proxy:2375
|
||||
NODE_NAME: host-2
|
||||
PEER_TOKEN: ${HODA_PEER_TOKEN:?set HODA_PEER_TOKEN in .env}
|
||||
volumes:
|
||||
- hoda-data:/data
|
||||
ports:
|
||||
- "<host-2-lan-ip>:8081:8080"
|
||||
depends_on:
|
||||
- socket-proxy
|
||||
|
||||
# Read-only Docker API: container lists and events, nothing else.
|
||||
socket-proxy:
|
||||
image: tecnativa/docker-socket-proxy
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
CONTAINERS: 1
|
||||
EVENTS: 1
|
||||
POST: 0
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
|
||||
volumes:
|
||||
hoda-data:
|
||||
@@ -1,45 +0,0 @@
|
||||
# HODA primary, on Docker host 1. Serves apps.mariosem.es through Pangolin and
|
||||
# merges in the apps the agent on host 2 reports.
|
||||
#
|
||||
# Set HODA_PEER_TOKEN in a .env file next to this one (the same value as on host 2),
|
||||
# and replace <host-2-lan-ip>. There is no published port: Pangolin reaches hoda:8080
|
||||
# over a Docker network it shares with this stack. Create the apps.mariosem.es
|
||||
# resource in the Pangolin UI with SSO on, or keep the pangolin.* labels below if
|
||||
# Pangolin's site connector reads this host's Docker labels.
|
||||
services:
|
||||
hoda:
|
||||
image: git.mariosem.es/msemes/hoda:${HODA_TAG:-latest}
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
MODE: primary
|
||||
DOCKER_HOST: tcp://socket-proxy:2375
|
||||
DASHBOARD_TITLE: apps.mariosem.es
|
||||
NODE_NAME: host-1
|
||||
PEERS: http://<host-2-lan-ip>:8081
|
||||
PEER_TOKEN: ${HODA_PEER_TOKEN:?set HODA_PEER_TOKEN in .env}
|
||||
volumes:
|
||||
- hoda-data:/data
|
||||
depends_on:
|
||||
- socket-proxy
|
||||
labels:
|
||||
pangolin.public-resources.hoda.name: HODA
|
||||
pangolin.public-resources.hoda.mode: http
|
||||
pangolin.public-resources.hoda.full-domain: apps.mariosem.es
|
||||
pangolin.public-resources.hoda.auth.sso-enabled: "true"
|
||||
pangolin.public-resources.hoda.targets[0].method: http
|
||||
pangolin.public-resources.hoda.targets[0].hostname: hoda
|
||||
pangolin.public-resources.hoda.targets[0].port: "8080"
|
||||
|
||||
# Read-only Docker API: container lists and events, nothing else.
|
||||
socket-proxy:
|
||||
image: tecnativa/docker-socket-proxy
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
CONTAINERS: 1
|
||||
EVENTS: 1
|
||||
POST: 0
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
|
||||
volumes:
|
||||
hoda-data:
|
||||
@@ -0,0 +1,68 @@
|
||||
# HODA — a second Docker host, the agent: reports this host's labeled apps and their icons to
|
||||
# the dashboard on the main host (docker-compose.yml). It serves no dashboard of its own, and a
|
||||
# setup with one host doesn't need it.
|
||||
#
|
||||
# Usage:
|
||||
# cp .env.agent.example .env # then set HODA_PEER_TOKEN and HODA_AGENT_BIND_IP
|
||||
# docker compose -f docker-compose.agent.yml pull
|
||||
# docker compose -f docker-compose.agent.yml up -d
|
||||
#
|
||||
# The main host's HODA_AGENT_URL must point here: http://<HODA_AGENT_BIND_IP>:<HODA_AGENT_PORT>,
|
||||
# with the same HODA_PEER_TOKEN.
|
||||
|
||||
name: hoda-agent
|
||||
|
||||
x-logging: &logging
|
||||
driver: json-file
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
|
||||
services:
|
||||
hoda-agent:
|
||||
image: git.mariosem.es/msemes/hoda:${HODA_TAG:-latest}
|
||||
container_name: hoda-agent
|
||||
restart: unless-stopped
|
||||
# `:latest` is mutable; `always` makes `docker compose up -d` check the registry for a newer
|
||||
# image. If you pin HODA_TAG to a fixed tag, `missing` is enough.
|
||||
pull_policy: always
|
||||
depends_on:
|
||||
- socket-proxy
|
||||
environment:
|
||||
MODE: agent
|
||||
DOCKER_HOST: tcp://socket-proxy:2375
|
||||
NODE_NAME: ${HODA_NODE_NAME:-host-2}
|
||||
PEER_TOKEN: ${HODA_PEER_TOKEN:?HODA_PEER_TOKEN must be set in .env (the same value as on the main host).}
|
||||
LOG_LEVEL: ${HODA_LOG_LEVEL:-info}
|
||||
ports:
|
||||
# Published on the LAN IP only, and every request needs the peer token as well.
|
||||
- "${HODA_AGENT_BIND_IP:?HODA_AGENT_BIND_IP must be set in .env to this host's LAN IP (e.g. 10.20.30.11).}:${HODA_AGENT_PORT:-8081}:8080"
|
||||
volumes:
|
||||
# Icon cache. Set HODA_DATA_DIR to bind-mount a host directory instead of the named volume;
|
||||
# it must be owned by the image's user first: sudo chown -R 65532:65532 /path/to/dir
|
||||
- ${HODA_DATA_DIR:-hoda_data}:/data
|
||||
# The binary only writes to /data, and needs no privileges.
|
||||
read_only: true
|
||||
cap_drop: [ALL]
|
||||
security_opt: ["no-new-privileges:true"]
|
||||
mem_limit: 128m
|
||||
cpus: 0.5
|
||||
logging: *logging
|
||||
|
||||
# Read-only Docker API for HODA: container lists and events, nothing else. No published port.
|
||||
socket-proxy:
|
||||
image: tecnativa/docker-socket-proxy:latest
|
||||
container_name: hoda-agent-socket-proxy
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
CONTAINERS: 1
|
||||
EVENTS: 1
|
||||
POST: 0
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
mem_limit: 64m
|
||||
logging: *logging
|
||||
|
||||
volumes:
|
||||
# Fallback when HODA_DATA_DIR is unset; a no-op if /data is bind-mounted to a host path.
|
||||
hoda_data:
|
||||
@@ -0,0 +1,75 @@
|
||||
# HODA — the main host: serves the dashboard of every labeled app on this host's Docker.
|
||||
#
|
||||
# Usage:
|
||||
# cp .env.example .env # the defaults fit the main host
|
||||
# docker compose pull # grab the latest image from the Gitea registry
|
||||
# docker compose up -d
|
||||
#
|
||||
# Point the Pangolin resource for apps.mariosem.es at http://HODA_BIND_IP:HODA_PORT
|
||||
# (http://10.20.30.10:10040 with .env.example) and turn SSO on: HODA has no login of its own.
|
||||
#
|
||||
# One host needs nothing else. A second Docker host runs docker-compose.agent.yml, and this
|
||||
# host then gets HODA_AGENT_URL and HODA_PEER_TOKEN in .env to pull that host's apps.
|
||||
#
|
||||
# The image is built and published by .gitea/workflows/ci.yml.
|
||||
|
||||
name: hoda
|
||||
|
||||
x-logging: &logging
|
||||
driver: json-file
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
|
||||
services:
|
||||
hoda:
|
||||
image: git.mariosem.es/msemes/hoda:${HODA_TAG:-latest}
|
||||
container_name: hoda
|
||||
restart: unless-stopped
|
||||
# `:latest` is mutable; `always` makes `docker compose up -d` check the registry for a newer
|
||||
# image. If you pin HODA_TAG to a fixed tag, `missing` is enough.
|
||||
pull_policy: always
|
||||
depends_on:
|
||||
- socket-proxy
|
||||
environment:
|
||||
MODE: primary
|
||||
DOCKER_HOST: tcp://socket-proxy:2375
|
||||
NODE_NAME: ${HODA_NODE_NAME:-host-1}
|
||||
DASHBOARD_TITLE: ${HODA_TITLE:-apps.mariosem.es}
|
||||
# Only with a second host: its agent's URL and the token both hosts share. HODA refuses to
|
||||
# start with an agent URL but no token.
|
||||
PEERS: ${HODA_AGENT_URL:-}
|
||||
PEER_TOKEN: ${HODA_PEER_TOKEN:-}
|
||||
LOG_LEVEL: ${HODA_LOG_LEVEL:-info}
|
||||
ports:
|
||||
# Published on one address only: loopback by default, or the LAN IP Pangolin reaches.
|
||||
- "${HODA_BIND_IP:-127.0.0.1}:${HODA_PORT:-8090}:8080"
|
||||
volumes:
|
||||
# Icon cache. Set HODA_DATA_DIR to bind-mount a host directory instead of the named volume;
|
||||
# it must be owned by the image's user first: sudo chown -R 65532:65532 /path/to/dir
|
||||
- ${HODA_DATA_DIR:-hoda_data}:/data
|
||||
# The binary only writes to /data, and needs no privileges.
|
||||
read_only: true
|
||||
cap_drop: [ALL]
|
||||
security_opt: ["no-new-privileges:true"]
|
||||
mem_limit: 128m
|
||||
cpus: 0.5
|
||||
logging: *logging
|
||||
|
||||
# Read-only Docker API for HODA: container lists and events, nothing else. No published port.
|
||||
socket-proxy:
|
||||
image: tecnativa/docker-socket-proxy:latest
|
||||
container_name: hoda-socket-proxy
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
CONTAINERS: 1
|
||||
EVENTS: 1
|
||||
POST: 0
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
mem_limit: 64m
|
||||
logging: *logging
|
||||
|
||||
volumes:
|
||||
# Fallback when HODA_DATA_DIR is unset; a no-op if /data is bind-mounted to a host path.
|
||||
hoda_data:
|
||||
Reference in new issue
Block a user