Add self-contained Docker Compose stacks for pivoine.art infrastructure
Migrated 11 services from monolithic docker-compose project into independent stacks, each with dedicated databases, minimal .env configuration, and bind-mount data volumes. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
.claude
|
||||||
|
.env
|
||||||
|
*.sql
|
||||||
39
README.md
Normal file
39
README.md
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
# Stacks
|
||||||
|
|
||||||
|
Self-contained Docker Compose stacks for `pivoine.art` infrastructure.
|
||||||
|
|
||||||
|
Each stack is independently deployable with its own `compose.yml` and `.env`. All persistent data lives in `../.data/<stack>/`.
|
||||||
|
|
||||||
|
## Stacks
|
||||||
|
|
||||||
|
| Stack | Description | Services |
|
||||||
|
|---|---|---|
|
||||||
|
| `traefik` | Reverse proxy, TLS termination | traefik |
|
||||||
|
| `mailpit` | SMTP relay (no web UI) | mailpit |
|
||||||
|
| `watchtower` | Automatic container updates | watchtower |
|
||||||
|
| `umami` | Web analytics | umami, db |
|
||||||
|
| `immich` | Photo & video management | immich, ml, redis, db |
|
||||||
|
| `joplin` | Note sync server | joplin, db |
|
||||||
|
| `mattermost` | Team chat | mattermost, db |
|
||||||
|
| `gitea` | Git hosting + CI runner | gitea, runner, db |
|
||||||
|
| `coolify` | Deployment platform | coolify, realtime, redis, db |
|
||||||
|
| `sexy` | pivoine.art website | directus, frontend, redis, db |
|
||||||
|
| `vaultwarden` | Password manager | vaultwarden |
|
||||||
|
|
||||||
|
## Deployment
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Sync a stack to VPS
|
||||||
|
rsync -avz <stack>/ vps:~/stacks/<stack>/
|
||||||
|
|
||||||
|
# Start a stack
|
||||||
|
ssh vps 'cd ~/stacks/<stack> && docker compose up -d'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Network
|
||||||
|
|
||||||
|
All stacks share the external `falcon_network` Docker network for inter-service communication (e.g. traefik routing, mailpit SMTP).
|
||||||
|
|
||||||
|
## Data
|
||||||
|
|
||||||
|
Persistent data is stored in `~/stacks/.data/<stack>/` on the VPS using bind mounts. Database stacks use dedicated Postgres instances with simple credentials.
|
||||||
129
coolify/compose.yml
Normal file
129
coolify/compose.yml
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
---
|
||||||
|
services:
|
||||||
|
coolify:
|
||||||
|
image: ghcr.io/coollabsio/coolify:latest
|
||||||
|
container_name: coolify
|
||||||
|
environment:
|
||||||
|
APP_ID: ${APP_ID}
|
||||||
|
APP_KEY: ${APP_KEY}
|
||||||
|
APP_NAME: Coolify
|
||||||
|
APP_ENV: production
|
||||||
|
APP_URL: https://${TRAEFIK_HOST}
|
||||||
|
APP_PORT: 8080
|
||||||
|
DB_HOST: coolify_db
|
||||||
|
DB_PORT: 5432
|
||||||
|
DB_DATABASE: coolify
|
||||||
|
DB_USERNAME: coolify
|
||||||
|
DB_PASSWORD: coolify
|
||||||
|
REDIS_HOST: coolify_redis
|
||||||
|
REDIS_PORT: 6379
|
||||||
|
PUSHER_HOST: realtime.${TRAEFIK_HOST}
|
||||||
|
PUSHER_PORT: 443
|
||||||
|
PUSHER_APP_ID: ${PUSHER_APP_ID}
|
||||||
|
PUSHER_APP_KEY: ${PUSHER_APP_KEY}
|
||||||
|
PUSHER_APP_SECRET: ${PUSHER_APP_SECRET}
|
||||||
|
PUSHER_SCHEME: https
|
||||||
|
SSL_MODE: "off"
|
||||||
|
volumes:
|
||||||
|
- ../.data/coolify/data:/data/coolify
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
- ../.data/coolify/storage/ssh:/var/www/html/storage/app/ssh
|
||||||
|
- ../.data/coolify/storage/applications:/var/www/html/storage/app/applications
|
||||||
|
- ../.data/coolify/storage/databases:/var/www/html/storage/app/databases
|
||||||
|
- ../.data/coolify/storage/services:/var/www/html/storage/app/services
|
||||||
|
- ../.data/coolify/storage/backups:/var/www/html/storage/app/backups
|
||||||
|
depends_on:
|
||||||
|
db:
|
||||||
|
condition: service_healthy
|
||||||
|
redis:
|
||||||
|
condition: service_healthy
|
||||||
|
realtime:
|
||||||
|
condition: service_healthy
|
||||||
|
restart: always
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.middlewares.coolify-redirect-web-secure.redirectscheme.scheme=https"
|
||||||
|
- "traefik.http.routers.coolify-web.middlewares=coolify-redirect-web-secure"
|
||||||
|
- "traefik.http.routers.coolify-web.rule=Host(`${TRAEFIK_HOST}`)"
|
||||||
|
- "traefik.http.routers.coolify-web.entrypoints=web"
|
||||||
|
- "traefik.http.routers.coolify-web.service=coolify"
|
||||||
|
- "traefik.http.routers.coolify-web-secure.rule=Host(`${TRAEFIK_HOST}`)"
|
||||||
|
- "traefik.http.routers.coolify-web-secure.tls.certresolver=resolver"
|
||||||
|
- "traefik.http.routers.coolify-web-secure.entrypoints=web-secure"
|
||||||
|
- "traefik.http.routers.coolify-web-secure.middlewares=security-headers@file"
|
||||||
|
- "traefik.http.routers.coolify-web-secure.service=coolify"
|
||||||
|
- "traefik.http.routers.coolify-web-secure.priority=1"
|
||||||
|
- "traefik.http.services.coolify.loadbalancer.server.port=8080"
|
||||||
|
- "traefik.docker.network=${NETWORK_NAME}"
|
||||||
|
- "com.centurylinklabs.watchtower.enable=true"
|
||||||
|
networks:
|
||||||
|
- compose_network
|
||||||
|
realtime:
|
||||||
|
image: ghcr.io/coollabsio/coolify-realtime:1.0.10
|
||||||
|
container_name: coolify_realtime
|
||||||
|
environment:
|
||||||
|
APP_NAME: Coolify
|
||||||
|
SOKETI_DEBUG: "false"
|
||||||
|
SOKETI_DEFAULT_APP_ID: ${PUSHER_APP_ID}
|
||||||
|
SOKETI_DEFAULT_APP_KEY: ${PUSHER_APP_KEY}
|
||||||
|
SOKETI_DEFAULT_APP_SECRET: ${PUSHER_APP_SECRET}
|
||||||
|
volumes:
|
||||||
|
- ../.data/coolify/storage/ssh:/var/www/html/storage/app/ssh
|
||||||
|
restart: always
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:6001/ready && wget -qO- http://127.0.0.1:6002/ready"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 2s
|
||||||
|
retries: 10
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.coolify-realtime-web.rule=Host(`realtime.${TRAEFIK_HOST}`)"
|
||||||
|
- "traefik.http.routers.coolify-realtime-web.entrypoints=web"
|
||||||
|
- "traefik.http.routers.coolify-realtime-web.service=coolify-realtime"
|
||||||
|
- "traefik.http.routers.coolify-realtime-web-secure.rule=Host(`realtime.${TRAEFIK_HOST}`)"
|
||||||
|
- "traefik.http.routers.coolify-realtime-web-secure.tls.certresolver=resolver"
|
||||||
|
- "traefik.http.routers.coolify-realtime-web-secure.entrypoints=web-secure"
|
||||||
|
- "traefik.http.routers.coolify-realtime-web-secure.service=coolify-realtime"
|
||||||
|
- "traefik.http.services.coolify-realtime.loadbalancer.server.port=6001"
|
||||||
|
- "traefik.http.routers.coolify-terminal-ws.rule=Host(`${TRAEFIK_HOST}`) && PathPrefix(`/terminal/ws`)"
|
||||||
|
- "traefik.http.routers.coolify-terminal-ws.tls.certresolver=resolver"
|
||||||
|
- "traefik.http.routers.coolify-terminal-ws.entrypoints=web-secure"
|
||||||
|
- "traefik.http.routers.coolify-terminal-ws.service=coolify-terminal"
|
||||||
|
- "traefik.http.routers.coolify-terminal-ws.priority=100"
|
||||||
|
- "traefik.http.services.coolify-terminal.loadbalancer.server.port=6002"
|
||||||
|
- "traefik.docker.network=${NETWORK_NAME}"
|
||||||
|
- "com.centurylinklabs.watchtower.enable=true"
|
||||||
|
networks:
|
||||||
|
- compose_network
|
||||||
|
redis:
|
||||||
|
image: redis:7-alpine
|
||||||
|
container_name: coolify_redis
|
||||||
|
restart: always
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
networks:
|
||||||
|
- compose_network
|
||||||
|
db:
|
||||||
|
image: postgres:16-alpine
|
||||||
|
container_name: coolify_db
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: coolify
|
||||||
|
POSTGRES_USER: coolify
|
||||||
|
POSTGRES_PASSWORD: coolify
|
||||||
|
volumes:
|
||||||
|
- ../.data/coolify/db:/var/lib/postgresql/data
|
||||||
|
restart: always
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
networks:
|
||||||
|
- compose_network
|
||||||
|
networks:
|
||||||
|
compose_network:
|
||||||
|
name: ${NETWORK_NAME}
|
||||||
|
external: true
|
||||||
104
gitea/compose.yml
Normal file
104
gitea/compose.yml
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
---
|
||||||
|
services:
|
||||||
|
gitea:
|
||||||
|
image: gitea/gitea:latest
|
||||||
|
container_name: gitea
|
||||||
|
environment:
|
||||||
|
TZ: ${TIMEZONE:-Europe/Amsterdam}
|
||||||
|
USER_UID: 1000
|
||||||
|
USER_GID: 1000
|
||||||
|
GITEA__APP_NAME: dev.pivoine.art
|
||||||
|
GITEA__database__DB_TYPE: postgres
|
||||||
|
GITEA__database__HOST: gitea_db:5432
|
||||||
|
GITEA__database__NAME: gitea
|
||||||
|
GITEA__database__USER: gitea
|
||||||
|
GITEA__database__PASSWD: gitea
|
||||||
|
GITEA__server__DOMAIN: ${TRAEFIK_HOST}
|
||||||
|
GITEA__server__SSH_DOMAIN: ${TRAEFIK_HOST}
|
||||||
|
GITEA__server__ROOT_URL: https://${TRAEFIK_HOST}/
|
||||||
|
GITEA__server__PROTOCOL: http
|
||||||
|
GITEA__server__HTTP_PORT: 3000
|
||||||
|
GITEA__server__START_SSH_SERVER: "true"
|
||||||
|
GITEA__server__SSH_PORT: 2222
|
||||||
|
GITEA__server__SSH_LISTEN_PORT: 2222
|
||||||
|
GITEA__mailer__ENABLED: "true"
|
||||||
|
GITEA__mailer__PROTOCOL: smtp
|
||||||
|
GITEA__mailer__SMTP_ADDR: mailpit
|
||||||
|
GITEA__mailer__SMTP_PORT: 1025
|
||||||
|
GITEA__service__DISABLE_REGISTRATION: "false"
|
||||||
|
GITEA__service__REQUIRE_SIGNIN_VIEW: "false"
|
||||||
|
GITEA__service__ENABLE_NOTIFY_MAIL: "true"
|
||||||
|
GITEA__service__DEFAULT_EMAIL_NOTIFICATIONS: enabled
|
||||||
|
GITEA__packages__ENABLED: "true"
|
||||||
|
GITEA__actions__ENABLED: "true"
|
||||||
|
GITEA__ui__THEMES: gitea-auto,gitea-light,gitea-dark,arc-green,edge-auto,edge-dark,edge-light,everforest-auto,everforest-dark,everforest-light,gruvbox-auto,gruvbox-dark,gruvbox-light,gruvbox-material-auto,gruvbox-material-dark,gruvbox-material-light,nord,palenight,soft-era,sonokai,sonokai-andromeda,sonokai-atlantis,sonokai-espresso,sonokai-maia,sonokai-shusia
|
||||||
|
GITEA__ui__DEFAULT_THEME: edge-dark
|
||||||
|
GITEA__ui__ENABLE_FEED: "true"
|
||||||
|
ports:
|
||||||
|
- "2222:2222"
|
||||||
|
volumes:
|
||||||
|
- ../.data/gitea/data:/data
|
||||||
|
- ../.data/gitea/config:/etc/gitea
|
||||||
|
- ./themes:/data/gitea/public/assets/css:ro
|
||||||
|
- /etc/localtime:/etc/localtime:ro
|
||||||
|
depends_on:
|
||||||
|
db:
|
||||||
|
condition: service_healthy
|
||||||
|
restart: always
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.middlewares.gitea-redirect-web-secure.redirectscheme.scheme=https"
|
||||||
|
- "traefik.http.routers.gitea-web.middlewares=gitea-redirect-web-secure"
|
||||||
|
- "traefik.http.routers.gitea-web.rule=Host(`${TRAEFIK_HOST}`)"
|
||||||
|
- "traefik.http.routers.gitea-web.entrypoints=web"
|
||||||
|
- "traefik.http.routers.gitea-web-secure.rule=Host(`${TRAEFIK_HOST}`)"
|
||||||
|
- "traefik.http.routers.gitea-web-secure.tls.certresolver=resolver"
|
||||||
|
- "traefik.http.routers.gitea-web-secure.entrypoints=web-secure"
|
||||||
|
- "traefik.http.routers.gitea-web-secure.middlewares=security-headers@file"
|
||||||
|
- "traefik.http.services.gitea-web-secure.loadbalancer.server.port=3000"
|
||||||
|
- "traefik.docker.network=${NETWORK_NAME}"
|
||||||
|
- "com.centurylinklabs.watchtower.enable=true"
|
||||||
|
networks:
|
||||||
|
- compose_network
|
||||||
|
runner:
|
||||||
|
image: gitea/act_runner:latest
|
||||||
|
container_name: gitea_runner
|
||||||
|
privileged: true
|
||||||
|
command: ["act_runner", "daemon", "--config", "/data/config.yaml"]
|
||||||
|
environment:
|
||||||
|
TZ: ${TIMEZONE:-Europe/Amsterdam}
|
||||||
|
GITEA_INSTANCE_URL: https://${TRAEFIK_HOST}
|
||||||
|
GITEA_RUNNER_REGISTRATION_TOKEN: ${RUNNER_TOKEN}
|
||||||
|
GITEA_RUNNER_NAME: docker-runner
|
||||||
|
GITEA_RUNNER_LABELS: ubuntu-latest:docker://catthehacker/ubuntu:act-latest,ubuntu-22.04:docker://catthehacker/ubuntu:act-22.04,ubuntu-20.04:docker://catthehacker/ubuntu:act-20.04
|
||||||
|
DOCKER_HOST: unix:///var/run/docker.sock
|
||||||
|
volumes:
|
||||||
|
- ../.data/gitea/runner:/data
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
- ./runner-config.yaml:/data/config.yaml:ro
|
||||||
|
labels:
|
||||||
|
- "com.centurylinklabs.watchtower.enable=true"
|
||||||
|
restart: always
|
||||||
|
networks:
|
||||||
|
- compose_network
|
||||||
|
db:
|
||||||
|
image: postgres:16-alpine
|
||||||
|
container_name: gitea_db
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: gitea
|
||||||
|
POSTGRES_USER: gitea
|
||||||
|
POSTGRES_PASSWORD: gitea
|
||||||
|
volumes:
|
||||||
|
- ../.data/gitea/db:/var/lib/postgresql/data
|
||||||
|
restart: always
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
networks:
|
||||||
|
- compose_network
|
||||||
|
networks:
|
||||||
|
compose_network:
|
||||||
|
name: ${NETWORK_NAME}
|
||||||
|
external: true
|
||||||
32
gitea/runner-config.yaml
Normal file
32
gitea/runner-config.yaml
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
log:
|
||||||
|
level: info
|
||||||
|
|
||||||
|
runner:
|
||||||
|
file: .runner
|
||||||
|
capacity: 1
|
||||||
|
envs: {}
|
||||||
|
env_file: .env
|
||||||
|
timeout: 3h
|
||||||
|
insecure: false
|
||||||
|
fetch_timeout: 5s
|
||||||
|
fetch_interval: 2s
|
||||||
|
labels: []
|
||||||
|
|
||||||
|
cache:
|
||||||
|
enabled: true
|
||||||
|
dir: ""
|
||||||
|
host: ""
|
||||||
|
port: 0
|
||||||
|
external_server: ""
|
||||||
|
|
||||||
|
container:
|
||||||
|
network: ""
|
||||||
|
privileged: false
|
||||||
|
options: "-v /var/run/docker.sock:/var/run/docker.sock"
|
||||||
|
workdir_parent: ""
|
||||||
|
valid_volumes: []
|
||||||
|
docker_host: ""
|
||||||
|
force_pull: false
|
||||||
|
|
||||||
|
host:
|
||||||
|
workdir_parent: ""
|
||||||
1
gitea/themes/theme-edge-auto.css
Normal file
1
gitea/themes/theme-edge-auto.css
Normal file
File diff suppressed because one or more lines are too long
1
gitea/themes/theme-edge-dark.css
Normal file
1
gitea/themes/theme-edge-dark.css
Normal file
File diff suppressed because one or more lines are too long
1
gitea/themes/theme-edge-light.css
Normal file
1
gitea/themes/theme-edge-light.css
Normal file
File diff suppressed because one or more lines are too long
1
gitea/themes/theme-everforest-auto.css
Normal file
1
gitea/themes/theme-everforest-auto.css
Normal file
File diff suppressed because one or more lines are too long
1
gitea/themes/theme-everforest-dark.css
Normal file
1
gitea/themes/theme-everforest-dark.css
Normal file
File diff suppressed because one or more lines are too long
1
gitea/themes/theme-everforest-light.css
Normal file
1
gitea/themes/theme-everforest-light.css
Normal file
File diff suppressed because one or more lines are too long
1
gitea/themes/theme-gruvbox-auto.css
Normal file
1
gitea/themes/theme-gruvbox-auto.css
Normal file
File diff suppressed because one or more lines are too long
1
gitea/themes/theme-gruvbox-dark.css
Normal file
1
gitea/themes/theme-gruvbox-dark.css
Normal file
File diff suppressed because one or more lines are too long
1
gitea/themes/theme-gruvbox-light.css
Normal file
1
gitea/themes/theme-gruvbox-light.css
Normal file
File diff suppressed because one or more lines are too long
1
gitea/themes/theme-gruvbox-material-auto.css
Normal file
1
gitea/themes/theme-gruvbox-material-auto.css
Normal file
File diff suppressed because one or more lines are too long
1
gitea/themes/theme-gruvbox-material-dark.css
Normal file
1
gitea/themes/theme-gruvbox-material-dark.css
Normal file
File diff suppressed because one or more lines are too long
1
gitea/themes/theme-gruvbox-material-light.css
Normal file
1
gitea/themes/theme-gruvbox-material-light.css
Normal file
File diff suppressed because one or more lines are too long
1
gitea/themes/theme-nord.css
Normal file
1
gitea/themes/theme-nord.css
Normal file
File diff suppressed because one or more lines are too long
1
gitea/themes/theme-palenight.css
Normal file
1
gitea/themes/theme-palenight.css
Normal file
File diff suppressed because one or more lines are too long
1
gitea/themes/theme-soft-era.css
Normal file
1
gitea/themes/theme-soft-era.css
Normal file
File diff suppressed because one or more lines are too long
1
gitea/themes/theme-sonokai-andromeda.css
Normal file
1
gitea/themes/theme-sonokai-andromeda.css
Normal file
File diff suppressed because one or more lines are too long
1
gitea/themes/theme-sonokai-atlantis.css
Normal file
1
gitea/themes/theme-sonokai-atlantis.css
Normal file
File diff suppressed because one or more lines are too long
1
gitea/themes/theme-sonokai-espresso.css
Normal file
1
gitea/themes/theme-sonokai-espresso.css
Normal file
File diff suppressed because one or more lines are too long
1
gitea/themes/theme-sonokai-maia.css
Normal file
1
gitea/themes/theme-sonokai-maia.css
Normal file
File diff suppressed because one or more lines are too long
1
gitea/themes/theme-sonokai-shusia.css
Normal file
1
gitea/themes/theme-sonokai-shusia.css
Normal file
File diff suppressed because one or more lines are too long
1
gitea/themes/theme-sonokai.css
Normal file
1
gitea/themes/theme-sonokai.css
Normal file
File diff suppressed because one or more lines are too long
84
immich/compose.yml
Normal file
84
immich/compose.yml
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
---
|
||||||
|
services:
|
||||||
|
immich:
|
||||||
|
image: ghcr.io/immich-app/immich-server:release
|
||||||
|
container_name: immich
|
||||||
|
environment:
|
||||||
|
TZ: ${TIMEZONE:-Europe/Amsterdam}
|
||||||
|
DB_HOSTNAME: immich_db
|
||||||
|
DB_PORT: 5432
|
||||||
|
DB_USERNAME: immich
|
||||||
|
DB_PASSWORD: immich
|
||||||
|
DB_DATABASE_NAME: immich
|
||||||
|
REDIS_HOSTNAME: immich_redis
|
||||||
|
REDIS_PORT: 6379
|
||||||
|
IMMICH_MACHINE_LEARNING_URL: http://immich_ml:3003
|
||||||
|
volumes:
|
||||||
|
- ../.data/immich/upload:/usr/src/app/upload
|
||||||
|
- /etc/localtime:/etc/localtime:ro
|
||||||
|
depends_on:
|
||||||
|
db:
|
||||||
|
condition: service_healthy
|
||||||
|
redis:
|
||||||
|
condition: service_healthy
|
||||||
|
restart: always
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.middlewares.immich-redirect-web-secure.redirectscheme.scheme=https"
|
||||||
|
- "traefik.http.routers.immich-web.middlewares=immich-redirect-web-secure"
|
||||||
|
- "traefik.http.routers.immich-web.rule=Host(`${TRAEFIK_HOST}`)"
|
||||||
|
- "traefik.http.routers.immich-web.entrypoints=web"
|
||||||
|
- "traefik.http.routers.immich-web-secure.rule=Host(`${TRAEFIK_HOST}`)"
|
||||||
|
- "traefik.http.routers.immich-web-secure.tls.certresolver=resolver"
|
||||||
|
- "traefik.http.routers.immich-web-secure.entrypoints=web-secure"
|
||||||
|
- "traefik.http.routers.immich-web-secure.middlewares=security-headers@file"
|
||||||
|
- "traefik.http.services.immich-web-secure.loadbalancer.server.port=2283"
|
||||||
|
- "traefik.docker.network=${NETWORK_NAME}"
|
||||||
|
- "com.centurylinklabs.watchtower.enable=true"
|
||||||
|
networks:
|
||||||
|
- compose_network
|
||||||
|
ml:
|
||||||
|
image: ghcr.io/immich-app/immich-machine-learning:release
|
||||||
|
container_name: immich_ml
|
||||||
|
environment:
|
||||||
|
TZ: ${TIMEZONE:-Europe/Amsterdam}
|
||||||
|
volumes:
|
||||||
|
- ../.data/immich/model-cache:/cache
|
||||||
|
restart: always
|
||||||
|
labels:
|
||||||
|
- "com.centurylinklabs.watchtower.enable=true"
|
||||||
|
networks:
|
||||||
|
- compose_network
|
||||||
|
redis:
|
||||||
|
image: redis:7-alpine
|
||||||
|
container_name: immich_redis
|
||||||
|
restart: always
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
networks:
|
||||||
|
- compose_network
|
||||||
|
db:
|
||||||
|
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0
|
||||||
|
container_name: immich_db
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: immich
|
||||||
|
POSTGRES_USER: immich
|
||||||
|
POSTGRES_PASSWORD: immich
|
||||||
|
POSTGRES_INITDB_ARGS: --data-checksums
|
||||||
|
volumes:
|
||||||
|
- ../.data/immich/db:/var/lib/postgresql/data
|
||||||
|
restart: always
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
networks:
|
||||||
|
- compose_network
|
||||||
|
networks:
|
||||||
|
compose_network:
|
||||||
|
name: ${NETWORK_NAME}
|
||||||
|
external: true
|
||||||
59
joplin/compose.yml
Normal file
59
joplin/compose.yml
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
---
|
||||||
|
services:
|
||||||
|
joplin:
|
||||||
|
image: joplin/server:latest
|
||||||
|
container_name: joplin
|
||||||
|
environment:
|
||||||
|
TZ: ${TIMEZONE:-Europe/Amsterdam}
|
||||||
|
APP_PORT: 22300
|
||||||
|
APP_BASE_URL: https://${TRAEFIK_HOST}
|
||||||
|
DB_CLIENT: pg
|
||||||
|
POSTGRES_HOST: joplin_db
|
||||||
|
POSTGRES_PORT: 5432
|
||||||
|
POSTGRES_DATABASE: joplin
|
||||||
|
POSTGRES_USER: joplin
|
||||||
|
POSTGRES_PASSWORD: joplin
|
||||||
|
MAILER_ENABLED: 1
|
||||||
|
MAILER_HOST: mailpit
|
||||||
|
MAILER_PORT: 1025
|
||||||
|
MAILER_SECURE: 0
|
||||||
|
depends_on:
|
||||||
|
db:
|
||||||
|
condition: service_healthy
|
||||||
|
restart: always
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.middlewares.joplin-redirect-web-secure.redirectscheme.scheme=https"
|
||||||
|
- "traefik.http.routers.joplin-web.middlewares=joplin-redirect-web-secure"
|
||||||
|
- "traefik.http.routers.joplin-web.rule=Host(`${TRAEFIK_HOST}`)"
|
||||||
|
- "traefik.http.routers.joplin-web.entrypoints=web"
|
||||||
|
- "traefik.http.routers.joplin-web-secure.rule=Host(`${TRAEFIK_HOST}`)"
|
||||||
|
- "traefik.http.routers.joplin-web-secure.tls.certresolver=resolver"
|
||||||
|
- "traefik.http.routers.joplin-web-secure.entrypoints=web-secure"
|
||||||
|
- "traefik.http.routers.joplin-web-secure.middlewares=security-headers@file"
|
||||||
|
- "traefik.http.services.joplin-web-secure.loadbalancer.server.port=22300"
|
||||||
|
- "traefik.docker.network=${NETWORK_NAME}"
|
||||||
|
- "com.centurylinklabs.watchtower.enable=true"
|
||||||
|
networks:
|
||||||
|
- compose_network
|
||||||
|
db:
|
||||||
|
image: postgres:16-alpine
|
||||||
|
container_name: joplin_db
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: joplin
|
||||||
|
POSTGRES_USER: joplin
|
||||||
|
POSTGRES_PASSWORD: joplin
|
||||||
|
volumes:
|
||||||
|
- ../.data/joplin/db:/var/lib/postgresql/data
|
||||||
|
restart: always
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
networks:
|
||||||
|
- compose_network
|
||||||
|
networks:
|
||||||
|
compose_network:
|
||||||
|
name: ${NETWORK_NAME}
|
||||||
|
external: true
|
||||||
29
mailpit/compose.yml
Normal file
29
mailpit/compose.yml
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
---
|
||||||
|
services:
|
||||||
|
mailpit:
|
||||||
|
image: axllent/mailpit:latest
|
||||||
|
container_name: mailpit
|
||||||
|
environment:
|
||||||
|
TZ: ${TIMEZONE:-Europe/Amsterdam}
|
||||||
|
MP_SMTP_AUTH_ACCEPT_ANY: 1
|
||||||
|
MP_SMTP_AUTH_ALLOW_INSECURE: 1
|
||||||
|
MP_MAX_MESSAGES: 5000
|
||||||
|
MP_SMTP_RELAY_ALL: "true"
|
||||||
|
MP_SMTP_RELAY_HOST: ${SMTP_RELAY_HOST}
|
||||||
|
MP_SMTP_RELAY_PORT: ${SMTP_RELAY_PORT}
|
||||||
|
MP_SMTP_RELAY_USERNAME: ${SMTP_RELAY_USERNAME}
|
||||||
|
MP_SMTP_RELAY_PASSWORD: ${SMTP_RELAY_PASSWORD}
|
||||||
|
MP_SMTP_RELAY_AUTH: plain
|
||||||
|
MP_SMTP_RELAY_TLS: "true"
|
||||||
|
MP_UI_BIND_ADDR: 0.0.0.0:0
|
||||||
|
volumes:
|
||||||
|
- ../.data/mailpit:/data
|
||||||
|
restart: always
|
||||||
|
labels:
|
||||||
|
- "com.centurylinklabs.watchtower.enable=true"
|
||||||
|
networks:
|
||||||
|
- compose_network
|
||||||
|
networks:
|
||||||
|
compose_network:
|
||||||
|
name: ${NETWORK_NAME}
|
||||||
|
external: true
|
||||||
68
mattermost/compose.yml
Normal file
68
mattermost/compose.yml
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
---
|
||||||
|
services:
|
||||||
|
mattermost:
|
||||||
|
image: mattermost/mattermost-team-edition:latest
|
||||||
|
container_name: mattermost
|
||||||
|
security_opt:
|
||||||
|
- no-new-privileges:true
|
||||||
|
pids_limit: 200
|
||||||
|
tmpfs:
|
||||||
|
- /tmp
|
||||||
|
environment:
|
||||||
|
TZ: ${TIMEZONE:-Europe/Amsterdam}
|
||||||
|
MM_SQLSETTINGS_DRIVERNAME: postgres
|
||||||
|
MM_SQLSETTINGS_DATASOURCE: postgres://mattermost:mattermost@mattermost_db:5432/mattermost?sslmode=disable&connect_timeout=10
|
||||||
|
MM_BLEVESETTINGS_INDEXDIR: /mattermost/bleve-indexes
|
||||||
|
MM_SERVICESETTINGS_SITEURL: https://${TRAEFIK_HOST}
|
||||||
|
MM_SERVICESETTINGS_ENABLELOCALMODE: "true"
|
||||||
|
MM_EMAILSETTINGS_ENABLESMTPAUTH: "false"
|
||||||
|
MM_EMAILSETTINGS_SMTPSERVER: mailpit
|
||||||
|
MM_EMAILSETTINGS_SMTPPORT: "1025"
|
||||||
|
MM_EMAILSETTINGS_CONNECTIONSECURITY: ""
|
||||||
|
MM_EMAILSETTINGS_FEEDBACKNAME: Mattermost
|
||||||
|
volumes:
|
||||||
|
- ../.data/mattermost/config:/mattermost/config:rw
|
||||||
|
- ../.data/mattermost/data:/mattermost/data:rw
|
||||||
|
- ../.data/mattermost/plugins:/mattermost/plugins:rw
|
||||||
|
- ../.data/mattermost/client-plugins:/mattermost/client/plugins:rw
|
||||||
|
- ../.data/mattermost/bleve:/mattermost/bleve-indexes:rw
|
||||||
|
depends_on:
|
||||||
|
db:
|
||||||
|
condition: service_healthy
|
||||||
|
restart: always
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.middlewares.mattermost-redirect-web-secure.redirectscheme.scheme=https"
|
||||||
|
- "traefik.http.routers.mattermost-web.middlewares=mattermost-redirect-web-secure"
|
||||||
|
- "traefik.http.routers.mattermost-web.rule=Host(`${TRAEFIK_HOST}`)"
|
||||||
|
- "traefik.http.routers.mattermost-web.entrypoints=web"
|
||||||
|
- "traefik.http.routers.mattermost-web-secure.rule=Host(`${TRAEFIK_HOST}`)"
|
||||||
|
- "traefik.http.routers.mattermost-web-secure.tls.certresolver=resolver"
|
||||||
|
- "traefik.http.routers.mattermost-web-secure.entrypoints=web-secure"
|
||||||
|
- "traefik.http.routers.mattermost-web-secure.middlewares=security-headers@file"
|
||||||
|
- "traefik.http.services.mattermost-web-secure.loadbalancer.server.port=8065"
|
||||||
|
- "traefik.docker.network=${NETWORK_NAME}"
|
||||||
|
- "com.centurylinklabs.watchtower.enable=true"
|
||||||
|
networks:
|
||||||
|
- compose_network
|
||||||
|
db:
|
||||||
|
image: postgres:16-alpine
|
||||||
|
container_name: mattermost_db
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: mattermost
|
||||||
|
POSTGRES_USER: mattermost
|
||||||
|
POSTGRES_PASSWORD: mattermost
|
||||||
|
volumes:
|
||||||
|
- ../.data/mattermost/db:/var/lib/postgresql/data
|
||||||
|
restart: always
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
networks:
|
||||||
|
- compose_network
|
||||||
|
networks:
|
||||||
|
compose_network:
|
||||||
|
name: ${NETWORK_NAME}
|
||||||
|
external: true
|
||||||
122
sexy/compose.yml
Normal file
122
sexy/compose.yml
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
---
|
||||||
|
services:
|
||||||
|
sexy:
|
||||||
|
image: dev.pivoine.art/valknar/sexy:latest
|
||||||
|
container_name: sexy
|
||||||
|
user: node
|
||||||
|
working_dir: /home/node/app/packages/frontend
|
||||||
|
command: ["node", "build/index.js"]
|
||||||
|
environment:
|
||||||
|
TZ: ${TIMEZONE:-Europe/Amsterdam}
|
||||||
|
NODE_ENV: production
|
||||||
|
PUBLIC_API_URL: https://${TRAEFIK_HOST}/api
|
||||||
|
PUBLIC_URL: https://${TRAEFIK_HOST}
|
||||||
|
PUBLIC_UMAMI_ID: ""
|
||||||
|
volumes:
|
||||||
|
- ../.data/sexy/bundle:/home/node/app/packages/bundle
|
||||||
|
restart: always
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.middlewares.sexy-redirect-web-secure.redirectscheme.scheme=https"
|
||||||
|
- "traefik.http.routers.sexy-web.middlewares=sexy-redirect-web-secure"
|
||||||
|
- "traefik.http.routers.sexy-web.rule=Host(`${TRAEFIK_HOST}`)"
|
||||||
|
- "traefik.http.routers.sexy-web.entrypoints=web"
|
||||||
|
- "traefik.http.routers.sexy-web-secure.rule=Host(`${TRAEFIK_HOST}`)"
|
||||||
|
- "traefik.http.routers.sexy-web-secure.tls.certresolver=resolver"
|
||||||
|
- "traefik.http.routers.sexy-web-secure.entrypoints=web-secure"
|
||||||
|
- "traefik.http.middlewares.sexy-compress.compress=true"
|
||||||
|
- "traefik.http.routers.sexy-web-secure.middlewares=sexy-compress"
|
||||||
|
- "traefik.http.services.sexy-web-secure.loadbalancer.server.port=3000"
|
||||||
|
- "traefik.docker.network=${NETWORK_NAME}"
|
||||||
|
- "com.centurylinklabs.watchtower.enable=true"
|
||||||
|
networks:
|
||||||
|
- compose_network
|
||||||
|
directus:
|
||||||
|
image: directus/directus:11.12.0
|
||||||
|
container_name: sexy_directus
|
||||||
|
environment:
|
||||||
|
TZ: ${TIMEZONE:-Europe/Amsterdam}
|
||||||
|
SECRET: ${DIRECTUS_SECRET}
|
||||||
|
DB_CLIENT: pg
|
||||||
|
DB_HOST: sexy_db
|
||||||
|
DB_PORT: 5432
|
||||||
|
DB_DATABASE: directus
|
||||||
|
DB_USER: directus
|
||||||
|
DB_PASSWORD: directus
|
||||||
|
CACHE_ENABLED: "true"
|
||||||
|
CACHE_AUTO_PURGE: "true"
|
||||||
|
CACHE_STORE: redis
|
||||||
|
REDIS: redis://sexy_redis:6379
|
||||||
|
WEBSOCKETS_ENABLED: "true"
|
||||||
|
PUBLIC_URL: https://${TRAEFIK_HOST}/api
|
||||||
|
CORS_ENABLED: "true"
|
||||||
|
CORS_ORIGIN: https://${TRAEFIK_HOST}
|
||||||
|
SESSION_COOKIE_SECURE: "true"
|
||||||
|
SESSION_COOKIE_SAME_SITE: strict
|
||||||
|
SESSION_COOKIE_DOMAIN: ${TRAEFIK_HOST}
|
||||||
|
EXTENSIONS_PATH: ./extensions
|
||||||
|
EXTENSIONS_AUTO_RELOAD: "false"
|
||||||
|
CONTENT_SECURITY_POLICY_DIRECTIVES__FRAME_SRC: https://${TRAEFIK_HOST}
|
||||||
|
EMAIL_TRANSPORT: smtp
|
||||||
|
EMAIL_SMTP_HOST: mailpit
|
||||||
|
EMAIL_SMTP_PORT: 1025
|
||||||
|
USER_REGISTER_URL_ALLOW_LIST: https://${TRAEFIK_HOST}/signup/verify
|
||||||
|
PASSWORD_RESET_URL_ALLOW_LIST: https://${TRAEFIK_HOST}/password/reset
|
||||||
|
volumes:
|
||||||
|
- ../.data/sexy/uploads:/directus/uploads
|
||||||
|
- ../.data/sexy/bundle:/directus/extensions/sexy.pivoine.art
|
||||||
|
depends_on:
|
||||||
|
db:
|
||||||
|
condition: service_healthy
|
||||||
|
redis:
|
||||||
|
condition: service_healthy
|
||||||
|
restart: always
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.middlewares.sexy-directus-redirect-web-secure.redirectscheme.scheme=https"
|
||||||
|
- "traefik.http.routers.sexy-directus-web.middlewares=sexy-directus-redirect-web-secure"
|
||||||
|
- "traefik.http.routers.sexy-directus-web.rule=Host(`${TRAEFIK_HOST}`) && PathPrefix(`/api`)"
|
||||||
|
- "traefik.http.routers.sexy-directus-web.entrypoints=web"
|
||||||
|
- "traefik.http.routers.sexy-directus-web-secure.rule=Host(`${TRAEFIK_HOST}`) && PathPrefix(`/api`)"
|
||||||
|
- "traefik.http.routers.sexy-directus-web-secure.tls.certresolver=resolver"
|
||||||
|
- "traefik.http.routers.sexy-directus-web-secure.entrypoints=web-secure"
|
||||||
|
- "traefik.http.middlewares.sexy-directus-compress.compress=true"
|
||||||
|
- "traefik.http.middlewares.sexy-directus-strip.stripprefix.prefixes=/api"
|
||||||
|
- "traefik.http.routers.sexy-directus-web-secure.middlewares=sexy-directus-strip,sexy-directus-compress"
|
||||||
|
- "traefik.http.services.sexy-directus-web-secure.loadbalancer.server.port=8055"
|
||||||
|
- "traefik.docker.network=${NETWORK_NAME}"
|
||||||
|
- "com.centurylinklabs.watchtower.enable=true"
|
||||||
|
networks:
|
||||||
|
- compose_network
|
||||||
|
redis:
|
||||||
|
image: redis:7-alpine
|
||||||
|
container_name: sexy_redis
|
||||||
|
restart: always
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
networks:
|
||||||
|
- compose_network
|
||||||
|
db:
|
||||||
|
image: postgres:16-alpine
|
||||||
|
container_name: sexy_db
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: directus
|
||||||
|
POSTGRES_USER: directus
|
||||||
|
POSTGRES_PASSWORD: directus
|
||||||
|
volumes:
|
||||||
|
- ../.data/sexy/db:/var/lib/postgresql/data
|
||||||
|
restart: always
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
networks:
|
||||||
|
- compose_network
|
||||||
|
networks:
|
||||||
|
compose_network:
|
||||||
|
name: ${NETWORK_NAME}
|
||||||
|
external: true
|
||||||
48
traefik/compose.yml
Normal file
48
traefik/compose.yml
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
---
|
||||||
|
services:
|
||||||
|
traefik:
|
||||||
|
image: traefik:latest
|
||||||
|
container_name: traefik
|
||||||
|
command:
|
||||||
|
- "--api.dashboard=false"
|
||||||
|
- "--ping=true"
|
||||||
|
- "--log.level=INFO"
|
||||||
|
- "--accesslog=true"
|
||||||
|
- "--global.sendAnonymousUsage=false"
|
||||||
|
- "--global.checkNewVersion=true"
|
||||||
|
- "--providers.docker=true"
|
||||||
|
- "--providers.docker.exposedbydefault=false"
|
||||||
|
- "--providers.docker.network=${NETWORK_NAME}"
|
||||||
|
- "--providers.file.directory=/etc/traefik/dynamic"
|
||||||
|
- "--providers.file.watch=true"
|
||||||
|
- "--entrypoints.web.address=:80"
|
||||||
|
- "--entrypoints.web-secure.address=:443"
|
||||||
|
- "--entrypoints.web.http.redirections.entryPoint.to=web-secure"
|
||||||
|
- "--entrypoints.web.http.redirections.entryPoint.scheme=https"
|
||||||
|
- "--entrypoints.web.http.redirections.entryPoint.permanent=true"
|
||||||
|
- "--entrypoints.web-secure.http.middlewares=security-headers@file"
|
||||||
|
- "--certificatesresolvers.resolver.acme.tlschallenge=true"
|
||||||
|
- "--certificatesresolvers.resolver.acme.email=${ACME_EMAIL}"
|
||||||
|
- "--certificatesresolvers.resolver.acme.storage=/letsencrypt/acme.json"
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
- "443:443"
|
||||||
|
volumes:
|
||||||
|
- ../.data/traefik/letsencrypt:/letsencrypt
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
|
- ./dynamic:/etc/traefik/dynamic:ro
|
||||||
|
restart: always
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "traefik", "healthcheck", "--ping"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 3
|
||||||
|
start_period: 10s
|
||||||
|
labels:
|
||||||
|
- "com.centurylinklabs.watchtower.enable=true"
|
||||||
|
networks:
|
||||||
|
- compose_network
|
||||||
|
networks:
|
||||||
|
compose_network:
|
||||||
|
name: ${NETWORK_NAME}
|
||||||
|
external: true
|
||||||
43
traefik/dynamic/security.yaml
Normal file
43
traefik/dynamic/security.yaml
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
tls:
|
||||||
|
options:
|
||||||
|
default:
|
||||||
|
minVersion: VersionTLS12
|
||||||
|
cipherSuites:
|
||||||
|
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||||
|
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
|
||||||
|
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
|
||||||
|
- TLS_AES_128_GCM_SHA256
|
||||||
|
- TLS_AES_256_GCM_SHA384
|
||||||
|
- TLS_CHACHA20_POLY1305_SHA256
|
||||||
|
curvePreferences:
|
||||||
|
- CurveP521
|
||||||
|
- CurveP384
|
||||||
|
sniStrict: true
|
||||||
|
|
||||||
|
http:
|
||||||
|
middlewares:
|
||||||
|
security-headers:
|
||||||
|
headers:
|
||||||
|
stsSeconds: 31536000
|
||||||
|
stsIncludeSubdomains: true
|
||||||
|
stsPreload: true
|
||||||
|
forceSTSHeader: true
|
||||||
|
customFrameOptionsValue: "SAMEORIGIN"
|
||||||
|
browserXssFilter: true
|
||||||
|
contentTypeNosniff: true
|
||||||
|
referrerPolicy: "strict-origin-when-cross-origin"
|
||||||
|
customResponseHeaders:
|
||||||
|
X-Robots-Tag: "none,noarchive,nosnippet,notranslate,noimageindex"
|
||||||
|
Permissions-Policy: "camera=(), microphone=(), geolocation=(), payment=(), usb=(), magnetometer=(), accelerometer=(), gyroscope=()"
|
||||||
|
X-Content-Type-Options: "nosniff"
|
||||||
|
X-Frame-Options: "SAMEORIGIN"
|
||||||
|
rate-limit:
|
||||||
|
rateLimit:
|
||||||
|
average: 100
|
||||||
|
burst: 50
|
||||||
|
period: 1s
|
||||||
|
api-rate-limit:
|
||||||
|
rateLimit:
|
||||||
|
average: 30
|
||||||
|
burst: 15
|
||||||
|
period: 1s
|
||||||
55
umami/compose.yml
Normal file
55
umami/compose.yml
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
---
|
||||||
|
services:
|
||||||
|
umami:
|
||||||
|
image: ghcr.io/umami-software/umami:latest
|
||||||
|
container_name: umami
|
||||||
|
environment:
|
||||||
|
TZ: ${TIMEZONE:-Europe/Amsterdam}
|
||||||
|
DATABASE_URL: postgresql://umami:umami@db:5432/umami
|
||||||
|
APP_SECRET: ${APP_SECRET}
|
||||||
|
depends_on:
|
||||||
|
db:
|
||||||
|
condition: service_healthy
|
||||||
|
init: true
|
||||||
|
restart: always
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "curl http://localhost:3000/api/heartbeat"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.middlewares.umami-redirect-web-secure.redirectscheme.scheme=https"
|
||||||
|
- "traefik.http.routers.umami-web.middlewares=umami-redirect-web-secure"
|
||||||
|
- "traefik.http.routers.umami-web.rule=Host(`${TRAEFIK_HOST}`)"
|
||||||
|
- "traefik.http.routers.umami-web.entrypoints=web"
|
||||||
|
- "traefik.http.routers.umami-web-secure.rule=Host(`${TRAEFIK_HOST}`)"
|
||||||
|
- "traefik.http.routers.umami-web-secure.tls.certresolver=resolver"
|
||||||
|
- "traefik.http.routers.umami-web-secure.entrypoints=web-secure"
|
||||||
|
- "traefik.http.routers.umami-web-secure.middlewares=security-headers@file"
|
||||||
|
- "traefik.http.services.umami-web-secure.loadbalancer.server.port=3000"
|
||||||
|
- "traefik.docker.network=${NETWORK_NAME}"
|
||||||
|
- "com.centurylinklabs.watchtower.enable=true"
|
||||||
|
networks:
|
||||||
|
- compose_network
|
||||||
|
db:
|
||||||
|
image: postgres:15-alpine
|
||||||
|
container_name: umami_db
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: umami
|
||||||
|
POSTGRES_USER: umami
|
||||||
|
POSTGRES_PASSWORD: umami
|
||||||
|
volumes:
|
||||||
|
- ../.data/umami/db:/var/lib/postgresql/data
|
||||||
|
restart: always
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
networks:
|
||||||
|
- compose_network
|
||||||
|
networks:
|
||||||
|
compose_network:
|
||||||
|
name: ${NETWORK_NAME}
|
||||||
|
external: true
|
||||||
38
vaultwarden/compose.yml
Normal file
38
vaultwarden/compose.yml
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
---
|
||||||
|
services:
|
||||||
|
vaultwarden:
|
||||||
|
image: vaultwarden/server:latest
|
||||||
|
container_name: vaultwarden
|
||||||
|
environment:
|
||||||
|
TZ: ${TIMEZONE:-Europe/Amsterdam}
|
||||||
|
DOMAIN: https://${TRAEFIK_HOST}
|
||||||
|
WEBSOCKET_ENABLED: "true"
|
||||||
|
SIGNUPS_ALLOWED: "true"
|
||||||
|
INVITATIONS_ALLOWED: "true"
|
||||||
|
SHOW_PASSWORD_HINT: "false"
|
||||||
|
SMTP_HOST: mailpit
|
||||||
|
SMTP_FROM_NAME: Vaultwarden
|
||||||
|
SMTP_SECURITY: off
|
||||||
|
SMTP_PORT: 1025
|
||||||
|
volumes:
|
||||||
|
- ../.data/vaultwarden:/data
|
||||||
|
restart: always
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.middlewares.vaultwarden-redirect-web-secure.redirectscheme.scheme=https"
|
||||||
|
- "traefik.http.routers.vaultwarden-web.middlewares=vaultwarden-redirect-web-secure"
|
||||||
|
- "traefik.http.routers.vaultwarden-web.rule=Host(`${TRAEFIK_HOST}`)"
|
||||||
|
- "traefik.http.routers.vaultwarden-web.entrypoints=web"
|
||||||
|
- "traefik.http.routers.vaultwarden-web-secure.rule=Host(`${TRAEFIK_HOST}`)"
|
||||||
|
- "traefik.http.routers.vaultwarden-web-secure.tls.certresolver=resolver"
|
||||||
|
- "traefik.http.routers.vaultwarden-web-secure.entrypoints=web-secure"
|
||||||
|
- "traefik.http.routers.vaultwarden-web-secure.middlewares=security-headers@file"
|
||||||
|
- "traefik.http.services.vaultwarden-web-secure.loadbalancer.server.port=80"
|
||||||
|
- "traefik.docker.network=${NETWORK_NAME}"
|
||||||
|
- "com.centurylinklabs.watchtower.enable=true"
|
||||||
|
networks:
|
||||||
|
- compose_network
|
||||||
|
networks:
|
||||||
|
compose_network:
|
||||||
|
name: ${NETWORK_NAME}
|
||||||
|
external: true
|
||||||
22
watchtower/compose.yml
Normal file
22
watchtower/compose.yml
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
---
|
||||||
|
services:
|
||||||
|
watchtower:
|
||||||
|
image: containrrr/watchtower:latest
|
||||||
|
container_name: watchtower
|
||||||
|
environment:
|
||||||
|
DOCKER_API_VERSION: "1.44"
|
||||||
|
WATCHTOWER_POLL_INTERVAL: 300
|
||||||
|
WATCHTOWER_LABEL_ENABLE: "true"
|
||||||
|
WATCHTOWER_CLEANUP: "true"
|
||||||
|
WATCHTOWER_INCLUDE_STOPPED: "false"
|
||||||
|
WATCHTOWER_INCLUDE_RESTARTING: "true"
|
||||||
|
WATCHTOWER_RUN_ONCE: "false"
|
||||||
|
WATCHTOWER_NOTIFICATIONS: ${NOTIFICATIONS:-}
|
||||||
|
WATCHTOWER_NOTIFICATION_URL: ${NOTIFICATION_URL:-}
|
||||||
|
WATCHTOWER_LOG_LEVEL: info
|
||||||
|
WATCHTOWER_ROLLING_RESTART: "false"
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
restart: always
|
||||||
|
labels:
|
||||||
|
- "com.centurylinklabs.watchtower.enable=true"
|
||||||
Reference in New Issue
Block a user