Tots els compose
This commit is contained in:
34
adguard/docker-compose.yml
Normal file
34
adguard/docker-compose.yml
Normal file
@@ -0,0 +1,34 @@
|
||||
# /opt/stacks/adguardhome/docker-compose.yml
|
||||
|
||||
services:
|
||||
adguardhome:
|
||||
container_name: adguardhome
|
||||
image: adguard/adguardhome:latest
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "53:53/tcp" # DNS TCP — públic (necessari per a tota la xarxa)
|
||||
- "53:53/udp" # DNS UDP — públic (necessari per a tota la xarxa)
|
||||
- "853:853/tcp" # DNS-over-TLS — públic (clients externs)
|
||||
- "3000:3000" # Wizard inicial (només local — tancar després de setup)
|
||||
- "8080:80" # Dashboard web (només local → via Nginx)
|
||||
volumes:
|
||||
- adguard_work:/opt/adguardhome/work # Volum named — evita reset al wizard
|
||||
- adguard_conf:/opt/adguardhome/conf # Volum named — configuració persistent
|
||||
environment:
|
||||
TZ: Europe/Madrid
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
networks:
|
||||
- dns-net
|
||||
- shared_net
|
||||
|
||||
volumes:
|
||||
adguard_work:
|
||||
adguard_conf:
|
||||
|
||||
networks:
|
||||
dns-net:
|
||||
driver: bridge
|
||||
shared_net:
|
||||
external: true
|
||||
name: shared_net
|
||||
17
astro/Dockerfile
Normal file
17
astro/Dockerfile
Normal file
@@ -0,0 +1,17 @@
|
||||
# ── Fase 1: Compilació amb Node.js ────────
|
||||
FROM node:20-alpine AS builder
|
||||
WORKDIR /app
|
||||
# Instal·la dependències primer (aprofita la cache de Docker)
|
||||
COPY package*.json ./
|
||||
RUN npm ci
|
||||
# Copia el codi font i compila
|
||||
COPY . .
|
||||
RUN npm run build
|
||||
|
||||
# ── Fase 2: Servir amb Nginx (imatge mínima) ──
|
||||
FROM nginx:alpine
|
||||
# Copia NOMÉS la carpeta dist/ de la fase anterior
|
||||
COPY --from=builder /app/dist /usr/share/nginx/html
|
||||
# Configuració Nginx per a SPA i rutes d'Astro
|
||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||
EXPOSE 80
|
||||
28
astro/docker-compose.yml
Normal file
28
astro/docker-compose.yml
Normal file
@@ -0,0 +1,28 @@
|
||||
# /opt/stacks/astro-web/docker-compose.yml
|
||||
|
||||
services:
|
||||
|
||||
astro-web:
|
||||
container_name: astro-web
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
image: astro-web:local # Nom explícit per a la imatge buildada
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
TZ: Europe/Madrid
|
||||
ports:
|
||||
- "8087:80" # Només local → via Nginx Proxy Manager
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:80"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 15s
|
||||
networks:
|
||||
- shared_net
|
||||
|
||||
networks:
|
||||
shared_net:
|
||||
external: true
|
||||
name: shared_net
|
||||
16
astro/nginx.conf
Normal file
16
astro/nginx.conf
Normal file
@@ -0,0 +1,16 @@
|
||||
server {
|
||||
listen 80;
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
# Rutes d'Astro: si no troba el fitxer, retorna 404.html
|
||||
location / {
|
||||
try_files $uri $uri/ $uri.html =404;
|
||||
}
|
||||
|
||||
# Cache agressiva per a assets compilats (hash al nom)
|
||||
location /_astro/ {
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
}
|
||||
103
authentik/docker-compose.yml
Normal file
103
authentik/docker-compose.yml
Normal file
@@ -0,0 +1,103 @@
|
||||
# /opt/stacks/authentik/docker-compose.yml
|
||||
|
||||
services:
|
||||
|
||||
# ── Base de dades PostgreSQL ─────────────
|
||||
postgresql:
|
||||
container_name: authentik-postgres
|
||||
image: postgres:16-alpine
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
POSTGRES_PASSWORD: '${PG_PASS}'
|
||||
POSTGRES_USER: authentik
|
||||
POSTGRES_DB: authentik
|
||||
volumes:
|
||||
- pg_data:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U authentik -d authentik"]
|
||||
interval: 10s
|
||||
timeout: 5s # Afegit
|
||||
retries: 5
|
||||
start_period: 30s # Afegit
|
||||
networks: [authentik_net]
|
||||
|
||||
# ── Redis per a sessions ─────────────────
|
||||
redis:
|
||||
container_name: authentik-redis
|
||||
image: redis:7.4-alpine
|
||||
restart: unless-stopped
|
||||
command: redis-server --requirepass '${REDIS_PASS}'
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "-a", "${REDIS_PASS}", "ping"]
|
||||
interval: 10s
|
||||
timeout: 5s # Afegit
|
||||
retries: 5
|
||||
start_period: 15s # Afegit
|
||||
networks: [authentik_net]
|
||||
|
||||
# ── Authentik Server (API + UI) ───────────
|
||||
server:
|
||||
container_name: authentik-server
|
||||
image: ghcr.io/goauthentik/server:2026.5.3 # Actualitzat a darrera versió estable
|
||||
restart: unless-stopped
|
||||
command: server
|
||||
environment:
|
||||
# ⚠️ NO afegir TZ aquí — trenca OAuth/SAML (doc oficial)
|
||||
AUTHENTIK_REDIS__HOST: redis
|
||||
AUTHENTIK_REDIS__PASSWORD: '${REDIS_PASS}'
|
||||
AUTHENTIK_POSTGRESQL__HOST: postgresql
|
||||
AUTHENTIK_POSTGRESQL__USER: authentik
|
||||
AUTHENTIK_POSTGRESQL__NAME: authentik
|
||||
AUTHENTIK_POSTGRESQL__PASSWORD: '${PG_PASS}'
|
||||
AUTHENTIK_SECRET_KEY: '${AUTHENTIK_SECRET_KEY}'
|
||||
AUTHENTIK_ERROR_REPORTING__ENABLED: "false" # String, no booleà YAML
|
||||
ports:
|
||||
- "127.0.0.1:9000:9000" # HTTP (només local → via Nginx)
|
||||
- "127.0.0.1:9443:9443" # HTTPS (només local → via Nginx)
|
||||
volumes:
|
||||
- authentik_media:/media
|
||||
- authentik_templates:/templates
|
||||
depends_on:
|
||||
postgresql:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
networks: [authentik_net, shared_net]
|
||||
|
||||
# ── Authentik Worker (tasques en segon pla) ──
|
||||
worker:
|
||||
container_name: authentik-worker
|
||||
image: ghcr.io/goauthentik/server:2026.5.3 # Mateixa versió que server
|
||||
restart: unless-stopped
|
||||
command: worker
|
||||
environment:
|
||||
# ⚠️ NO afegir TZ aquí — trenca OAuth/SAML (doc oficial)
|
||||
AUTHENTIK_REDIS__HOST: redis
|
||||
AUTHENTIK_REDIS__PASSWORD: '${REDIS_PASS}'
|
||||
AUTHENTIK_POSTGRESQL__HOST: postgresql
|
||||
AUTHENTIK_POSTGRESQL__USER: authentik
|
||||
AUTHENTIK_POSTGRESQL__NAME: authentik
|
||||
AUTHENTIK_POSTGRESQL__PASSWORD: '${PG_PASS}'
|
||||
AUTHENTIK_SECRET_KEY: '${AUTHENTIK_SECRET_KEY}'
|
||||
volumes:
|
||||
- authentik_media:/media
|
||||
- authentik_templates:/templates # Afegit: worker també necessita templates
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro # Gestió automàtica d'Outposts
|
||||
depends_on:
|
||||
postgresql:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
networks: [authentik_net]
|
||||
|
||||
volumes:
|
||||
pg_data:
|
||||
authentik_media:
|
||||
authentik_templates:
|
||||
|
||||
networks:
|
||||
authentik_net:
|
||||
driver: bridge
|
||||
shared_net:
|
||||
external: true
|
||||
name: shared_net
|
||||
19
bentopdf/docker-compose.yml
Normal file
19
bentopdf/docker-compose.yml
Normal file
@@ -0,0 +1,19 @@
|
||||
# /opt/stacks/bentopdf/docker-compose.yml
|
||||
|
||||
services:
|
||||
|
||||
bentopdf:
|
||||
container_name: bentopdf
|
||||
image: bentopdfteam/bentopdf:latest # Imatge activa — bentopdf/bentopdf és deprecated!
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
TZ: Europe/Madrid
|
||||
ports:
|
||||
- "9999:8080" # Només local → via Nginx Proxy Manager
|
||||
networks:
|
||||
- shared_net
|
||||
|
||||
networks:
|
||||
shared_net:
|
||||
external: true
|
||||
name: shared_net
|
||||
23
beszel/docker-compose.yml
Normal file
23
beszel/docker-compose.yml
Normal file
@@ -0,0 +1,23 @@
|
||||
# /opt/stacks/beszel/docker-compose.yml
|
||||
|
||||
services:
|
||||
beszel:
|
||||
image: henrygd/beszel:latest
|
||||
container_name: beszel
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8090:8090" # Interfície web (només local)
|
||||
volumes:
|
||||
- beszel_data:/beszel_data # Volum named — més estable que path relatiu
|
||||
environment:
|
||||
TZ: Europe/Madrid
|
||||
networks:
|
||||
- shared_net
|
||||
|
||||
volumes:
|
||||
beszel_data:
|
||||
|
||||
networks:
|
||||
shared_net:
|
||||
external: true
|
||||
name: shared_net
|
||||
30
ddns-go/docker-compose.yml
Normal file
30
ddns-go/docker-compose.yml
Normal file
@@ -0,0 +1,30 @@
|
||||
# /opt/stacks/ddns/docker-compose.yml
|
||||
|
||||
services:
|
||||
|
||||
ddns-go:
|
||||
container_name: ddns-go
|
||||
image: jeessy/ddns-go:latest
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "9876:9876" # UI web (només local → via Nginx)
|
||||
environment:
|
||||
TZ: Europe/Madrid
|
||||
volumes:
|
||||
- ddns_data:/root # Persisteix la configuració
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-qO-", "http://localhost:9876"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 15s
|
||||
networks:
|
||||
- shared_net
|
||||
|
||||
volumes:
|
||||
ddns_data:
|
||||
|
||||
networks:
|
||||
shared_net:
|
||||
external: true
|
||||
name: shared_net
|
||||
66
flowise/docker-compose.yml
Normal file
66
flowise/docker-compose.yml
Normal file
@@ -0,0 +1,66 @@
|
||||
# /opt/stacks/flowise/docker-compose.yml
|
||||
|
||||
services:
|
||||
|
||||
postgres:
|
||||
image: postgres:15-alpine
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
POSTGRES_USER: '${POSTGRES_USER}'
|
||||
POSTGRES_PASSWORD: '${POSTGRES_PASSWORD}'
|
||||
POSTGRES_DB: flowise
|
||||
TZ: Europe/Madrid
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d flowise"]
|
||||
interval: 10s
|
||||
timeout: 5s # Afegit: timeout explícit
|
||||
retries: 5
|
||||
start_period: 30s # Afegit: marge per a l'arrencada inicial
|
||||
networks:
|
||||
- flowise-net
|
||||
|
||||
flowise:
|
||||
image: flowiseai/flowise:latest
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "3000:3000" # Interfície web (només local → via Nginx)
|
||||
environment:
|
||||
TZ: Europe/Madrid
|
||||
# Base de dades
|
||||
DATABASE_TYPE: postgres
|
||||
DATABASE_HOST: postgres
|
||||
DATABASE_PORT: 5432
|
||||
DATABASE_NAME: flowise
|
||||
DATABASE_USER: '${POSTGRES_USER}'
|
||||
DATABASE_PASSWORD: '${POSTGRES_PASSWORD}'
|
||||
# Autenticació
|
||||
FLOWISE_USERNAME: '${FLOWISE_USERNAME}'
|
||||
FLOWISE_PASSWORD: '${FLOWISE_PASSWORD}'
|
||||
# Seguretat — CRÍTIC: fes backup d'aquesta clau!
|
||||
FLOWISE_SECRETKEY_OVERWRITE: '${FLOWISE_SECRETKEY}'
|
||||
# Paths i logs
|
||||
APIKEY_PATH: /root/.flowise
|
||||
SECRETKEY_PATH: /root/.flowise
|
||||
LOG_LEVEL: info
|
||||
LOG_PATH: /root/.flowise/logs
|
||||
volumes:
|
||||
- flowise_data:/root/.flowise
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- flowise-net
|
||||
- shared_net
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
flowise_data:
|
||||
|
||||
networks:
|
||||
flowise-net:
|
||||
driver: bridge
|
||||
shared_net:
|
||||
external: true
|
||||
name: shared_net
|
||||
83
gitea/docker-compose.yml
Normal file
83
gitea/docker-compose.yml
Normal file
@@ -0,0 +1,83 @@
|
||||
# /opt/stacks/gitea/docker-compose.yml
|
||||
|
||||
services:
|
||||
|
||||
# ── MariaDB ──────────────────────────────
|
||||
db:
|
||||
container_name: gitea-db
|
||||
image: mariadb:10.11
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
TZ: Europe/Madrid
|
||||
MYSQL_ROOT_PASSWORD: '${MYSQL_ROOT_PASSWORD}'
|
||||
MYSQL_DATABASE: gitea
|
||||
MYSQL_USER: gitea
|
||||
MYSQL_PASSWORD: '${MYSQL_PASSWORD}'
|
||||
volumes:
|
||||
- gitea_db:/var/lib/mysql
|
||||
healthcheck:
|
||||
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 30s
|
||||
networks: [gitea_net]
|
||||
|
||||
# ── Gitea ────────────────────────────────
|
||||
gitea:
|
||||
container_name: gitea
|
||||
image: gitea/gitea:1 # Pinnat a major version — evita trencaments per latest
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
TZ: Europe/Madrid # Substitueix els bind mounts de timezone
|
||||
USER_UID: 1000
|
||||
USER_GID: 1000
|
||||
# Connexió a MariaDB
|
||||
GITEA__database__DB_TYPE: mysql
|
||||
GITEA__database__HOST: db:3306
|
||||
GITEA__database__NAME: gitea
|
||||
GITEA__database__USER: gitea
|
||||
GITEA__database__PASSWD: '${MYSQL_PASSWORD}'
|
||||
# URL pública (obligatori per a clons SSH i web)
|
||||
GITEA__server__ROOT_URL: 'https://git.domini.com/'
|
||||
GITEA__server__SSH_DOMAIN: git.domini.com
|
||||
GITEA__server__SSH_PORT: 2222
|
||||
GITEA__server__DOMAIN: git.domini.com
|
||||
# Desactiva el registre públic
|
||||
GITEA__service__DISABLE_REGISTRATION: 'true'
|
||||
# Seguretat
|
||||
GITEA__security__SECRET_KEY: '${GITEA_SECRET_KEY}'
|
||||
GITEA__security__INTERNAL_TOKEN: '${GITEA_INTERNAL_TOKEN}'
|
||||
# Mailer — descomenta i configura per a notificacions per email
|
||||
# GITEA__mailer__ENABLED: 'true'
|
||||
# GITEA__mailer__SMTP_ADDR: mail.domini.com
|
||||
# GITEA__mailer__SMTP_PORT: '587'
|
||||
# GITEA__mailer__USER: '${GITEA_SMTP_USER}'
|
||||
# GITEA__mailer__PASSWD: '${GITEA_SMTP_PASSWORD}'
|
||||
# GITEA__mailer__FROM: 'Gitea <gitea@domini.com>'
|
||||
volumes:
|
||||
- gitea_data:/data
|
||||
ports:
|
||||
- "3000:3000" # Web UI → via Nginx Proxy Manager
|
||||
- "2222:22" # SSH públic — necessari per a git push/pull directe
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:3000"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 5
|
||||
start_period: 60s
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
networks: [gitea_net, shared_net]
|
||||
|
||||
volumes:
|
||||
gitea_db:
|
||||
gitea_data:
|
||||
|
||||
networks:
|
||||
gitea_net:
|
||||
driver: bridge
|
||||
shared_net:
|
||||
external: true
|
||||
name: shared_net
|
||||
21
glance/docker-compose.yml
Normal file
21
glance/docker-compose.yml
Normal file
@@ -0,0 +1,21 @@
|
||||
# /opt/stacks/glance/docker-compose.yml
|
||||
|
||||
services:
|
||||
glance:
|
||||
image: glanceapp/glance:latest
|
||||
container_name: glance
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "127.0.0.1:8080:8080" # Interfície web (només local)
|
||||
volumes:
|
||||
- ./glance.yml:/app/glance.yml:ro # Configuració principal
|
||||
- ./assets:/app/assets:ro # Assets locals (icones, imatges)
|
||||
environment:
|
||||
TZ: Europe/Madrid
|
||||
networks:
|
||||
- shared_net
|
||||
|
||||
networks:
|
||||
shared_net:
|
||||
external: true
|
||||
name: shared_net
|
||||
10
glance/glance.yml
Normal file
10
glance/glance.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
server:
|
||||
port: 8080
|
||||
|
||||
pages:
|
||||
- name: Inici
|
||||
columns:
|
||||
- size: full
|
||||
widgets:
|
||||
- type: clock
|
||||
hour-format: 24h
|
||||
15
headscale/config.yml
Normal file
15
headscale/config.yml
Normal file
@@ -0,0 +1,15 @@
|
||||
server_url: https://headscale.el-teu-domini.com
|
||||
listen_addr: 0.0.0.0:8080
|
||||
metrics_listen_addr: 0.0.0.0:9090
|
||||
private_key_path: /var/lib/headscale/private.key
|
||||
noise:
|
||||
private_key_path: /var/lib/headscale/noise_private.key
|
||||
ip_prefixes:
|
||||
- 100.64.0.0/10 # Rang IPs Tailscale
|
||||
dns_config:
|
||||
magic_dns: true
|
||||
base_domain: homelab.intern
|
||||
nameservers:
|
||||
- 9.9.9.9
|
||||
db_type: sqlite3
|
||||
db_path: /var/lib/headscale/db.sqlite
|
||||
48
headscale/docker-compose.yml
Normal file
48
headscale/docker-compose.yml
Normal file
@@ -0,0 +1,48 @@
|
||||
# /opt/stacks/headscale/docker-compose.yml
|
||||
|
||||
services:
|
||||
headscale:
|
||||
container_name: headscale
|
||||
image: headscale/headscale:latest
|
||||
restart: unless-stopped
|
||||
command: serve
|
||||
ports:
|
||||
- "8080:8080" # API i clients (només local → via Nginx)
|
||||
- "9090:9090" # Mètriques Prometheus (mai públic)
|
||||
volumes:
|
||||
- headscale_config:/etc/headscale # Configuració persistent
|
||||
- headscale_data:/var/lib/headscale # Dades persistents
|
||||
- headscale_socket:/var/run/headscale # Socket Unix per a la UI
|
||||
environment:
|
||||
TZ: Europe/Madrid
|
||||
networks:
|
||||
- headscale-net
|
||||
- shared_net
|
||||
|
||||
headscale-ui:
|
||||
container_name: headscale-ui
|
||||
image: ghcr.io/gurucomputing/headscale-ui:latest
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8081:80" # Interfície web (només local → via Nginx)
|
||||
volumes:
|
||||
- headscale_socket:/var/run/headscale # Socket Unix compartit amb headscale
|
||||
environment:
|
||||
TZ: Europe/Madrid
|
||||
depends_on:
|
||||
- headscale
|
||||
networks:
|
||||
- headscale-net
|
||||
- shared_net
|
||||
|
||||
volumes:
|
||||
headscale_config:
|
||||
headscale_data:
|
||||
headscale_socket:
|
||||
|
||||
networks:
|
||||
headscale-net:
|
||||
driver: bridge
|
||||
shared_net:
|
||||
external: true
|
||||
name: shared_net
|
||||
28
homarr/docker-compose.yml
Normal file
28
homarr/docker-compose.yml
Normal file
@@ -0,0 +1,28 @@
|
||||
# /opt/stacks/homarr/docker-compose.yml
|
||||
|
||||
services:
|
||||
homarr:
|
||||
image: ghcr.io/ajnart/homarr:latest
|
||||
container_name: homarr
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "7575:7575" # Interfície web (només local)
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro # :ro = només lectura
|
||||
- homarr_configs:/app/data/configs # Configuració
|
||||
- homarr_icons:/app/public/icons # Icones personalitzades
|
||||
- homarr_data:/data # Dades persistents
|
||||
environment:
|
||||
TZ: Europe/Madrid
|
||||
networks:
|
||||
- shared_net
|
||||
|
||||
volumes:
|
||||
homarr_configs:
|
||||
homarr_icons:
|
||||
homarr_data:
|
||||
|
||||
networks:
|
||||
shared_net:
|
||||
external: true
|
||||
name: shared_net
|
||||
112
immich/docker-compose.yml
Normal file
112
immich/docker-compose.yml
Normal file
@@ -0,0 +1,112 @@
|
||||
# /opt/stacks/immich/docker-compose.yml
|
||||
# Documentació oficial: https://docs.immich.app/install/docker-compose/
|
||||
|
||||
services:
|
||||
|
||||
# ── Immich Server ─────────────────────────
|
||||
immich-server:
|
||||
container_name: immich-server
|
||||
image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release}
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
TZ: ${TZ}
|
||||
DB_URL: "postgresql://${DB_USERNAME}:${DB_PASSWORD}@immich-db:5432/${DB_DATABASE_NAME}"
|
||||
REDIS_HOSTNAME: immich-redis
|
||||
IMMICH_ENV: production
|
||||
UPLOAD_LOCATION: ${UPLOAD_LOCATION}
|
||||
volumes:
|
||||
- ${UPLOAD_LOCATION}:/usr/src/app/upload
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
ports:
|
||||
- "127.0.0.1:2283:2283" # Web UI → via Nginx Proxy Manager
|
||||
depends_on:
|
||||
immich-db:
|
||||
condition: service_healthy
|
||||
immich-redis:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:2283/api/server/ping"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 5
|
||||
start_period: 60s
|
||||
networks:
|
||||
- immich_net
|
||||
- shared_net
|
||||
|
||||
|
||||
# ── Machine Learning ──────────────────────
|
||||
immich-machine-learning:
|
||||
container_name: immich-machine-learning
|
||||
image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
TZ: ${TZ}
|
||||
IMMICH_ENV: production
|
||||
volumes:
|
||||
- model-cache:/cache
|
||||
healthcheck:
|
||||
test: ["CMD", "python3", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:3003/ping')"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 5
|
||||
start_period: 120s # El model triga a carregar-se
|
||||
networks:
|
||||
- immich_net
|
||||
|
||||
|
||||
# ── Redis ─────────────────────────────────
|
||||
immich-redis:
|
||||
container_name: immich-redis
|
||||
image: redis:7-alpine
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
TZ: ${TZ}
|
||||
volumes:
|
||||
- redis-data:/data
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 10s
|
||||
networks:
|
||||
- immich_net
|
||||
|
||||
|
||||
# ── PostgreSQL + VectorChord ───────────────
|
||||
# Imatge oficial d'Immich — substitueix tensorchord/pgvecto-rs (obsoleta)
|
||||
immich-db:
|
||||
container_name: immich-db
|
||||
image: ghcr.io/immich-app/postgres:17-vectorchord
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
TZ: ${TZ}
|
||||
POSTGRES_DB: ${DB_DATABASE_NAME}
|
||||
POSTGRES_USER: ${DB_USERNAME}
|
||||
POSTGRES_PASSWORD: ${DB_PASSWORD}
|
||||
POSTGRES_INITDB_ARGS: "--data-checksums"
|
||||
volumes:
|
||||
- pgdata:/var/lib/postgresql/data # Volum named — mai network share
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U ${DB_USERNAME} -d ${DB_DATABASE_NAME}"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 30s
|
||||
networks:
|
||||
- immich_net
|
||||
|
||||
|
||||
volumes:
|
||||
pgdata:
|
||||
model-cache:
|
||||
redis-data:
|
||||
|
||||
|
||||
networks:
|
||||
immich_net:
|
||||
driver: bridge
|
||||
shared_net:
|
||||
external: true
|
||||
name: shared_net
|
||||
44
jenkins/docker-compose.yml
Normal file
44
jenkins/docker-compose.yml
Normal file
@@ -0,0 +1,44 @@
|
||||
# /opt/stacks/jenkins/docker-compose.yml
|
||||
#
|
||||
# SEGURETAT: Jenkins s'executa com a usuari jenkins (uid 1000), no com a root.
|
||||
# Per accedir a Docker des de pipelines, s'usa Docker-in-Docker (dind) o
|
||||
# s'afegeix l'usuari jenkins al grup docker del host (vegeu notes al final).
|
||||
|
||||
services:
|
||||
|
||||
jenkins:
|
||||
container_name: jenkins
|
||||
image: jenkins/jenkins:lts-jdk17
|
||||
restart: unless-stopped
|
||||
# NO usar user: root — risc crític amb docker.sock muntat
|
||||
# L'uid 1000 és l'usuari jenkins per defecte de la imatge oficial
|
||||
environment:
|
||||
TZ: Europe/Madrid
|
||||
JAVA_OPTS: >-
|
||||
-Djenkins.install.runSetupWizard=true
|
||||
-Xmx512m
|
||||
-Xms256m
|
||||
volumes:
|
||||
- jenkins_home:/var/jenkins_home
|
||||
# Docker socket — NOMÉS si has fet: sudo usermod -aG docker <host_user>
|
||||
# i has ajustat els permisos del socket (vegeu notes)
|
||||
# - /var/run/docker.sock:/var/run/docker.sock
|
||||
ports:
|
||||
- "8089:8080" # Web UI → via Nginx Proxy Manager
|
||||
- "50000:50000" # Agents Jenkins (JNLP)
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8080/login"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 5
|
||||
start_period: 90s # Jenkins triga a arrencar
|
||||
networks:
|
||||
- shared_net
|
||||
|
||||
volumes:
|
||||
jenkins_home:
|
||||
|
||||
networks:
|
||||
shared_net:
|
||||
external: true
|
||||
name: shared_net
|
||||
27
kavita/docker-compose.yml
Normal file
27
kavita/docker-compose.yml
Normal file
@@ -0,0 +1,27 @@
|
||||
# /opt/stacks/kavita/docker-compose.yml
|
||||
|
||||
services:
|
||||
|
||||
kavita:
|
||||
container_name: kavita
|
||||
image: jvmilazz0/kavita:latest
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
TZ: Europe/Madrid
|
||||
volumes:
|
||||
# Carpeta amb els teus llibres/còmics/manga (read-only — Kavita no necessita escriure-hi)
|
||||
- /ruta/als/teus/llibres:/manga:ro
|
||||
# Configuració i base de dades SQLite de Kavita
|
||||
- kavita_config:/kavita/config
|
||||
ports:
|
||||
- "127.0.0.1:5000:5000" # Només local → via Nginx Proxy Manager
|
||||
networks:
|
||||
- shared_net
|
||||
|
||||
volumes:
|
||||
kavita_config:
|
||||
|
||||
networks:
|
||||
shared_net:
|
||||
external: true
|
||||
name: shared_net
|
||||
42
localai/docker-compose.yml
Normal file
42
localai/docker-compose.yml
Normal file
@@ -0,0 +1,42 @@
|
||||
# /opt/stacks/localai/docker-compose.yml
|
||||
|
||||
services:
|
||||
|
||||
localai:
|
||||
container_name: localai
|
||||
image: localai/localai:latest-aio-cpu
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8080:8080" # API LocalAI (només local → via Nginx)
|
||||
environment:
|
||||
TZ: Europe/Madrid
|
||||
# Configuració de rendiment (prefix LOCALAI_ obligatori)
|
||||
LOCALAI_THREADS: 4 # Fils de CPU a usar
|
||||
LOCALAI_CONTEXT_SIZE: 4096 # Context màxim en tokens
|
||||
LOCALAI_MODELS_PATH: /models # Path dels models GGUF
|
||||
# Logs i telemetria
|
||||
LOCALAI_LOG_LEVEL: info
|
||||
LOCALAI_DISABLE_USAGE_STATS: true
|
||||
# Opcionals recomanats
|
||||
LOCALAI_PARALLEL_REQUESTS: true # Permet múltiples peticions simultànies
|
||||
LOCALAI_SINGLE_ACTIVE_BACKEND: true # Allibera memòria quan es canvia de model
|
||||
volumes:
|
||||
- localai_models:/models # Models GGUF persistents
|
||||
- localai_config:/etc/localai # Configuració de models YAML
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8080/readyz"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 5
|
||||
start_period: 120s # LocalAI triga a arrencar la 1a vegada
|
||||
networks:
|
||||
- shared_net
|
||||
|
||||
volumes:
|
||||
localai_models:
|
||||
localai_config:
|
||||
|
||||
networks:
|
||||
shared_net:
|
||||
external: true
|
||||
name: shared_net
|
||||
59
mariadb/docker-compose.yml
Normal file
59
mariadb/docker-compose.yml
Normal file
@@ -0,0 +1,59 @@
|
||||
# /opt/stacks/mariadb/docker-compose.yml
|
||||
|
||||
services:
|
||||
|
||||
# ── Servei MariaDB ───────────────────────
|
||||
mariadb:
|
||||
container_name: mariadb
|
||||
image: mariadb:11.4 # Pinnat a LTS estable
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
TZ: Europe/Madrid
|
||||
MARIADB_ROOT_PASSWORD: '${MARIADB_ROOT_PASSWORD}'
|
||||
MARIADB_DATABASE: '${MARIADB_DATABASE}'
|
||||
MARIADB_USER: '${MARIADB_USER}'
|
||||
MARIADB_PASSWORD: '${MARIADB_PASSWORD}'
|
||||
MARIADB_CHARACTER_SET_SERVER: utf8mb4
|
||||
MARIADB_COLLATION_SERVER: utf8mb4_unicode_ci
|
||||
ports:
|
||||
- "127.0.0.1:3306:3306" # Accés local per eines externes (DBeaver, etc.)
|
||||
volumes:
|
||||
- mariadb_data:/var/lib/mysql
|
||||
- mariadb_init:/docker-entrypoint-initdb.d # Volum named en lloc de bind mount
|
||||
healthcheck:
|
||||
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
|
||||
interval: 10s
|
||||
timeout: 5s # Afegit: timeout explícit
|
||||
retries: 5
|
||||
start_period: 60s # Afegit: marge per a scripts d'inicialització
|
||||
networks:
|
||||
- db_net
|
||||
|
||||
# ── Adminer: UI web per gestionar la BD ──
|
||||
adminer:
|
||||
container_name: adminer
|
||||
image: adminer:latest
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "127.0.0.1:8090:8080" # UI web (només local → via Nginx)
|
||||
environment:
|
||||
TZ: Europe/Madrid
|
||||
ADMINER_DEFAULT_SERVER: mariadb # Pre-omple el camp servidor a la UI
|
||||
ADMINER_DESIGN: pepa-linha # Tema visual més modern (opcional)
|
||||
depends_on:
|
||||
mariadb:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- db_net
|
||||
- shared_net
|
||||
|
||||
volumes:
|
||||
mariadb_data:
|
||||
mariadb_init: # Posa els teus scripts SQL aquí
|
||||
|
||||
networks:
|
||||
db_net:
|
||||
driver: bridge
|
||||
shared_net:
|
||||
external: true
|
||||
name: shared_net
|
||||
100
mautic/docker-compose.yml
Normal file
100
mautic/docker-compose.yml
Normal file
@@ -0,0 +1,100 @@
|
||||
# /opt/stacks/mautic/docker-compose.yml
|
||||
|
||||
services:
|
||||
|
||||
# ── MariaDB per a Mautic ─────────────────
|
||||
db:
|
||||
container_name: mautic-db
|
||||
image: mariadb:10.11
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
TZ: Europe/Madrid
|
||||
MYSQL_ROOT_PASSWORD: '${MYSQL_ROOT_PASSWORD}'
|
||||
MYSQL_DATABASE: mautic
|
||||
MYSQL_USER: mautic
|
||||
MYSQL_PASSWORD: '${MYSQL_PASSWORD}'
|
||||
volumes:
|
||||
- mautic_db:/var/lib/mysql
|
||||
healthcheck:
|
||||
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 30s
|
||||
networks: [mautic_net]
|
||||
|
||||
# ── Mautic — Aplicació principal (web) ───
|
||||
mautic_web:
|
||||
container_name: mautic-web
|
||||
image: mautic/mautic:6-apache # Actualitzat a Mautic 6
|
||||
restart: unless-stopped
|
||||
env_file: .mautic_env # Variables específiques de Mautic
|
||||
environment:
|
||||
TZ: Europe/Madrid
|
||||
MAUTIC_ROLE: mautic_web # Mode natiu de la imatge oficial
|
||||
volumes:
|
||||
- mautic_config:/var/www/html/config # Configuració local.php
|
||||
- mautic_logs:/var/www/html/var/logs # Logs de l'aplicació
|
||||
- mautic_media:/var/www/html/docroot/media # Fitxers pujats i generats
|
||||
ports:
|
||||
- "127.0.0.1:8083:80"
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost/mtc.js"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 5
|
||||
start_period: 60s
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
networks: [mautic_net, shared_net]
|
||||
|
||||
# ── Mautic Worker — processa cues async ──
|
||||
mautic_worker:
|
||||
container_name: mautic-worker
|
||||
image: mautic/mautic:6-apache
|
||||
restart: unless-stopped
|
||||
env_file: .mautic_env
|
||||
environment:
|
||||
TZ: Europe/Madrid
|
||||
MAUTIC_ROLE: mautic_worker # Mode worker natiu
|
||||
MAUTIC_MESSENGER_CONSUME_OPTS: '--time-limit=300 --memory-limit=128M'
|
||||
volumes:
|
||||
- mautic_config:/var/www/html/config
|
||||
- mautic_logs:/var/www/html/var/logs
|
||||
- mautic_media:/var/www/html/docroot/media
|
||||
depends_on:
|
||||
mautic_web:
|
||||
condition: service_healthy
|
||||
networks: [mautic_net]
|
||||
|
||||
# ── Mautic Cron — tasques programades ────
|
||||
mautic_cron:
|
||||
container_name: mautic-cron
|
||||
image: mautic/mautic:6-apache
|
||||
restart: unless-stopped
|
||||
env_file: .mautic_env
|
||||
environment:
|
||||
TZ: Europe/Madrid
|
||||
MAUTIC_ROLE: mautic_cron # Mode cron natiu — gestiona tots els jobs
|
||||
volumes:
|
||||
- mautic_config:/var/www/html/config
|
||||
- mautic_logs:/var/www/html/var/logs
|
||||
- mautic_media:/var/www/html/docroot/media
|
||||
depends_on:
|
||||
mautic_web:
|
||||
condition: service_healthy
|
||||
networks: [mautic_net]
|
||||
|
||||
volumes:
|
||||
mautic_db:
|
||||
mautic_config:
|
||||
mautic_logs:
|
||||
mautic_media:
|
||||
|
||||
networks:
|
||||
mautic_net:
|
||||
driver: bridge
|
||||
shared_net:
|
||||
external: true
|
||||
name: shared_net
|
||||
24
mermaid/docker-compose.yml
Normal file
24
mermaid/docker-compose.yml
Normal file
@@ -0,0 +1,24 @@
|
||||
# /opt/stacks/mermaid/docker-compose.yml
|
||||
#
|
||||
# IMPORTANT: mermaid-live-editor NO suporta variables d'entorn en runtime.
|
||||
# Les opcions com MERMAID_RENDERER_URL són build arguments — s'ignoren aquí.
|
||||
# La imatge pre-built usa mermaid.ink com a renderer (requereix internet).
|
||||
# Per a un entorn offline complet, cal fer un build propi (vegeu README).
|
||||
|
||||
services:
|
||||
|
||||
mermaid:
|
||||
container_name: mermaid
|
||||
image: ghcr.io/mermaid-js/mermaid-live-editor:latest
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
TZ: Europe/Madrid
|
||||
ports:
|
||||
- "8088:8080" # Només local → via Nginx Proxy Manager
|
||||
networks:
|
||||
- shared_net
|
||||
|
||||
networks:
|
||||
shared_net:
|
||||
external: true
|
||||
name: shared_net
|
||||
62
moodle/docker-compose.yml
Normal file
62
moodle/docker-compose.yml
Normal file
@@ -0,0 +1,62 @@
|
||||
# /opt/stacks/moodle/docker-compose.yml
|
||||
|
||||
services:
|
||||
|
||||
# ── MariaDB per a Moodle ─────────────────
|
||||
db:
|
||||
container_name: moodle-db
|
||||
image: mariadb:10.11
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
TZ: Europe/Madrid
|
||||
MYSQL_ROOT_PASSWORD: '${MYSQL_ROOT_PASSWORD}'
|
||||
MYSQL_DATABASE: moodle
|
||||
MYSQL_USER: moodle
|
||||
MYSQL_PASSWORD: '${MYSQL_PASSWORD}'
|
||||
command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
|
||||
volumes:
|
||||
- moodle_db:/var/lib/mysql
|
||||
healthcheck:
|
||||
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 30s
|
||||
networks: [moodle_net]
|
||||
|
||||
# ── Moodle — Aplicació principal ─────────
|
||||
moodle:
|
||||
container_name: moodle
|
||||
image: moodlehq/moodle-php-apache:8.2-bullseye
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
TZ: Europe/Madrid
|
||||
volumes:
|
||||
# Codi de Moodle i config.php
|
||||
- moodle_html:/var/www/html
|
||||
# Dades dels usuaris (fitxers pujats, cache, sessions)
|
||||
- moodle_data:/var/www/moodledata
|
||||
ports:
|
||||
- "127.0.0.1:8084:80" # Només local → via Nginx Proxy Manager
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost/login/index.php"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 5
|
||||
start_period: 120s
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
networks: [moodle_net, shared_net]
|
||||
|
||||
volumes:
|
||||
moodle_db:
|
||||
moodle_html:
|
||||
moodle_data:
|
||||
|
||||
networks:
|
||||
moodle_net:
|
||||
driver: bridge
|
||||
shared_net:
|
||||
external: true
|
||||
name: shared_net
|
||||
64
n8n/docker-compose.yml
Normal file
64
n8n/docker-compose.yml
Normal file
@@ -0,0 +1,64 @@
|
||||
# /opt/stacks/n8n/docker-compose.yml
|
||||
|
||||
services:
|
||||
|
||||
postgres:
|
||||
image: postgres:15
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
POSTGRES_USER: '${POSTGRES_USER}'
|
||||
POSTGRES_PASSWORD: '${POSTGRES_PASSWORD}'
|
||||
POSTGRES_DB: '${POSTGRES_DB}'
|
||||
TZ: Europe/Madrid
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
healthcheck: # Crític: n8n espera que postgres estigui llest
|
||||
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 30s
|
||||
networks:
|
||||
- n8n-net
|
||||
|
||||
n8n:
|
||||
image: n8nio/n8n:latest
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "5678:5678" # Interfície web (només local → via Nginx)
|
||||
environment:
|
||||
TZ: Europe/Madrid
|
||||
GENERIC_TIMEZONE: Europe/Madrid # Necessari per a workflows cron
|
||||
# Base de dades
|
||||
DB_TYPE: postgresdb
|
||||
DB_POSTGRESDB_HOST: postgres
|
||||
DB_POSTGRESDB_PORT: 5432
|
||||
DB_POSTGRESDB_DATABASE: '${POSTGRES_DB}'
|
||||
DB_POSTGRESDB_USER: '${POSTGRES_USER}'
|
||||
DB_POSTGRESDB_PASSWORD: '${POSTGRES_PASSWORD}'
|
||||
# Seguretat
|
||||
N8N_ENCRYPTION_KEY: '${N8N_ENCRYPTION_KEY}' # CRÍTIC: mai canviar un cop configurat
|
||||
# URL pública (necessari per a webhooks)
|
||||
N8N_HOST: '${N8N_HOST}'
|
||||
N8N_PORT: 5678
|
||||
N8N_PROTOCOL: https
|
||||
WEBHOOK_URL: 'https://${N8N_HOST}/'
|
||||
volumes:
|
||||
- n8n_data:/home/node/.n8n
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy # Espera que postgres estigui realment llest
|
||||
networks:
|
||||
- n8n-net
|
||||
- shared_net
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
n8n_data:
|
||||
|
||||
networks:
|
||||
n8n-net:
|
||||
driver: bridge
|
||||
shared_net:
|
||||
external: true
|
||||
name: shared_net
|
||||
110
nextcloud/docker-compose.yml
Normal file
110
nextcloud/docker-compose.yml
Normal file
@@ -0,0 +1,110 @@
|
||||
# /opt/stacks/nextcloud/docker-compose.yml
|
||||
|
||||
services:
|
||||
|
||||
# ── PostgreSQL per a Nextcloud ───────────
|
||||
db:
|
||||
container_name: nextcloud-db
|
||||
image: postgres:16-alpine
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
TZ: Europe/Madrid
|
||||
POSTGRES_DB: nextcloud
|
||||
POSTGRES_USER: nextcloud
|
||||
POSTGRES_PASSWORD: '${POSTGRES_PASSWORD}'
|
||||
volumes:
|
||||
- nc_db:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U nextcloud -d nextcloud"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 30s
|
||||
networks: [nc_net]
|
||||
|
||||
# ── Redis per a cache i sessions ─────────
|
||||
redis:
|
||||
container_name: nextcloud-redis
|
||||
image: redis:7.4-alpine
|
||||
restart: unless-stopped
|
||||
command: redis-server --requirepass '${REDIS_PASSWORD}'
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 15s
|
||||
networks: [nc_net]
|
||||
|
||||
# ── Nextcloud ────────────────────────────
|
||||
nextcloud:
|
||||
container_name: nextcloud
|
||||
image: nextcloud:33-apache # Actualitzat a darrera versió estable
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
TZ: Europe/Madrid
|
||||
# Connexió a PostgreSQL
|
||||
POSTGRES_HOST: db
|
||||
POSTGRES_DB: nextcloud
|
||||
POSTGRES_USER: nextcloud
|
||||
POSTGRES_PASSWORD: '${POSTGRES_PASSWORD}'
|
||||
# Connexió a Redis
|
||||
REDIS_HOST: redis
|
||||
REDIS_HOST_PASSWORD: '${REDIS_PASSWORD}'
|
||||
# Compte administrador inicial (només s'usa en la primera instal·lació)
|
||||
NEXTCLOUD_ADMIN_USER: '${NC_ADMIN_USER}'
|
||||
NEXTCLOUD_ADMIN_PASSWORD: '${NC_ADMIN_PASSWORD}'
|
||||
# Domini de confiança (obligatori!)
|
||||
NEXTCLOUD_TRUSTED_DOMAINS: 'cloud.el-meu-domini.com'
|
||||
# Configuració per a reverse proxy — genera URLs correctes
|
||||
OVERWRITEPROTOCOL: https
|
||||
OVERWRITECLIURL: 'https://cloud.el-meu-domini.com'
|
||||
TRUSTED_PROXIES: '172.16.0.0/12' # Rang de xarxes Docker internes
|
||||
# PHP — memòria i temps màxim
|
||||
PHP_MEMORY_LIMIT: 512M
|
||||
PHP_UPLOAD_LIMIT: 10G
|
||||
volumes:
|
||||
- nc_html:/var/www/html
|
||||
- nc_data:/var/www/html/data
|
||||
ports:
|
||||
- "127.0.0.1:8081:80" # Només local → via Nginx Proxy Manager
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost/status.php"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 5
|
||||
start_period: 60s # Nextcloud triga a instal·lar-se la 1a vegada
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
networks: [nc_net, shared_net]
|
||||
|
||||
# ── Cron: tasques programades de Nextcloud ──
|
||||
cron:
|
||||
container_name: nextcloud-cron
|
||||
image: nextcloud:33-apache # Mateixa versió que nextcloud!
|
||||
restart: unless-stopped
|
||||
entrypoint: /cron.sh
|
||||
environment:
|
||||
TZ: Europe/Madrid
|
||||
volumes:
|
||||
- nc_html:/var/www/html
|
||||
- nc_data:/var/www/html/data
|
||||
depends_on:
|
||||
nextcloud:
|
||||
condition: service_healthy # Espera que Nextcloud estigui llest
|
||||
networks: [nc_net]
|
||||
|
||||
volumes:
|
||||
nc_db:
|
||||
nc_html:
|
||||
nc_data:
|
||||
|
||||
networks:
|
||||
nc_net:
|
||||
driver: bridge
|
||||
shared_net:
|
||||
external: true
|
||||
name: shared_net
|
||||
46
ollama/docker-compose.yml
Normal file
46
ollama/docker-compose.yml
Normal file
@@ -0,0 +1,46 @@
|
||||
# /opt/stacks/ollama/docker-compose.yml
|
||||
|
||||
services:
|
||||
ollama:
|
||||
container_name: ollama
|
||||
image: ollama/ollama:latest
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "127.0.0.1:11434:11434" # API Ollama (només local, open-webui hi accedeix internament)
|
||||
volumes:
|
||||
- ollama_data:/root/.ollama # Models descarregats
|
||||
environment:
|
||||
TZ: Europe/Madrid
|
||||
OLLAMA_HOST: 0.0.0.0 # Necessari perquè open-webui hi accedeixi via xarxa interna
|
||||
networks:
|
||||
- ollama-net
|
||||
- shared_net
|
||||
|
||||
open-webui:
|
||||
container_name: open-webui
|
||||
image: ghcr.io/open-webui/open-webui:main
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "127.0.0.1:3000:8080" # Interfície web (només local → via Nginx)
|
||||
environment:
|
||||
TZ: Europe/Madrid
|
||||
OLLAMA_BASE_URL: http://ollama:11434
|
||||
WEBUI_SECRET_KEY: '${WEBUI_SECRET_KEY}' # Via .env
|
||||
volumes:
|
||||
- open_webui_data:/app/backend/data
|
||||
depends_on:
|
||||
- ollama
|
||||
networks:
|
||||
- ollama-net
|
||||
- shared_net
|
||||
|
||||
volumes:
|
||||
ollama_data:
|
||||
open_webui_data:
|
||||
|
||||
networks:
|
||||
ollama-net:
|
||||
driver: bridge
|
||||
shared_net:
|
||||
external: true
|
||||
name: shared_net
|
||||
40
onlyoffice/docker-compose.yml
Normal file
40
onlyoffice/docker-compose.yml
Normal file
@@ -0,0 +1,40 @@
|
||||
# Afegir al docker-compose.yml de Nextcloud
|
||||
# /opt/stacks/nextcloud/docker-compose.yml
|
||||
|
||||
services:
|
||||
|
||||
# ... (db, redis, nextcloud, cron ja existents) ...
|
||||
|
||||
# ── OnlyOffice Document Server ───────────
|
||||
onlyoffice:
|
||||
container_name: onlyoffice
|
||||
image: onlyoffice/documentserver:latest
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
TZ: Europe/Madrid
|
||||
# JWT — ha de coincidir EXACTAMENT amb el plugin de Nextcloud
|
||||
JWT_ENABLED: "true"
|
||||
JWT_SECRET: '${ONLYOFFICE_JWT_SECRET}'
|
||||
JWT_HEADER: Authorization # Valor per defecte oficial (no AuthorizationJwt)
|
||||
ports:
|
||||
- "8082:80" # Només local → via Nginx Proxy Manager
|
||||
volumes:
|
||||
- oo_data:/var/www/onlyoffice/Data # Certificats i configuració
|
||||
- oo_logs:/var/log/onlyoffice # Logs
|
||||
- oo_cache:/var/lib/onlyoffice # Cache de fitxers (OBLIGATORI!)
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost/healthcheck"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 5
|
||||
start_period: 60s # OnlyOffice triga a arrencar la 1a vegada
|
||||
networks: [nc_net, shared_net]
|
||||
|
||||
# Afegir als volumes existents:
|
||||
volumes:
|
||||
# ... (nc_db, nc_html, nc_data ja existents) ...
|
||||
oo_data:
|
||||
oo_logs:
|
||||
oo_cache: # Nou — cache de fitxers
|
||||
|
||||
# networks ja definides al compose de Nextcloud
|
||||
36
pihole/docker-compose.yml
Normal file
36
pihole/docker-compose.yml
Normal file
@@ -0,0 +1,36 @@
|
||||
# /opt/stacks/pihole/docker-compose.yml
|
||||
|
||||
services:
|
||||
pihole:
|
||||
container_name: pihole
|
||||
image: pihole/pihole:latest
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "53:53/tcp" # DNS TCP — sense 127.0.0.1 (ha de ser accessible a tota la xarxa)
|
||||
- "53:53/udp" # DNS UDP — ídem
|
||||
- "127.0.0.1:8080:80" # Interfície web (només local → via Nginx)
|
||||
environment:
|
||||
TZ: 'Europe/Madrid'
|
||||
WEBPASSWORD: '${PIHOLE_PASSWORD}' # Millor via .env
|
||||
PIHOLE_DNS_: '9.9.9.9;149.112.112.112'
|
||||
DNSSEC: 'true'
|
||||
DNSMASQ_LISTENING: 'all'
|
||||
volumes:
|
||||
- pihole_config:/etc/pihole # Volum named — més estable
|
||||
- pihole_dnsmasq:/etc/dnsmasq.d # Volum named — més estable
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
networks:
|
||||
- dns-net
|
||||
- shared_net
|
||||
|
||||
volumes:
|
||||
pihole_config:
|
||||
pihole_dnsmasq:
|
||||
|
||||
networks:
|
||||
dns-net:
|
||||
driver: bridge
|
||||
shared_net:
|
||||
external: true
|
||||
name: shared_net
|
||||
431
plex/docker-compose.yml
Normal file
431
plex/docker-compose.yml
Normal file
@@ -0,0 +1,431 @@
|
||||
# /opt/stacks/plex/docker-compose.yml
|
||||
|
||||
services:
|
||||
|
||||
# ─────────────────────────────────────────
|
||||
# PLEX
|
||||
# ─────────────────────────────────────────
|
||||
plex:
|
||||
image: lscr.io/linuxserver/plex:latest
|
||||
container_name: plex
|
||||
restart: unless-stopped
|
||||
network_mode: host # Necessari per a Plex discovery (mDNS/DLNA)
|
||||
|
||||
group_add:
|
||||
- "${VIDEO_GID:-44}" # grup 'video' per a GPU
|
||||
- "${RENDER_GID:-992}" # grup 'render' per a /dev/dri
|
||||
|
||||
environment:
|
||||
PUID: ${PUID}
|
||||
PGID: ${PGID}
|
||||
TZ: ${TZ}
|
||||
VERSION: docker
|
||||
PLEX_CLAIM: ${PLEX_CLAIM}
|
||||
|
||||
devices:
|
||||
- /dev/dri/renderD128:/dev/dri/renderD128
|
||||
- /dev/dri/card0:/dev/dri/card0
|
||||
|
||||
volumes:
|
||||
- ${DATA_DIR}/plex/config:/config
|
||||
- ${RIVEN_MOUNT}:/mnt/riven:rslave
|
||||
- ${PD_ZURG_MOUNT}:/mnt/pd_zurg:rslave
|
||||
- ${TORBOX_MOUNT}:/mnt/torbox_zurg:rslave
|
||||
- ${MEDIA_SERIES}:/mnt/media/series:ro
|
||||
- ${MEDIA_MOVIES}:/mnt/media/pelis:ro
|
||||
|
||||
depends_on:
|
||||
- pd_zurg
|
||||
- torbox_mount
|
||||
|
||||
|
||||
# ─────────────────────────────────────────
|
||||
# PD_ZURG — Real-Debrid + Zurg + rclone
|
||||
# ─────────────────────────────────────────
|
||||
pd_zurg:
|
||||
image: iampuid0/pd_zurg:latest
|
||||
container_name: pd_zurg
|
||||
restart: unless-stopped
|
||||
|
||||
stdin_open: true
|
||||
tty: true
|
||||
|
||||
devices:
|
||||
- /dev/fuse:/dev/fuse:rwm
|
||||
|
||||
cap_add:
|
||||
- SYS_ADMIN
|
||||
|
||||
security_opt:
|
||||
- apparmor:unconfined
|
||||
|
||||
environment:
|
||||
TZ: ${TZ}
|
||||
ZURG_ENABLED: "true"
|
||||
RD_API_KEY: ${RD_API_KEY}
|
||||
RCLONE_MOUNT_NAME: pd_zurg
|
||||
PD_ENABLED: "true"
|
||||
PLEX_USER: ${PLEX_USER}
|
||||
PLEX_TOKEN: ${PLEX_TOKEN}
|
||||
PLEX_ADDRESS: ${PLEX_ADDRESS}
|
||||
|
||||
volumes:
|
||||
- ${DATA_DIR}/pd_zurg/config:/config
|
||||
- ${DATA_DIR}/pd_zurg/log:/log
|
||||
- ${DATA_DIR}/pd_zurg/cache:/cache
|
||||
- ${DATA_DIR}/pd_zurg/RD:/zurg/RD
|
||||
- ${PD_ZURG_MOUNT}:/data:shared
|
||||
|
||||
|
||||
# ─────────────────────────────────────────
|
||||
# TORBOX MOUNT — Torbox WebDAV via rclone
|
||||
# ─────────────────────────────────────────
|
||||
torbox_mount:
|
||||
image: rclone/rclone:latest
|
||||
container_name: torbox_mount
|
||||
restart: unless-stopped
|
||||
|
||||
devices:
|
||||
- /dev/fuse:/dev/fuse:rwm
|
||||
|
||||
cap_add:
|
||||
- SYS_ADMIN
|
||||
|
||||
security_opt:
|
||||
- apparmor:unconfined
|
||||
|
||||
environment:
|
||||
TZ: ${TZ}
|
||||
|
||||
command: >
|
||||
mount torbox:
|
||||
/data
|
||||
--config /config/rclone.conf
|
||||
--allow-other
|
||||
--allow-non-empty
|
||||
--dir-cache-time 10s
|
||||
--vfs-cache-mode full
|
||||
--vfs-cache-max-size 512M
|
||||
--no-modtime
|
||||
--log-level INFO
|
||||
|
||||
volumes:
|
||||
- ${DATA_DIR}/torbox_mount/config:/config
|
||||
- ${TORBOX_MOUNT}:/data:shared
|
||||
|
||||
|
||||
# ─────────────────────────────────────────
|
||||
# SEERR — Gestor de peticions
|
||||
# ─────────────────────────────────────────
|
||||
seerr:
|
||||
image: ghcr.io/seerr-team/seerr:latest
|
||||
container_name: seerr
|
||||
restart: unless-stopped
|
||||
|
||||
environment:
|
||||
TZ: ${TZ}
|
||||
|
||||
volumes:
|
||||
- ${DATA_DIR}/seerr/config:/app/config
|
||||
|
||||
ports:
|
||||
- "5055:5055" # Web UI → via Nginx Proxy Manager
|
||||
|
||||
networks:
|
||||
- shared_net
|
||||
|
||||
|
||||
# ─────────────────────────────────────────
|
||||
# RIVEN — PostgreSQL
|
||||
# ─────────────────────────────────────────
|
||||
riven-postgres:
|
||||
image: postgres:17-alpine
|
||||
container_name: riven-postgres
|
||||
restart: unless-stopped
|
||||
|
||||
environment:
|
||||
TZ: ${TZ}
|
||||
POSTGRES_USER: ${RIVEN_POSTGRES_USER}
|
||||
POSTGRES_PASSWORD: ${RIVEN_POSTGRES_PASSWORD}
|
||||
POSTGRES_DB: ${RIVEN_POSTGRES_DB}
|
||||
|
||||
volumes:
|
||||
- riven_postgres_data:/var/lib/postgresql/data
|
||||
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U ${RIVEN_POSTGRES_USER} -d ${RIVEN_POSTGRES_DB}"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 30s
|
||||
|
||||
networks:
|
||||
- riven_net
|
||||
|
||||
|
||||
# ─────────────────────────────────────────
|
||||
# RIVEN — Redis
|
||||
# ─────────────────────────────────────────
|
||||
riven-redis:
|
||||
image: redis:7-alpine
|
||||
container_name: riven-redis
|
||||
restart: unless-stopped
|
||||
|
||||
environment:
|
||||
TZ: ${TZ}
|
||||
|
||||
volumes:
|
||||
- riven_redis_data:/data
|
||||
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 10s
|
||||
|
||||
networks:
|
||||
- riven_net
|
||||
|
||||
|
||||
# ─────────────────────────────────────────
|
||||
# RIVEN — Backend API
|
||||
# ─────────────────────────────────────────
|
||||
riven:
|
||||
image: ghcr.io/rivenmedia/riven-ts:sha-a367778 # Pinnat a SHA per estabilitat
|
||||
container_name: riven
|
||||
restart: unless-stopped
|
||||
|
||||
tty: true
|
||||
|
||||
cap_add:
|
||||
- SYS_ADMIN
|
||||
|
||||
security_opt:
|
||||
- apparmor:unconfined
|
||||
|
||||
devices:
|
||||
- /dev/fuse:/dev/fuse
|
||||
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
|
||||
environment:
|
||||
TZ: ${TZ}
|
||||
NODE_ENV: production # Era 'development' — canviat a production
|
||||
RIVEN_SETTING__databaseUrl: "postgresql://${RIVEN_POSTGRES_USER}:${RIVEN_POSTGRES_PASSWORD}@riven-postgres:5432/${RIVEN_POSTGRES_DB}"
|
||||
RIVEN_SETTING__redisUrl: "redis://riven-redis:6379"
|
||||
RIVEN_SETTING__gqlHost: "0.0.0.0"
|
||||
RIVEN_SETTING__gqlCorsOrigin: ${RIVEN_CORS_ORIGIN}
|
||||
# ⚠️ CSRF desactivat — només acceptable en xarxa privada/VPN
|
||||
RIVEN_SETTING__csrfPrevention: "false"
|
||||
APOLLO_CSRF_PREVENTION_ENABLED: "false"
|
||||
RIVEN_SETTING__enabledPlugins: '["stremthru","plex","tmdb","tvdb","seerr"]'
|
||||
RIVEN_PLUGIN_SETTING__REPO_PLUGIN_TMDB__apiKey: ${TMDB_API_KEY}
|
||||
RIVEN_PLUGIN_SETTING__REPO_PLUGIN_TVDB__apiKey: ${TVDB_API_KEY}
|
||||
RIVEN_PLUGIN_SETTING__REPO_PLUGIN_STREMTHRU__realdebridApiKey: ${RD_API_KEY}
|
||||
RIVEN_PLUGIN_SETTING__REPO_PLUGIN_STREMTHRU__torboxApiKey: ${TORBOX_API_KEY}
|
||||
RIVEN_PLUGIN_SETTING__REPO_PLUGIN_PLEX__plexServerUrl: ${PLEX_ADDRESS}
|
||||
RIVEN_PLUGIN_SETTING__REPO_PLUGIN_PLEX__plexToken: ${PLEX_TOKEN}
|
||||
RIVEN_PLUGIN_SETTING__REPO_PLUGIN_SEERR__apiKey: ${SEERR_API_KEY}
|
||||
RIVEN_PLUGIN_SETTING__REPO_PLUGIN_SEERR__url: ${SEERR_URL}
|
||||
RIVEN_PLUGIN_SETTING__REPO_PLUGIN_SEERR__autofixMetadataProviders: "true"
|
||||
RIVEN_SETTING__vfsMountPath: /mnt/riven
|
||||
|
||||
volumes:
|
||||
- riven_data:/riven/data
|
||||
- ${RIVEN_MOUNT}:/mnt/riven:shared
|
||||
|
||||
depends_on:
|
||||
riven-postgres:
|
||||
condition: service_healthy
|
||||
riven-redis:
|
||||
condition: service_healthy
|
||||
seerr:
|
||||
condition: service_started
|
||||
pd_zurg:
|
||||
condition: service_started
|
||||
|
||||
networks:
|
||||
- riven_net
|
||||
- shared_net
|
||||
|
||||
|
||||
# ─────────────────────────────────────────
|
||||
# RIVEN — Frontend UI
|
||||
# ─────────────────────────────────────────
|
||||
riven-frontend:
|
||||
image: ghcr.io/rivenmedia/riven-frontend:latest
|
||||
container_name: riven-frontend
|
||||
restart: unless-stopped
|
||||
|
||||
tty: true
|
||||
|
||||
environment:
|
||||
TZ: ${TZ}
|
||||
ORIGIN: ${RIVEN_ORIGIN}
|
||||
BACKEND_URL: "http://riven:3000"
|
||||
|
||||
volumes:
|
||||
- riven_frontend_config:/riven/config
|
||||
|
||||
depends_on:
|
||||
riven:
|
||||
condition: service_started
|
||||
|
||||
networks:
|
||||
- riven_net
|
||||
- shared_net
|
||||
|
||||
|
||||
# ─────────────────────────────────────────
|
||||
# DMM — MySQL Database
|
||||
# ─────────────────────────────────────────
|
||||
dmm-db:
|
||||
image: mysql:8.0
|
||||
container_name: dmm-db
|
||||
restart: unless-stopped
|
||||
|
||||
environment:
|
||||
TZ: ${TZ}
|
||||
MYSQL_ROOT_PASSWORD: ${DMM_DB_ROOT_PASSWORD}
|
||||
MYSQL_DATABASE: dmm
|
||||
MYSQL_USER: dmm
|
||||
MYSQL_PASSWORD: ${DMM_DB_PASSWORD}
|
||||
|
||||
volumes:
|
||||
- dmm_db_data:/var/lib/mysql
|
||||
|
||||
healthcheck:
|
||||
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${DMM_DB_ROOT_PASSWORD}"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 30s
|
||||
|
||||
networks:
|
||||
- dmm_net
|
||||
|
||||
|
||||
# ─────────────────────────────────────────
|
||||
# DMM — Redis
|
||||
# ─────────────────────────────────────────
|
||||
dmm-redis:
|
||||
image: redis:7-alpine
|
||||
container_name: dmm-redis
|
||||
restart: unless-stopped
|
||||
command: redis-server --appendonly yes --maxmemory 128mb --maxmemory-policy allkeys-lru
|
||||
|
||||
environment:
|
||||
TZ: ${TZ}
|
||||
|
||||
volumes:
|
||||
- dmm_redis_data:/data
|
||||
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 10s
|
||||
|
||||
networks:
|
||||
- dmm_net
|
||||
|
||||
|
||||
# ─────────────────────────────────────────
|
||||
# DMM — Tor proxy
|
||||
# ─────────────────────────────────────────
|
||||
dmm-tor:
|
||||
image: debridmediamanager/tor
|
||||
container_name: dmm-tor
|
||||
restart: unless-stopped
|
||||
|
||||
environment:
|
||||
TZ: ${TZ}
|
||||
|
||||
networks:
|
||||
- dmm_net
|
||||
|
||||
|
||||
# ─────────────────────────────────────────
|
||||
# DMM — App (built from source)
|
||||
# ─────────────────────────────────────────
|
||||
dmm:
|
||||
build:
|
||||
context: ${DMM_BUILD_CONTEXT} # Era hardcoded /opt/tatsukai/plex/dmm
|
||||
image: dmm-prod:local
|
||||
container_name: dmm
|
||||
restart: unless-stopped
|
||||
|
||||
environment:
|
||||
TZ: ${TZ}
|
||||
DATABASE_URL: ${DATABASE_URL}
|
||||
DMM_ORIGIN: ${DMM_URL}
|
||||
DMMCAST_SALT: ${DMM_SECRET}
|
||||
REDIS_URL: "redis://dmm-redis:6379"
|
||||
TMDB_KEY: ${TMDB_API_KEY}
|
||||
TRAKT_CLIENT_ID: ${TRAKT_CLIENT_ID}
|
||||
TRAKT_CLIENT_SECRET: ${TRAKT_CLIENT_SECRET}
|
||||
NEXT_PUBLIC_ANALYTICS_ENABLED: "false"
|
||||
MDBLIST_KEY: ${MDBLIST_KEY}
|
||||
TOR_PROXY: "socks5://dmm-tor:9050"
|
||||
|
||||
ports:
|
||||
- "3000:3000" # Web UI → via Nginx Proxy Manager
|
||||
|
||||
depends_on:
|
||||
dmm-db:
|
||||
condition: service_healthy
|
||||
dmm-redis:
|
||||
condition: service_healthy # Era service_started — ara espera healthcheck
|
||||
dmm-tor:
|
||||
condition: service_started
|
||||
|
||||
networks:
|
||||
- dmm_net
|
||||
- shared_net
|
||||
|
||||
|
||||
# ─────────────────────────────────────────
|
||||
# XTEVE — Proxy M3U / Virtual HDHomeRun
|
||||
# ─────────────────────────────────────────
|
||||
xteve:
|
||||
image: alturismo/xteve:latest
|
||||
container_name: xteve
|
||||
restart: unless-stopped
|
||||
|
||||
environment:
|
||||
TZ: ${TZ}
|
||||
XTEVE_TUNER: ${XTEVE_TUNER:-8}
|
||||
|
||||
ports:
|
||||
- "34400:34400" # Web UI → via Nginx Proxy Manager
|
||||
|
||||
volumes:
|
||||
- ${DATA_DIR}/xteve/config:/root/.xteve
|
||||
- ${DATA_DIR}/xteve/temp:/tmp/xteve
|
||||
- ${DATA_DIR}/epg/xmltv_master.xml:/root/xmltv.xml:ro
|
||||
- ${DATA_DIR}/epg/master.m3u:/root/playlist.m3u:ro
|
||||
|
||||
networks:
|
||||
- shared_net
|
||||
|
||||
|
||||
volumes:
|
||||
riven_data:
|
||||
riven_postgres_data:
|
||||
riven_redis_data:
|
||||
riven_frontend_config:
|
||||
dmm_db_data:
|
||||
dmm_redis_data:
|
||||
|
||||
|
||||
networks:
|
||||
riven_net:
|
||||
driver: bridge
|
||||
dmm_net:
|
||||
driver: bridge
|
||||
shared_net:
|
||||
external: true
|
||||
name: shared_net
|
||||
24
portainer/docker-compose.yml
Normal file
24
portainer/docker-compose.yml
Normal file
@@ -0,0 +1,24 @@
|
||||
# /opt/stacks/portainer/docker-compose.yml
|
||||
|
||||
services:
|
||||
portainer:
|
||||
image: portainer/portainer-ce:latest
|
||||
container_name: portainer
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "9000:9000" # Interfície web HTTP (només local)
|
||||
- "9443:9443" # Interfície web HTTPS (només local)
|
||||
# - "8000:8000" # Agent tunnel — descomenta si uses agents remots
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- portainer_data:/data
|
||||
networks:
|
||||
- shared_net
|
||||
|
||||
volumes:
|
||||
portainer_data:
|
||||
|
||||
networks:
|
||||
shared_net:
|
||||
external: true
|
||||
name: shared_net
|
||||
64
postgres/docker-compose.yml
Normal file
64
postgres/docker-compose.yml
Normal file
@@ -0,0 +1,64 @@
|
||||
# /opt/stacks/postgres/docker-compose.yml
|
||||
|
||||
services:
|
||||
|
||||
# ── Servei PostgreSQL ────────────────────
|
||||
postgres:
|
||||
container_name: postgres
|
||||
image: postgres:16-alpine
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
TZ: Europe/Madrid
|
||||
POSTGRES_USER: '${POSTGRES_USER}'
|
||||
POSTGRES_PASSWORD: '${POSTGRES_PASSWORD}'
|
||||
POSTGRES_DB: '${POSTGRES_DB}'
|
||||
# UTF8 sense locale específic → compatible amb Alpine
|
||||
POSTGRES_INITDB_ARGS: '--encoding=UTF8 --locale=en_US.utf8'
|
||||
ports:
|
||||
- "5432:5432" # Accés local per DBeaver, psql, etc.
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
- postgres_init:/docker-entrypoint-initdb.d # Scripts SQL d'inicialització
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
|
||||
interval: 10s
|
||||
timeout: 5s # Afegit
|
||||
retries: 5
|
||||
start_period: 30s # Afegit: marge per a scripts d'init
|
||||
networks:
|
||||
- pg_net
|
||||
|
||||
# ── pgAdmin: UI web per gestionar Postgres ──
|
||||
pgadmin:
|
||||
container_name: pgadmin
|
||||
image: dpage/pgadmin4:latest
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "5050:80" # UI web (només local → via Nginx)
|
||||
environment:
|
||||
TZ: Europe/Madrid
|
||||
PGADMIN_DEFAULT_EMAIL: '${PGADMIN_EMAIL}'
|
||||
PGADMIN_DEFAULT_PASSWORD: '${PGADMIN_PASSWORD}'
|
||||
PGADMIN_DISABLE_POSTFIX: 'true' # Evita errors de Postfix als logs
|
||||
PGADMIN_CONFIG_SERVER_MODE: 'False' # Mode personal (un sol usuari)
|
||||
PGADMIN_CONFIG_MASTER_PASSWORD_REQUIRED: 'False' # Simplifica l'accés local
|
||||
volumes:
|
||||
- pgadmin_data:/var/lib/pgadmin # Persisteix servidors i preferències
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- pg_net
|
||||
- shared_net
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
postgres_init: # Posa els teus scripts .sql aquí
|
||||
pgadmin_data: # Configuració de pgAdmin persistent
|
||||
|
||||
networks:
|
||||
pg_net:
|
||||
driver: bridge
|
||||
shared_net:
|
||||
external: true
|
||||
name: shared_net
|
||||
70
redis/docker-compose.yml
Normal file
70
redis/docker-compose.yml
Normal file
@@ -0,0 +1,70 @@
|
||||
# /opt/stacks/redis/docker-compose.yml
|
||||
|
||||
services:
|
||||
|
||||
# ── Servei Redis ─────────────────────────
|
||||
redis:
|
||||
container_name: redis
|
||||
image: redis:7.4-alpine # Pinnat a LTS estable
|
||||
restart: unless-stopped
|
||||
command:
|
||||
- redis-server
|
||||
- --requirepass
|
||||
- '${REDIS_PASSWORD}'
|
||||
- --appendonly
|
||||
- "yes"
|
||||
- --maxmemory
|
||||
- 256mb
|
||||
- --maxmemory-policy
|
||||
- allkeys-lru
|
||||
- --loglevel
|
||||
- notice
|
||||
ports:
|
||||
- "127.0.0.1:6379:6379" # Accés local per a clients externs
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
environment:
|
||||
TZ: Europe/Madrid
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"]
|
||||
interval: 10s
|
||||
timeout: 5s # Afegit
|
||||
retries: 5
|
||||
start_period: 15s # Afegit
|
||||
networks:
|
||||
- redis_net
|
||||
|
||||
# ── RedisInsight: UI web per gestionar Redis ──
|
||||
redisinsight:
|
||||
container_name: redisinsight
|
||||
image: redis/redisinsight:latest # Imatge oficial actualitzada
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "127.0.0.1:5540:5540" # Port correcte és 5540, no 8001!
|
||||
environment:
|
||||
TZ: Europe/Madrid
|
||||
RI_ENCRYPTION_KEY: '${RI_ENCRYPTION_KEY}' # Xifra contrasenyes guardades
|
||||
# Preconfiguració automàtica de la connexió al Redis local
|
||||
RI_REDIS_HOST: redis
|
||||
RI_REDIS_PORT: 6379
|
||||
RI_REDIS_ALIAS: Redis Local
|
||||
RI_REDIS_PASSWORD: '${REDIS_PASSWORD}'
|
||||
volumes:
|
||||
- redisinsight_data:/data # Persisteix connexions i historial
|
||||
depends_on:
|
||||
redis:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- redis_net
|
||||
- shared_net
|
||||
|
||||
volumes:
|
||||
redis_data:
|
||||
redisinsight_data:
|
||||
|
||||
networks:
|
||||
redis_net:
|
||||
driver: bridge
|
||||
shared_net:
|
||||
external: true
|
||||
name: shared_net
|
||||
49
vaultwarden/docker-compose.yml
Normal file
49
vaultwarden/docker-compose.yml
Normal file
@@ -0,0 +1,49 @@
|
||||
# /opt/stacks/vaultwarden/docker-compose.yml
|
||||
|
||||
services:
|
||||
|
||||
vaultwarden:
|
||||
container_name: vaultwarden
|
||||
image: vaultwarden/server:latest
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
TZ: Europe/Madrid
|
||||
# Domini públic (obligatori per a links d'invitació i 2FA)
|
||||
DOMAIN: 'https://vault.el-meu-domini.com'
|
||||
# Seguretat: registre tancat
|
||||
SIGNUPS_ALLOWED: "false"
|
||||
# Token admin — usa hash argon2id (vegeu .env i instruccions sota)
|
||||
ADMIN_TOKEN: '${VAULTWARDEN_ADMIN_TOKEN}'
|
||||
# Configuració SMTP
|
||||
SMTP_HOST: '${SMTP_HOST}'
|
||||
SMTP_PORT: 587
|
||||
SMTP_SECURITY: starttls # Explícit: starttls | force_tls | off
|
||||
SMTP_FROM: '${SMTP_FROM}'
|
||||
SMTP_USERNAME: '${SMTP_USERNAME}'
|
||||
SMTP_PASSWORD: '${SMTP_PASSWORD}'
|
||||
SMTP_FROM_NAME: Vaultwarden
|
||||
# Logs
|
||||
LOG_LEVEL: warn
|
||||
# WebSockets integrats al port principal des de v1.29.0
|
||||
# WEBSOCKET_ENABLED i port 3012 eliminats des de v1.31.0
|
||||
volumes:
|
||||
- vaultwarden_data:/data
|
||||
ports:
|
||||
- "127.0.0.1:8080:80" # Port únic — WebSockets inclosos
|
||||
# Port 3012 ELIMINAT — ja no existeix des de v1.31.0
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:80/alive"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 15s
|
||||
networks:
|
||||
- shared_net
|
||||
|
||||
volumes:
|
||||
vaultwarden_data:
|
||||
|
||||
networks:
|
||||
shared_net:
|
||||
external: true
|
||||
name: shared_net
|
||||
38
wg-easy/docker-compose.yml
Normal file
38
wg-easy/docker-compose.yml
Normal file
@@ -0,0 +1,38 @@
|
||||
# /opt/stacks/wg-easy/docker-compose.yml
|
||||
|
||||
services:
|
||||
wg-easy:
|
||||
container_name: wg-easy
|
||||
image: ghcr.io/wg-easy/wg-easy:latest
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
WG_HOST: '${WG_HOST}' # Domini o IP pública — via .env
|
||||
PASSWORD_HASH: '${WG_PASSWORD_HASH}' # Hash bcrypt — via .env
|
||||
WG_PORT: 51820
|
||||
WG_DEFAULT_ADDRESS: '10.0.0.1' # Adreça del servidor VPN (no .x)
|
||||
WG_DEFAULT_DNS: '${WG_DNS}' # AdGuard/Pi-hole — via .env
|
||||
WG_ALLOWED_IPS: '0.0.0.0/0'
|
||||
UI_TRAFFIC_STATS: true
|
||||
UI_CHART_TYPE: 1
|
||||
TZ: Europe/Madrid
|
||||
ports:
|
||||
- "51820:51820/udp" # WireGuard VPN — públic (necessari per a clients)
|
||||
- "51821:51821" # Interfície web (només local → via Nginx)
|
||||
volumes:
|
||||
- wg_easy_data:/etc/wireguard # Volum named — configuració persistent
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
- SYS_MODULE
|
||||
sysctls:
|
||||
- net.ipv4.ip_forward=1
|
||||
- net.ipv4.conf.all.src_valid_mark=1
|
||||
networks:
|
||||
- shared_net
|
||||
|
||||
volumes:
|
||||
wg_easy_data:
|
||||
|
||||
networks:
|
||||
shared_net:
|
||||
external: true
|
||||
name: shared_net
|
||||
92
wordpress/docker-compose.yml
Normal file
92
wordpress/docker-compose.yml
Normal file
@@ -0,0 +1,92 @@
|
||||
# /opt/stacks/wordpress/docker-compose.yml
|
||||
|
||||
services:
|
||||
|
||||
# ── MariaDB ──────────────────────────────
|
||||
db:
|
||||
container_name: wordpress-db
|
||||
image: mariadb:10.11
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
TZ: Europe/Madrid
|
||||
MYSQL_ROOT_PASSWORD: '${MYSQL_ROOT_PASSWORD}'
|
||||
MYSQL_DATABASE: wordpress
|
||||
MYSQL_USER: wordpress
|
||||
MYSQL_PASSWORD: '${MYSQL_PASSWORD}'
|
||||
volumes:
|
||||
- wp_db:/var/lib/mysql
|
||||
healthcheck:
|
||||
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 30s
|
||||
networks: [wp_net]
|
||||
|
||||
# ── Redis — cache d'objectes ─────────────
|
||||
# Nota: Redis és volàtil per defecte — la cache es perd en reiniciar.
|
||||
# Per a WordPress és acceptable (es reconstrueix automàticament).
|
||||
redis:
|
||||
container_name: wordpress-redis
|
||||
image: redis:7-alpine
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
TZ: Europe/Madrid
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 10s
|
||||
networks: [wp_net]
|
||||
|
||||
# ── WordPress ────────────────────────────
|
||||
wordpress:
|
||||
container_name: wordpress
|
||||
image: wordpress:6-apache
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
TZ: Europe/Madrid
|
||||
# Connexió a MariaDB
|
||||
WORDPRESS_DB_HOST: db
|
||||
WORDPRESS_DB_NAME: wordpress
|
||||
WORDPRESS_DB_USER: wordpress
|
||||
WORDPRESS_DB_PASSWORD: '${MYSQL_PASSWORD}'
|
||||
# Claus de seguretat — les 8 obligatòries
|
||||
# Genera-les a: https://api.wordpress.org/secret-key/1.1/salt/
|
||||
WORDPRESS_AUTH_KEY: '${WP_AUTH_KEY}'
|
||||
WORDPRESS_SECURE_AUTH_KEY: '${WP_SECURE_AUTH_KEY}'
|
||||
WORDPRESS_LOGGED_IN_KEY: '${WP_LOGGED_IN_KEY}'
|
||||
WORDPRESS_NONCE_KEY: '${WP_NONCE_KEY}'
|
||||
WORDPRESS_AUTH_SALT: '${WP_AUTH_SALT}'
|
||||
WORDPRESS_SECURE_AUTH_SALT: '${WP_SECURE_AUTH_SALT}'
|
||||
WORDPRESS_LOGGED_IN_SALT: '${WP_LOGGED_IN_SALT}'
|
||||
WORDPRESS_NONCE_SALT: '${WP_NONCE_SALT}'
|
||||
# Configuració addicional via wp-config
|
||||
WORDPRESS_CONFIG_EXTRA: |
|
||||
define('WP_REDIS_HOST', 'redis');
|
||||
define('WP_REDIS_PORT', 6379);
|
||||
define('WP_CACHE', true);
|
||||
define('WP_HOME', '${WP_URL}');
|
||||
define('WP_SITEURL', '${WP_URL}');
|
||||
volumes:
|
||||
- wp_data:/var/www/html
|
||||
ports:
|
||||
- "8086:80"
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy # Afegit — WordPress necessita Redis disponible
|
||||
networks: [wp_net, shared_net]
|
||||
|
||||
volumes:
|
||||
wp_db:
|
||||
wp_data:
|
||||
|
||||
networks:
|
||||
wp_net:
|
||||
driver: bridge
|
||||
shared_net:
|
||||
external: true
|
||||
name: shared_net
|
||||
Reference in New Issue
Block a user