128 lines
3.8 KiB
YAML
128 lines
3.8 KiB
YAML
# HomeOS — dev stack (dev = prod parity, R8). All app-family services share one image.
|
|
# mosquitto / mqtt-listener (Phase 3) and discovery sidecar (Phase 4) are added in their phases.
|
|
|
|
x-app-image: &app-image
|
|
image: homeos-app:dev
|
|
build:
|
|
context: .
|
|
dockerfile: docker/app/Dockerfile
|
|
args:
|
|
HOST_UID: ${HOST_UID:-1000}
|
|
HOST_GID: ${HOST_GID:-1000}
|
|
# Laravel reads its own .env from the mounted volume (correct phpdotenv interpolation).
|
|
# Compose still reads root .env for ${...} substitution in this file (ports, uid, db creds).
|
|
volumes:
|
|
- .:/var/www/html
|
|
- ./docker/nginx/default.conf:/etc/nginx/sites-available/default:ro
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
redis:
|
|
condition: service_started
|
|
restart: unless-stopped
|
|
|
|
services:
|
|
app:
|
|
<<: *app-image
|
|
ports:
|
|
- "${APP_PORT:-80}:80"
|
|
- "${VITE_PORT:-5173}:5173"
|
|
|
|
horizon:
|
|
<<: *app-image
|
|
command: ["php", "artisan", "horizon"]
|
|
ports: []
|
|
|
|
scheduler:
|
|
<<: *app-image
|
|
command: ["php", "artisan", "schedule:work"]
|
|
ports: []
|
|
|
|
reverb:
|
|
<<: *app-image
|
|
command: ["php", "artisan", "reverb:start", "--host=0.0.0.0", "--port=8080"]
|
|
ports:
|
|
- "${REVERB_HOST_PORT:-6001}:8080"
|
|
|
|
mqtt-listener:
|
|
<<: *app-image
|
|
command: ["php", "artisan", "mqtt:listen"]
|
|
restart: always
|
|
ports: []
|
|
|
|
db:
|
|
image: timescale/timescaledb:latest-pg17
|
|
environment:
|
|
POSTGRES_DB: ${DB_DATABASE:-homeos}
|
|
POSTGRES_USER: ${DB_USERNAME:-homeos}
|
|
POSTGRES_PASSWORD: ${DB_PASSWORD:-homeos}
|
|
volumes:
|
|
- db-data:/var/lib/postgresql/data
|
|
ports:
|
|
- "127.0.0.1:${DB_HOST_PORT:-5432}:5432"
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "pg_isready -U ${DB_USERNAME:-homeos} -d ${DB_DATABASE:-homeos}"]
|
|
interval: 5s
|
|
timeout: 5s
|
|
retries: 10
|
|
restart: unless-stopped
|
|
|
|
redis:
|
|
image: redis:7-alpine
|
|
command: ["redis-server", "--appendonly", "yes"]
|
|
volumes:
|
|
- redis-data:/data
|
|
restart: unless-stopped
|
|
|
|
mosquitto:
|
|
image: eclipse-mosquitto:2
|
|
# Wrapper runs mosquitto + reloads it (SIGHUP) when a device credential is provisioned.
|
|
command: ["/bin/sh", "/mosquitto/config/entrypoint.sh"]
|
|
volumes:
|
|
- ./docker/mosquitto/config:/mosquitto/config
|
|
- mosquitto-data:/mosquitto/data
|
|
ports:
|
|
# LAN-reachable so real devices can connect (auth + ACL enforced)
|
|
- "${MQTT_HOST_PORT:-1883}:1883"
|
|
restart: unless-stopped
|
|
|
|
# Ring bridge — part of the stack so it starts automatically (no manual command). Idle and
|
|
# cheap until you log in. Ring has no local API (handoff §12): the account login + 2FA is done
|
|
# in ring-mqtt's own web UI (http://<host>:${RING_UI_PORT:-55123}), which mints the refresh
|
|
# token; the bridge then connects to our broker as the least-privileged `ring` user and
|
|
# publishes device state under ring/# for HomeOS to ingest. We do not build a custom Ring client.
|
|
ring-mqtt:
|
|
image: tsightler/ring-mqtt
|
|
depends_on:
|
|
- mosquitto
|
|
environment:
|
|
RUNMODE: docker
|
|
volumes:
|
|
- ring-data:/data
|
|
# Generated by gen-passwd.sh (holds the broker mqtt_url); the token/state lives in ring-data.
|
|
- ./docker/ring-mqtt/config.json:/data/config.json:ro
|
|
ports:
|
|
# ring-mqtt setup/token web UI. Port may differ by ring-mqtt version — adjust if needed.
|
|
- "${RING_UI_PORT:-55123}:55123"
|
|
restart: unless-stopped
|
|
|
|
# Discovery sidecar — host network so mDNS/SSDP multicast reaches the smart-home VLAN.
|
|
discovery:
|
|
build:
|
|
context: ./sidecar
|
|
dockerfile: Dockerfile
|
|
network_mode: host
|
|
cap_add: [NET_RAW]
|
|
environment:
|
|
MQTT_HOST: 127.0.0.1
|
|
MQTT_PORT: ${MQTT_HOST_PORT:-1883}
|
|
MQTT_USERNAME: sidecar
|
|
MQTT_PASSWORD: ${MQTT_SIDECAR_PASSWORD}
|
|
restart: unless-stopped
|
|
|
|
volumes:
|
|
db-data:
|
|
redis-data:
|
|
mosquitto-data:
|
|
ring-data:
|