docker-compose.yml
Rama main · réplica de lectura del repositorio original.
version: "3.8" # kept so the legacy docker-compose 1.x still reads the file; Compose v2 ignores it with a warning
services:
actual-sync:
build:
context: .
dockerfile: Dockerfile
image: actual-sync:latest
container_name: actual-sync
restart: unless-stopped
# Environment variables (optional, overrides config.json)
environment:
# PUID/PGID: run as this UID/GID and chown the data/logs volumes to match.
# Defaults to 1001:1001. On Unraid set 99:100 (nobody:users).
- PUID=1001
- PGID=1001
- TZ=Europe/Madrid
- NODE_ENV=production
# Mount config and data volumes
volumes:
# Configuration file
- ./config/config.json:/app/config/config.json:ro
# Persistent data directories
- actual-sync-data:/app/data
- actual-sync-logs:/app/logs
# If using custom data directories for budget files
# - ./budget-data:/budget-data
# Dashboard, health and metrics port, published on this machine only:
# nothing else on the network can reach it. To use the dashboard from
# another machine, put a reverse proxy in front (docs/DOCKER_DEPLOYMENT.md,
# "Behind a reverse proxy"), or change this to "3000:3000" and set
# healthCheck.dashboard.auth (and healthCheck.auth for the metrics) in
# config.json first. healthCheck.host stays "0.0.0.0" inside the container
# either way; this line decides who can reach it.
ports:
- "127.0.0.1:3000:3000"
# Container hardening (#253). Every Linux capability is dropped, then the
# three the entrypoint needs are added back. It runs as root only to apply
# PUID/PGID and chown the volumes, then drops to actualuser, which runs
# with no capability at all. Verified by a container run against each
# setting (see docs/DOCKER_DEPLOYMENT.md, "Container hardening").
# CHOWN: chown -R of /app/data and /app/logs
# SETUID, SETGID: usermod/groupmod for PUID/PGID, and su-exec to the user
# A bind-mounted data or logs directory that another user owns with mode
# 700 also needs DAC_READ_SEARCH, or the chown cannot enter it.
# Alternative: set `user: "1001:1001"` (the owner of your directories).
# The entrypoint then skips its root phase and needs no capability, so
# cap_add can be removed entirely.
cap_drop:
- ALL
cap_add:
- CHOWN
- SETUID
- SETGID
# No process in the container can gain privileges through a setuid binary,
# whatever capabilities it holds.
security_opt:
- no-new-privileges:true
# Optional: read-only root filesystem. It works with the default PUID/PGID
# (1001:1001). Any other value needs usermod and groupmod to write
# /etc/passwd and /etc/group, which a read-only root refuses, so the
# container does not start. Uncomment both lines together.
# read_only: true
# tmpfs:
# - /tmp
# Resource limits
deploy:
resources:
limits:
cpus: '1.0'
memory: 512M
reservations:
cpus: '0.25'
memory: 128M
# Health check
healthcheck:
test: ["CMD", "node", "-e", "require('http').get('http://localhost:3000/health', (r) => { process.exit(r.statusCode === 200 ? 0 : 1); }).on('error', () => process.exit(1));"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
# Logging configuration (#451). stdout is the main log sink and the Docker
# log driver keeps it; json-file has no size limit by default, so cap it here.
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "5"
# Network configuration
networks:
- actual-network
# Optional: Actual Budget server
# Uncomment if you want to run Actual Budget alongside sync service
# actual-server:
# image: actualbudget/actual-server:latest
# container_name: actual-server
# restart: unless-stopped
# ports:
# - "5006:5006"
# volumes:
# - actual-server-data:/data
# networks:
# - actual-network
# Optional: Monitoring with Prometheus
# prometheus:
# image: prom/prometheus:latest
# container_name: prometheus
# restart: unless-stopped
# ports:
# - "9090:9090"
# volumes:
# - ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml:ro
# - prometheus-data:/prometheus
# command:
# - '--config.file=/etc/prometheus/prometheus.yml'
# - '--storage.tsdb.path=/prometheus'
# networks:
# - actual-network
# Optional: Grafana for visualization
# grafana:
# image: grafana/grafana:latest
# container_name: grafana
# restart: unless-stopped
# ports:
# - "3001:3000"
# volumes:
# - grafana-data:/var/lib/grafana
# environment:
# - GF_SECURITY_ADMIN_PASSWORD=admin
# networks:
# - actual-network
networks:
actual-network:
driver: bridge
volumes:
actual-sync-data:
driver: local
actual-sync-logs:
driver: local
# actual-server-data:
# driver: local
# prometheus-data:
# driver: local
# grafana-data:
# driver: local