468 lines
20 KiB
YAML
468 lines
20 KiB
YAML
# Single compose file for both paths.
|
|
#
|
|
# Collimo runs from its published image, a built binary: no source reaches
|
|
# the Docker host. COLLIMO_VERSION picks the release.
|
|
# docker-compose.build.yml, added beside this file, builds from source
|
|
# instead, for development.
|
|
#
|
|
# Portainer GitOps: Portainer reads this file from the repository. Stack
|
|
# variables come from Portainer's Environment variables panel.
|
|
#
|
|
# Plain CLI: `docker compose up -d` reads the same variables out of a local
|
|
# .env automatically — Compose interpolates ${VAR} from .env without needing
|
|
# an `env_file:` key, which is why there isn't one. An `env_file:` would
|
|
# break the Portainer path, since .env is deliberately not in the repo.
|
|
#
|
|
# There is no top-level `name:` — Portainer sets the compose project name
|
|
# from the stack name, and a hardcoded one here would fight it.
|
|
|
|
services:
|
|
telemetry:
|
|
# The published image, at the release COLLIMO_VERSION names: 0.9.0, or
|
|
# qa for what is under test, and never latest. COLLIMO_IMAGE is the
|
|
# registry path, one line to change when it moves. Its own container
|
|
# names keep it apart from an earlier stack of this project on the same
|
|
# host.
|
|
# Each release writes its own version and registry in as the defaults,
|
|
# so a blank stack runs it.
|
|
image: ${COLLIMO_IMAGE:-ghcr.io/collimohq/collimo}:${COLLIMO_VERSION:-0.1.2}
|
|
# Ask the registry on every deploy. A fixed release costs one quick
|
|
# request; qa moves, and this is how a redeploy picks it up.
|
|
pull_policy: always
|
|
container_name: collimo
|
|
restart: unless-stopped
|
|
environment:
|
|
# false turns off Network, Protect, WAN and the probe, for a stack that
|
|
# watches only hypervisors and storage — or one tried out beside an
|
|
# existing stack, so the controller is not polled twice.
|
|
UNIFI_ENABLED: ${UNIFI_ENABLED:-true}
|
|
UNIFI_HOST: ${UNIFI_HOST:-}
|
|
UNIFI_API_KEY: ${UNIFI_API_KEY:-}
|
|
UNIFI_USERNAME: ${UNIFI_USERNAME:-}
|
|
UNIFI_PASSWORD: ${UNIFI_PASSWORD:-}
|
|
UNIFI_SITE: ${UNIFI_SITE:-default}
|
|
PORT_SLEEPS: ${PORT_SLEEPS:-}
|
|
# Protect on separate hardware (a UNVR) needs its own host and its own
|
|
# credentials — the gateway's do not work on it. Leave these unset when
|
|
# one console runs both applications.
|
|
PROTECT_HOST: ${PROTECT_HOST:-}
|
|
PROTECT_API_KEY: ${PROTECT_API_KEY:-}
|
|
PROTECT_USERNAME: ${PROTECT_USERNAME:-}
|
|
PROTECT_PASSWORD: ${PROTECT_PASSWORD:-}
|
|
UNIFI_OS: ${UNIFI_OS:-true}
|
|
UNIFI_VERIFY_TLS: ${UNIFI_VERIFY_TLS:-false}
|
|
POLL_INTERVAL: ${POLL_INTERVAL:-30s}
|
|
REQUEST_TIMEOUT: ${REQUEST_TIMEOUT:-20s}
|
|
PROTECT_ENABLED: ${PROTECT_ENABLED:-true}
|
|
PROTECT_BOOTSTRAP: ${PROTECT_BOOTSTRAP:-true}
|
|
LISTEN_ADDR: ":8080"
|
|
METRICS_URL: "http://victoria-metrics:8428"
|
|
METRICS_PUSH: "true"
|
|
|
|
# WAN health and ISP accountability. The gateway WAN objects and the
|
|
# cable modem DOCSIS state ride along with the device poll and cost no
|
|
# extra requests; WAN_POLL_INTERVAL only paces the aggregated dashboard
|
|
# and stat/health.
|
|
WAN_ENABLED: ${WAN_ENABLED:-true}
|
|
WAN_POLL_INTERVAL: ${WAN_POLL_INTERVAL:-60s}
|
|
WAN_DASHBOARD_SCALE: ${WAN_DASHBOARD_SCALE:-24h}
|
|
SPEEDTEST_INTERVAL: ${SPEEDTEST_INTERVAL:-15m}
|
|
BACKFILL_ON_START: ${BACKFILL_ON_START:-true}
|
|
|
|
# The outage archive. Fixed path because it is a named volume, not a
|
|
# host path — Portainer stacks cannot resolve relative host paths, and a
|
|
# named volume needs none.
|
|
LEDGER_PATH: /var/lib/collimo/ledger.jsonl
|
|
LEDGER_RETENTION: ${LEDGER_RETENTION:-8760h}
|
|
|
|
# Demarcation probe. Unset PROBE_TARGETS leaves it off. Point
|
|
# wan_next_hop at your own WAN1 next hop, by its literal address.
|
|
PROBE_TARGETS: ${PROBE_TARGETS:-}
|
|
PROBE_INTERVAL: ${PROBE_INTERVAL:-60s}
|
|
PROBE_COUNT: ${PROBE_COUNT:-10}
|
|
|
|
# Hypervisors and storage, one slot each. Every slot is listed because
|
|
# Portainer only passes a variable into the container when this file
|
|
# names it. The Settings page generates the lines for a new source:
|
|
# SOURCE_1=proxmox https://pve1:8006 name=pve-lab user=telemetry@pve!ro
|
|
# SOURCE_1_SECRET=<token secret>
|
|
SOURCE_1: ${SOURCE_1:-}
|
|
SOURCE_1_SECRET: ${SOURCE_1_SECRET:-}
|
|
SOURCE_2: ${SOURCE_2:-}
|
|
SOURCE_2_SECRET: ${SOURCE_2_SECRET:-}
|
|
SOURCE_3: ${SOURCE_3:-}
|
|
SOURCE_3_SECRET: ${SOURCE_3_SECRET:-}
|
|
SOURCE_4: ${SOURCE_4:-}
|
|
SOURCE_4_SECRET: ${SOURCE_4_SECRET:-}
|
|
SOURCE_5: ${SOURCE_5:-}
|
|
SOURCE_5_SECRET: ${SOURCE_5_SECRET:-}
|
|
SOURCE_6: ${SOURCE_6:-}
|
|
SOURCE_6_SECRET: ${SOURCE_6_SECRET:-}
|
|
SOURCE_7: ${SOURCE_7:-}
|
|
SOURCE_7_SECRET: ${SOURCE_7_SECRET:-}
|
|
SOURCE_8: ${SOURCE_8:-}
|
|
SOURCE_8_SECRET: ${SOURCE_8_SECRET:-}
|
|
|
|
# Up-checks: ping, HTTP or a TCP port for anything with an address,
|
|
# entries separated by ; such as
|
|
# CHECKS=ping 192.168.1.20 name=printer; http https://nas.lab:5001 name=nas
|
|
CHECKS: ${CHECKS:-}
|
|
|
|
# Sign-in. Off until ADMIN_PASSWORD (free) or OIDC_* / LDAP_* (paid)
|
|
# are set. See PORTAINER.md.
|
|
ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}
|
|
ADMIN_PASSWORD: ${ADMIN_PASSWORD:-}
|
|
SESSION_TTL: ${SESSION_TTL:-168h}
|
|
METRICS_TOKEN: ${METRICS_TOKEN:-}
|
|
OIDC_ISSUER: ${OIDC_ISSUER:-}
|
|
OIDC_CLIENT_ID: ${OIDC_CLIENT_ID:-}
|
|
OIDC_CLIENT_SECRET: ${OIDC_CLIENT_SECRET:-}
|
|
OIDC_ROLES: ${OIDC_ROLES:-}
|
|
OIDC_NAME: ${OIDC_NAME:-}
|
|
OIDC_SCOPES: ${OIDC_SCOPES:-}
|
|
OIDC_GROUPS_CLAIM: ${OIDC_GROUPS_CLAIM:-}
|
|
OIDC_REDIRECT_URL: ${OIDC_REDIRECT_URL:-}
|
|
LDAP_URL: ${LDAP_URL:-}
|
|
LDAP_STARTTLS: ${LDAP_STARTTLS:-false}
|
|
LDAP_VERIFY_TLS: ${LDAP_VERIFY_TLS:-true}
|
|
LDAP_CA_CERT: ${LDAP_CA_CERT:-}
|
|
LDAP_BIND_DN: ${LDAP_BIND_DN:-}
|
|
LDAP_BIND_PASSWORD: ${LDAP_BIND_PASSWORD:-}
|
|
LDAP_BASE_DN: ${LDAP_BASE_DN:-}
|
|
LDAP_USER_FILTER: ${LDAP_USER_FILTER:-}
|
|
LDAP_GROUP_ATTR: ${LDAP_GROUP_ATTR:-}
|
|
LDAP_ROLES: ${LDAP_ROLES:-}
|
|
|
|
# The license key, when there is one. Without it every install runs a
|
|
# 30-day trial of the paid features, then carries on as Community.
|
|
COLLIMO_LICENSE: ${COLLIMO_LICENSE:-}
|
|
|
|
# Several sites, for an MSP (ADR-0044): a collector at each client
|
|
# site reports to one hub, calling out only. Unset is one site on its
|
|
# own.
|
|
COLLIMO_ROLE: ${COLLIMO_ROLE:-standalone}
|
|
HUB_URL: ${HUB_URL:-}
|
|
HUB_ENROL: ${HUB_ENROL:-}
|
|
HUB_LINK: ${HUB_LINK:-normal}
|
|
|
|
# Notification channels. Each is off until its variables are set; any
|
|
# number can be on. Slack, Teams, PagerDuty and the webhook are paid.
|
|
# Settings -> Notifications shows each one's state and the rules in
|
|
# force; see PORTAINER.md for what each variable means.
|
|
GOTIFY_URL: ${GOTIFY_URL:-}
|
|
GOTIFY_TOKEN: ${GOTIFY_TOKEN:-}
|
|
# With the bundled Gotify and no token, Collimo makes a shared
|
|
# collimo-alerts account and its own app, using the admin password.
|
|
GOTIFY_ALERTS_PASSWORD: ${GOTIFY_ALERTS_PASSWORD:-}
|
|
GOTIFY_ADMIN_PASSWORD: ${GOTIFY_ADMIN_PASSWORD:-}
|
|
NTFY_URL: ${NTFY_URL:-}
|
|
NTFY_TOKEN: ${NTFY_TOKEN:-}
|
|
PUSHOVER_TOKEN: ${PUSHOVER_TOKEN:-}
|
|
PUSHOVER_USER: ${PUSHOVER_USER:-}
|
|
DISCORD_WEBHOOK_URL: ${DISCORD_WEBHOOK_URL:-}
|
|
SMTP_HOST: ${SMTP_HOST:-}
|
|
SMTP_PORT: ${SMTP_PORT:-587}
|
|
SMTP_TLS: ${SMTP_TLS:-}
|
|
SMTP_USERNAME: ${SMTP_USERNAME:-}
|
|
SMTP_PASSWORD: ${SMTP_PASSWORD:-}
|
|
SMTP_FROM: ${SMTP_FROM:-}
|
|
SMTP_TO: ${SMTP_TO:-}
|
|
# open or all when SMTP_TO is a help desk's mailbox: one ticket per alert
|
|
SMTP_TICKETS: ${SMTP_TICKETS:-}
|
|
SLACK_WEBHOOK_URL: ${SLACK_WEBHOOK_URL:-}
|
|
TEAMS_WEBHOOK_URL: ${TEAMS_WEBHOOK_URL:-}
|
|
PAGERDUTY_ROUTING_KEY: ${PAGERDUTY_ROUTING_KEY:-}
|
|
WEBHOOK_URL: ${WEBHOOK_URL:-}
|
|
WEBHOOK_SECRET: ${WEBHOOK_SECRET:-}
|
|
APPRISE_URL: ${APPRISE_URL:-}
|
|
APPRISE_URLS: ${APPRISE_URLS:-}
|
|
APPRISE_KEY: ${APPRISE_KEY:-}
|
|
|
|
# Inventory of the vCenter and Proxmox VE sources, as Excel, CSV or
|
|
# HTML from the Virtualization tab. Taking one by hand is free; the
|
|
# daily run, history and the Changes sheet are paid. See PORTAINER.md.
|
|
# Encrypts local users and groups on the volume (paid). 32 random bytes
|
|
# in base64: openssl rand -base64 32, or Settings → Users and groups.
|
|
SETTINGS_KEY: ${SETTINGS_KEY:-}
|
|
|
|
# The assistant (experimental, paid): Explain on alerts, Review on
|
|
# sources, answered by a language model you choose. Up to four, one
|
|
# per slot: the provider (claude, openai, gemini, xai, or llamacpp,
|
|
# lmstudio, ollama or local), then the address of a model you run, then
|
|
# optional name=, model=, context= and timeout=. The key goes in
|
|
# AI_n_KEY. Settings -> Add a model writes them. See PORTAINER.md.
|
|
AI_1: ${AI_1:-}
|
|
AI_1_KEY: ${AI_1_KEY:-}
|
|
AI_2: ${AI_2:-}
|
|
AI_2_KEY: ${AI_2_KEY:-}
|
|
AI_3: ${AI_3:-}
|
|
AI_3_KEY: ${AI_3_KEY:-}
|
|
AI_4: ${AI_4:-}
|
|
AI_4_KEY: ${AI_4_KEY:-}
|
|
# One model, as before there were slots: slot 1 when AI_1 is not set.
|
|
AI_PROVIDER: ${AI_PROVIDER:-}
|
|
AI_URL: ${AI_URL:-}
|
|
AI_MODEL: ${AI_MODEL:-}
|
|
AI_API_KEY: ${AI_API_KEY:-}
|
|
AI_CONTEXT: ${AI_CONTEXT:-}
|
|
AI_TIMEOUT: ${AI_TIMEOUT:-5m}
|
|
|
|
INVENTORY: ${INVENTORY:-on}
|
|
INVENTORY_AT: ${INVENTORY_AT:-02:30}
|
|
# Days of inventory history: a year by default; 2557 keeps seven years.
|
|
INVENTORY_KEEP: ${INVENTORY_KEEP:-365}
|
|
# Capacity planning (paid): forecast thresholds in %, runway alert
|
|
# days, allocation limits, and hosts kept spare per cluster.
|
|
CAPACITY_THRESHOLDS: ${CAPACITY_THRESHOLDS:-cpu=80,mem=80,disk=85,pool=85}
|
|
CAPACITY_RUNWAY: ${CAPACITY_RUNWAY:-warn=90,bad=30}
|
|
CAPACITY_RATIOS: ${CAPACITY_RATIOS:-vcpu=4,vmem=1,disk=1.5}
|
|
CAPACITY_VM_SIZE: ${CAPACITY_VM_SIZE:-vcpu=4,mem=16,disk=100}
|
|
CAPACITY_HA: ${CAPACITY_HA:-}
|
|
# The monthly capacity summary: who gets it, whose name is on it, and
|
|
# the host "What to buy" plans in (empty: each cluster's largest).
|
|
CAPACITY_SUMMARY_TO: ${CAPACITY_SUMMARY_TO:-}
|
|
CAPACITY_SUMMARY_BY: ${CAPACITY_SUMMARY_BY:-}
|
|
CAPACITY_HOST: ${CAPACITY_HOST:-}
|
|
# Rated endurance per drive model, for disk wear: CT1000P310SSD8=220
|
|
CAPACITY_DISK_TBW: ${CAPACITY_DISK_TBW:-}
|
|
# A copy of every inventory in PostgreSQL, for Grafana and Power BI
|
|
# (paid). For the stack's own, add "postgres" to COMPOSE_PROFILES and
|
|
# set INVENTORY_DB_PASSWORD; for one you run, set INVENTORY_DB_URL. The
|
|
# reader password makes a read-only collimo_reader role for reports.
|
|
INVENTORY_DB_URL: ${INVENTORY_DB_URL:-}
|
|
INVENTORY_DB_PASSWORD: ${INVENTORY_DB_PASSWORD:-}
|
|
INVENTORY_DB_READER_PASSWORD: ${INVENTORY_DB_READER_PASSWORD:-}
|
|
INVENTORY_DB_CA: ${INVENTORY_DB_CA:-}
|
|
|
|
# Backups. Off until a target is set: BACKUP_DIR comes from an overlay
|
|
# that mounts an NFS or SMB share (docker-compose.backup-nfs.yml,
|
|
# docker-compose.backup-smb.yml); BACKUP_S3_* is object storage, paid.
|
|
# See PORTAINER.md.
|
|
BACKUP_NAME: ${BACKUP_NAME:-collimo}
|
|
BACKUP_KEY: ${BACKUP_KEY:-}
|
|
BACKUP_AT: ${BACKUP_AT:-03:30}
|
|
BACKUP_HISTORY: ${BACKUP_HISTORY:-true}
|
|
BACKUP_HISTORY_DAY: ${BACKUP_HISTORY_DAY:-sunday}
|
|
BACKUP_KEEP: ${BACKUP_KEEP:-14}
|
|
BACKUP_HISTORY_KEEP: ${BACKUP_HISTORY_KEEP:-4}
|
|
BACKUP_RESTORE: ${BACKUP_RESTORE:-auto}
|
|
BACKUP_S3_ENDPOINT: ${BACKUP_S3_ENDPOINT:-}
|
|
BACKUP_S3_REGION: ${BACKUP_S3_REGION:-us-east-1}
|
|
BACKUP_S3_BUCKET: ${BACKUP_S3_BUCKET:-}
|
|
BACKUP_S3_PREFIX: ${BACKUP_S3_PREFIX:-collimo}
|
|
BACKUP_S3_ACCESS_KEY: ${BACKUP_S3_ACCESS_KEY:-}
|
|
BACKUP_S3_SECRET_KEY: ${BACKUP_S3_SECRET_KEY:-}
|
|
DASHBOARD_URL: ${DASHBOARD_URL:-}
|
|
NOTIFY_DEFAULT: ${NOTIFY_DEFAULT:-bad}
|
|
NOTIFY_RULES: ${NOTIFY_RULES:-}
|
|
NOTIFY_DELAY: ${NOTIFY_DELAY:-2m}
|
|
NOTIFY_ON_CLEAR: ${NOTIFY_ON_CLEAR:-true}
|
|
NOTIFY_REPEAT: ${NOTIFY_REPEAT:-off}
|
|
NOTIFY_QUIET: ${NOTIFY_QUIET:-}
|
|
TZ: ${TZ:-}
|
|
PROBE_TIMEOUT: ${PROBE_TIMEOUT:-2s}
|
|
|
|
# Read by Compose, not the collector: passed in only so Settings ->
|
|
# Stack environment can start from what is set. Never a secret.
|
|
COMPOSE_PROFILES: ${COMPOSE_PROFILES:-}
|
|
WEB_PORT: ${WEB_PORT:-8090}
|
|
COLLIMO_IMAGE: ${COLLIMO_IMAGE:-ghcr.io/collimohq/collimo}
|
|
COLLIMO_VERSION: ${COLLIMO_VERSION:-}
|
|
RETENTION: ${RETENTION:-13w}
|
|
GOTIFY_ADMIN_USER: ${GOTIFY_ADMIN_USER:-admin}
|
|
GOTIFY_PORT: ${GOTIFY_PORT:-8091}
|
|
IGOTIFY_PORT: ${IGOTIFY_PORT:-8092}
|
|
IGOTIFY_GOTIFY_URLS: ${IGOTIFY_GOTIFY_URLS:-http://gotify}
|
|
APPRISE_PORT: ${APPRISE_PORT:-8093}
|
|
INVENTORY_DB_BIND: ${INVENTORY_DB_BIND:-127.0.0.1}
|
|
INVENTORY_DB_PORT: ${INVENTORY_DB_PORT:-5432}
|
|
ports:
|
|
# 8090 rather than 8080, so it does not collide with an existing
|
|
# earlier deployment on the same host.
|
|
- "${WEB_PORT:-8090}:8080"
|
|
volumes:
|
|
# A named volume, so there is no host path for Portainer to fail to
|
|
# resolve. The root filesystem stays read-only; this is the one writable
|
|
# mount, and it is what makes the outage archive outlive the controller
|
|
# 21-hour window.
|
|
- ledger-data:/var/lib/collimo
|
|
sysctls:
|
|
# Lets the container open an unprivileged ICMP datagram socket for the
|
|
# demarcation probe, with cap_drop: ALL still in force. The range must
|
|
# include the UID/GID the image runs as, which is 65534. Without this the
|
|
# probe reports itself unavailable and nothing else is affected.
|
|
net.ipv4.ping_group_range: "65534 65534"
|
|
depends_on:
|
|
- victoria-metrics
|
|
healthcheck:
|
|
# The image is scratch — no shell, no curl. The binary probes itself.
|
|
test: ["CMD", "/collimo", "-healthcheck"]
|
|
interval: 30s
|
|
timeout: 5s
|
|
retries: 3
|
|
start_period: 45s
|
|
read_only: true
|
|
tmpfs:
|
|
- /tmp
|
|
cap_drop:
|
|
- ALL
|
|
security_opt:
|
|
- no-new-privileges:true
|
|
logging:
|
|
driver: json-file
|
|
options:
|
|
max-size: "10m"
|
|
max-file: "3"
|
|
|
|
victoria-metrics:
|
|
# Pin to a release tag once you have one you are happy with.
|
|
image: victoriametrics/victoria-metrics:latest
|
|
container_name: collimo-victoria-metrics
|
|
restart: unless-stopped
|
|
command:
|
|
- "-storageDataPath=/victoria-metrics-data"
|
|
- "-retentionPeriod=${RETENTION:-13w}"
|
|
- "-httpListenAddr=:8428"
|
|
- "-memory.allowedPercent=60"
|
|
volumes:
|
|
- vm-data:/victoria-metrics-data
|
|
# Not published. The dashboard reaches it over the stack network and
|
|
# proxies queries, so it never needs to be on your LAN.
|
|
security_opt:
|
|
- no-new-privileges:true
|
|
logging:
|
|
driver: json-file
|
|
options:
|
|
max-size: "10m"
|
|
max-file: "3"
|
|
|
|
# ---- Optional: Gotify and iGotify --------------------------------------
|
|
#
|
|
# Neither starts unless its profile is enabled on the stack:
|
|
# COMPOSE_PROFILES=gotify,igotify both, for a host with neither
|
|
# COMPOSE_PROFILES=igotify iGotify beside a Gotify you already run
|
|
# Leave COMPOSE_PROFILES unset if you run both already, and point
|
|
# GOTIFY_URL at your server.
|
|
#
|
|
# Inside the stack the collector reaches Gotify as http://gotify, so set
|
|
# GOTIFY_URL=http://gotify when using the bundled one. First deploy, then
|
|
# create an application in Gotify's web UI, put its token in GOTIFY_TOKEN,
|
|
# and update the stack.
|
|
#
|
|
# For HMS-Docker hosts, docker-compose.hms-docker.yml adds the Traefik
|
|
# routes and proxy network; see PORTAINER.md.
|
|
gotify:
|
|
profiles: ["gotify"]
|
|
image: gotify/server:latest
|
|
container_name: collimo-gotify
|
|
restart: unless-stopped
|
|
environment:
|
|
GOTIFY_DEFAULTUSER_NAME: ${GOTIFY_ADMIN_USER:-admin}
|
|
# Set this. Unset, Gotify creates its admin with the password "admin".
|
|
GOTIFY_DEFAULTUSER_PASS: ${GOTIFY_ADMIN_PASSWORD:-}
|
|
TZ: ${TZ:-}
|
|
volumes:
|
|
# A named volume, like the outage archive: no host path to resolve.
|
|
- gotify-data:/app/data
|
|
ports:
|
|
- "${GOTIFY_PORT:-8091}:80"
|
|
security_opt:
|
|
- no-new-privileges:true
|
|
|
|
# Relays Gotify messages to the iGotify iPhone app through Apple's push
|
|
# service. The phone must reach both Gotify and iGotify, so away from home
|
|
# they need a tunnel or reverse proxy in front of them.
|
|
igotify:
|
|
profiles: ["igotify"]
|
|
image: ghcr.io/androidseb25/igotify-notification-assist:latest
|
|
container_name: collimo-igotify
|
|
hostname: igotify
|
|
restart: unless-stopped
|
|
pull_policy: always
|
|
environment:
|
|
# http://gotify for the bundled Gotify; your server's URL otherwise.
|
|
GOTIFY_URLS: ${IGOTIFY_GOTIFY_URLS:-http://gotify}
|
|
# Only needed when Gotify and iGotify are not reachable over public
|
|
# domains. Set all three or none: GOTIFY_URLS, these two.
|
|
GOTIFY_CLIENT_TOKENS: ${IGOTIFY_CLIENT_TOKENS:-}
|
|
SECNTFY_TOKENS: ${IGOTIFY_SECNTFY_TOKENS:-}
|
|
volumes:
|
|
- igotify-data:/app/data
|
|
ports:
|
|
- "${IGOTIFY_PORT:-8092}:8080"
|
|
security_opt:
|
|
- no-new-privileges:true
|
|
|
|
# ---- Optional: PostgreSQL, for the inventory's database copy ----------
|
|
#
|
|
# Starts only with "postgres" in COMPOSE_PROFILES. Set
|
|
# INVENTORY_DB_PASSWORD and the collector finds it at collimo-postgres on
|
|
# its own; nothing else to set. It holds a copy: the inventory files on
|
|
# ledger-data stay the master and travel with the backups, and the copy is
|
|
# rebuilt from them, so this volume needs no backup of its own.
|
|
#
|
|
# Grafana and Power BI connect with their own PostgreSQL connectors, as
|
|
# collimo_reader with INVENTORY_DB_READER_PASSWORD, never as the writer.
|
|
# The port listens on the Docker host's loopback only; set
|
|
# INVENTORY_DB_BIND=0.0.0.0 for a reporting tool on another machine.
|
|
postgres:
|
|
profiles: ["postgres"]
|
|
image: postgres:18-alpine
|
|
container_name: collimo-postgres
|
|
restart: unless-stopped
|
|
environment:
|
|
POSTGRES_USER: collimo
|
|
POSTGRES_DB: collimo
|
|
# The image refuses to start without one, so a missing password shows
|
|
# here rather than as an open database.
|
|
POSTGRES_PASSWORD: ${INVENTORY_DB_PASSWORD:-}
|
|
TZ: ${TZ:-}
|
|
volumes:
|
|
# PostgreSQL 18 keeps its data under a versioned directory here.
|
|
- postgres-data:/var/lib/postgresql
|
|
ports:
|
|
- "${INVENTORY_DB_BIND:-127.0.0.1}:${INVENTORY_DB_PORT:-5432}:5432"
|
|
# Postgres sets POSTGRES_PASSWORD only when its volume is first made, so
|
|
# changing INVENTORY_DB_PASSWORD later left Collimo refused. The first
|
|
# check in each container sets the password from the environment, over
|
|
# the container's own socket, which needs none, and marks /tmp so it is
|
|
# done once: a redeploy with a new password is a new container with an
|
|
# empty /tmp. (A password cannot be tested from in here: Postgres trusts
|
|
# every connection from inside its container, 127.0.0.1 included.) The
|
|
# password reaches SQL as a psql variable, so no quote in it can break
|
|
# the statement.
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "pg_isready -U collimo -d collimo && { [ -f /tmp/collimo-password-set ] || { echo \"ALTER ROLE collimo PASSWORD :'pw';\" | psql -U collimo -d collimo -q -v ON_ERROR_STOP=1 -v pw=\"$$POSTGRES_PASSWORD\" >/dev/null && touch /tmp/collimo-password-set; }; }"]
|
|
interval: 30s
|
|
timeout: 5s
|
|
retries: 3
|
|
start_period: 20s
|
|
security_opt:
|
|
- no-new-privileges:true
|
|
|
|
# Apprise: one paid channel that reaches more than a hundred services.
|
|
# Starts only with "apprise" in COMPOSE_PROFILES; then set
|
|
# APPRISE_URL=http://apprise:8000 and APPRISE_URLS to the services to
|
|
# notify. With APPRISE_URLS it keeps nothing, so it needs no backup.
|
|
apprise:
|
|
profiles: ["apprise"]
|
|
image: caronc/apprise:latest
|
|
container_name: collimo-apprise
|
|
hostname: apprise
|
|
restart: unless-stopped
|
|
pull_policy: always
|
|
volumes:
|
|
- apprise-config:/config
|
|
ports:
|
|
- "${APPRISE_PORT:-8093}:8000"
|
|
security_opt:
|
|
- no-new-privileges:true
|
|
|
|
volumes:
|
|
vm-data:
|
|
ledger-data:
|
|
gotify-data:
|
|
igotify-data:
|
|
apprise-config:
|
|
postgres-data:
|