48 lines
1.4 KiB
YAML
48 lines
1.4 KiB
YAML
services:
|
|
app:
|
|
build:
|
|
context: /docker/linumiq-invoice/git/
|
|
dockerfile: Dockerfile
|
|
image: linumiq-invoice:dev
|
|
container_name: linumiq-invoice-dev
|
|
restart: unless-stopped
|
|
# --- Container hardening (DEV) ---------------------------------------
|
|
# Prevent privilege escalation and drop all Linux capabilities (the app
|
|
# is a plain Node HTTP server — it needs none).
|
|
security_opt:
|
|
- "no-new-privileges:true"
|
|
cap_drop:
|
|
- ALL
|
|
# Read-only root filesystem: the app never writes to the image at runtime
|
|
# (Prisma client is baked at build; the SQLite DB lives on the /data bind
|
|
# mount; logo/image caches live in the DB or in-memory). npm/Prisma
|
|
# incidental writes are redirected to the tmpfs /tmp (see Dockerfile env).
|
|
read_only: true
|
|
tmpfs:
|
|
- /tmp
|
|
# Resource limits (Compose v2 / docker compose, non-swarm).
|
|
mem_limit: 512m
|
|
pids_limit: 256
|
|
cpus: 1.5
|
|
env_file:
|
|
- .env.dev
|
|
environment:
|
|
# SQLite file lives on a bind mount so it survives image rebuilds.
|
|
DATABASE_URL: "file:/data/prod.sqlite"
|
|
NODE_ENV: production
|
|
PORT: "3000"
|
|
volumes:
|
|
- /docker/linumiq-invoice/dev/data:/data
|
|
healthcheck:
|
|
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:3000/healthz"]
|
|
interval: 30s
|
|
timeout: 5s
|
|
retries: 3
|
|
networks:
|
|
- caddy_net
|
|
|
|
networks:
|
|
caddy_net:
|
|
name: caddy_net
|
|
external: true
|