added app-catalog

This commit is contained in:
2026-02-11 20:27:53 +01:00
commit 82a8c8b6cf
14 changed files with 1230 additions and 0 deletions
+41
View File
@@ -0,0 +1,41 @@
# ActualBudget - Personal Finance / Budgeting
# Domain: budget.{{DOMAIN}}
# Database: None (file-based)
# RAM: ~50MB | Pi-compatible: Yes
#
# Environment variables (set in Portainer):
# (none required — app is self-contained)
#
# First-time setup:
# Create a password on first visit, no default credentials.
services:
actualbudget:
image: actualbudget/actual-server:26.1.0
container_name: actualbudget
restart: unless-stopped
environment:
- TZ=Europe/Budapest
volumes:
- actualbudget_data:/data
networks:
- traefik-public
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "http://localhost:5006/"]
interval: 30s
timeout: 5s
retries: 3
start_period: 10s
labels:
- "traefik.enable=true"
- "traefik.http.routers.actualbudget.rule=Host(`budget.{{DOMAIN}}`)"
- "traefik.http.routers.actualbudget.entrypoints=websecure"
- "traefik.http.routers.actualbudget.tls=true"
- "traefik.http.services.actualbudget.loadbalancer.server.port=5006"
volumes:
actualbudget_data:
networks:
traefik-public:
external: true
+90
View File
@@ -0,0 +1,90 @@
# Docmost - Modern Wiki / Documentation (Notion-like)
# Domain: docs.{{DOMAIN}}
# Database: PostgreSQL + Redis
# RAM: ~200MB | Pi-compatible: Heavy but possible
#
# Environment variables (set in Portainer):
# APP_SECRET - Random secret for session signing (required, generate with: openssl rand -hex 32)
# DB_PASSWORD - PostgreSQL password (required)
#
# First-time setup:
# First registered user becomes admin.
services:
docmost:
image: docmost/docmost:0.25.3
container_name: docmost
restart: unless-stopped
depends_on:
docmost-postgres:
condition: service_healthy
docmost-redis:
condition: service_healthy
environment:
- APP_SECRET=${APP_SECRET}
- DATABASE_URL=postgresql://docmost:${DB_PASSWORD}@docmost-postgres:5432/docmost
- REDIS_URL=redis://docmost-redis:6379
- APP_URL=https://docs.{{DOMAIN}}
- STORAGE_DRIVER=local
- FILE_UPLOAD_SIZE_LIMIT=50mb
volumes:
- docmost_storage:/app/data/storage
networks:
- traefik-public
- docmost-internal
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "http://localhost:3000/"]
interval: 30s
timeout: 5s
retries: 3
start_period: 30s
labels:
- "traefik.enable=true"
- "traefik.http.routers.docmost.rule=Host(`docs.{{DOMAIN}}`)"
- "traefik.http.routers.docmost.entrypoints=websecure"
- "traefik.http.routers.docmost.tls=true"
- "traefik.http.services.docmost.loadbalancer.server.port=3000"
docmost-postgres:
image: postgres:16-alpine
container_name: docmost-postgres
restart: unless-stopped
environment:
- POSTGRES_USER=docmost
- POSTGRES_PASSWORD=${DB_PASSWORD}
- POSTGRES_DB=docmost
volumes:
- docmost_postgres_data:/var/lib/postgresql/data
networks:
- docmost-internal
healthcheck:
test: ["CMD-SHELL", "pg_isready -U docmost -d docmost"]
interval: 10s
timeout: 5s
retries: 5
start_period: 20s
docmost-redis:
image: redis:7-alpine
container_name: docmost-redis
restart: unless-stopped
command: redis-server --appendonly yes
volumes:
- docmost_redis_data:/data
networks:
- docmost-internal
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 3
volumes:
docmost_storage:
docmost_postgres_data:
docmost_redis_data:
networks:
traefik-public:
external: true
docmost-internal:
+50
View File
@@ -0,0 +1,50 @@
# FileBrowser - Simple Web File Manager
# Domain: files.{{DOMAIN}}
# Database: None (file-based)
# RAM: ~30MB | Pi-compatible: Yes
#
# Environment variables (set in Portainer):
# (none required)
#
# First-time setup:
# Default login: admin / admin — change immediately!
#
# Volume notes:
# filebrowser_data is the browsable file area.
# For HDD access, override this volume in Portainer:
# /mnt/hdd_1:/srv (or a specific subdirectory)
services:
filebrowser:
image: filebrowser/filebrowser:v2.32.0
container_name: filebrowser
restart: unless-stopped
environment:
- TZ=Europe/Budapest
- PUID=1000
- PGID=1000
volumes:
- filebrowser_data:/srv
- filebrowser_config:/database
networks:
- traefik-public
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "http://localhost:80/health"]
interval: 30s
timeout: 5s
retries: 3
start_period: 10s
labels:
- "traefik.enable=true"
- "traefik.http.routers.filebrowser.rule=Host(`files.{{DOMAIN}}`)"
- "traefik.http.routers.filebrowser.entrypoints=websecure"
- "traefik.http.routers.filebrowser.tls=true"
- "traefik.http.services.filebrowser.loadbalancer.server.port=80"
volumes:
filebrowser_data:
filebrowser_config:
networks:
traefik-public:
external: true
+44
View File
@@ -0,0 +1,44 @@
# Homebox - Home Inventory Management
# Domain: inventory.{{DOMAIN}}
# Database: None (SQLite, file-based)
# RAM: ~50MB | Pi-compatible: Yes
#
# Environment variables (set in Portainer):
# (none required)
#
# First-time setup:
# Register on first visit, first user becomes owner.
services:
homebox:
image: ghcr.io/sysadminsmedia/homebox:v0.16.3
container_name: homebox
restart: unless-stopped
environment:
- HBOX_LOG_LEVEL=info
- HBOX_LOG_FORMAT=text
- HBOX_WEB_MAX_UPLOAD_SIZE=50
- TZ=Europe/Budapest
volumes:
- homebox_data:/data
networks:
- traefik-public
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "http://localhost:7745/api/v1/status"]
interval: 30s
timeout: 5s
retries: 3
start_period: 10s
labels:
- "traefik.enable=true"
- "traefik.http.routers.homebox.rule=Host(`inventory.{{DOMAIN}}`)"
- "traefik.http.routers.homebox.entrypoints=websecure"
- "traefik.http.routers.homebox.tls=true"
- "traefik.http.services.homebox.loadbalancer.server.port=7745"
volumes:
homebox_data:
networks:
traefik-public:
external: true
+115
View File
@@ -0,0 +1,115 @@
# Immich - Self-hosted Photo & Video Management
# Domain: photos.{{DOMAIN}}
# Database: PostgreSQL (with VectorChord) + Redis
# RAM: ~4GB minimum | Pi-compatible: No (ML too heavy)
#
# Environment variables (set in Portainer):
# DB_PASSWORD - PostgreSQL password (required)
#
# Volume notes:
# immich_upload is the photo/video storage location.
# For HDD storage, override in Portainer stack:
# /mnt/hdd_1/storage/immich:/usr/src/app/upload
#
# First-time setup:
# Create admin account on first visit.
services:
immich-server:
image: ghcr.io/immich-app/immich-server:v2.5.5
container_name: immich-server
restart: unless-stopped
depends_on:
immich-postgres:
condition: service_healthy
immich-redis:
condition: service_healthy
environment:
- DB_PASSWORD=${DB_PASSWORD}
- DB_HOSTNAME=immich-postgres
- DB_USERNAME=immich
- DB_DATABASE_NAME=immich
- REDIS_HOSTNAME=immich-redis
- IMMICH_MACHINE_LEARNING_URL=http://immich-machine-learning:3003
- TZ=Europe/Budapest
volumes:
- immich_upload:/usr/src/app/upload
networks:
- traefik-public
- immich-internal
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "http://localhost:2283/api/server/ping"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
labels:
- "traefik.enable=true"
- "traefik.http.routers.immich.rule=Host(`photos.{{DOMAIN}}`)"
- "traefik.http.routers.immich.entrypoints=websecure"
- "traefik.http.routers.immich.tls=true"
- "traefik.http.services.immich.loadbalancer.server.port=2283"
immich-machine-learning:
image: ghcr.io/immich-app/immich-machine-learning:v2.5.5
container_name: immich-machine-learning
restart: unless-stopped
environment:
- TZ=Europe/Budapest
- TRANSFORMERS_CACHE=/cache
volumes:
- immich_ml_cache:/cache
networks:
- immich-internal
healthcheck:
test: ["CMD", "python3", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:3003/ping')"]
interval: 30s
timeout: 10s
retries: 3
start_period: 120s
immich-postgres:
image: ghcr.io/immich-app/postgres:16-vectorchord0.3.0
container_name: immich-postgres
restart: unless-stopped
environment:
- POSTGRES_USER=immich
- POSTGRES_PASSWORD=${DB_PASSWORD}
- POSTGRES_DB=immich
- POSTGRES_INITDB_ARGS=--data-checksums
volumes:
- immich_postgres_data:/var/lib/postgresql/data
networks:
- immich-internal
healthcheck:
test: ["CMD-SHELL", "pg_isready -U immich -d immich"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
immich-redis:
image: redis:7-alpine
container_name: immich-redis
restart: unless-stopped
command: redis-server --appendonly yes
volumes:
- immich_redis_data:/data
networks:
- immich-internal
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 3
volumes:
immich_upload:
immich_ml_cache:
immich_postgres_data:
immich_redis_data:
networks:
traefik-public:
external: true
immich-internal:
+53
View File
@@ -0,0 +1,53 @@
# Mealie - Recipe Manager & Meal Planner
# Domain: recipes.{{DOMAIN}}
# Database: None (SQLite, built-in)
# RAM: ~200MB | Pi-compatible: Yes (arm64 only)
#
# Environment variables (set in Portainer):
# (none required for basic usage)
# SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASSWORD - for email features (optional)
#
# First-time setup:
# Default login: changeme@example.com / MyPassword
# Change immediately after first login!
services:
mealie:
image: ghcr.io/mealie-recipes/mealie:v3.10.2
container_name: mealie
restart: unless-stopped
environment:
- ALLOW_SIGNUP=false
- PUID=1000
- PGID=1000
- TZ=Europe/Budapest
- MAX_WORKERS=1
- WEB_CONCURRENCY=1
- BASE_URL=https://recipes.{{DOMAIN}}
volumes:
- mealie_data:/app/data/
networks:
- traefik-public
deploy:
resources:
limits:
memory: 1000M
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "http://localhost:9000/"]
interval: 30s
timeout: 5s
retries: 3
start_period: 30s
labels:
- "traefik.enable=true"
- "traefik.http.routers.mealie.rule=Host(`recipes.{{DOMAIN}}`)"
- "traefik.http.routers.mealie.entrypoints=websecure"
- "traefik.http.routers.mealie.tls=true"
- "traefik.http.services.mealie.loadbalancer.server.port=9000"
volumes:
mealie_data:
networks:
traefik-public:
external: true
+115
View File
@@ -0,0 +1,115 @@
# ROMM - ROM Manager for Game Libraries
# Domain: arcade.{{DOMAIN}}
# Database: MariaDB + Redis
# RAM: ~300MB | Pi-compatible: Possible but heavy
#
# Environment variables (set in Portainer):
# DB_PASSWORD - MariaDB user password (required)
# MYSQL_ROOT_PASSWORD - MariaDB root password (required)
# ROMM_AUTH_SECRET_KEY - Auth secret (required, generate with: openssl rand -hex 32)
# IGDB_CLIENT_ID - IGDB API client ID (optional, for game metadata)
# IGDB_CLIENT_SECRET - IGDB API client secret (optional)
# STEAMGRIDDB_API_KEY - SteamGridDB API key (optional, for cover art)
#
# First-time setup:
# Default login: admin / admin — change immediately!
services:
romm:
image: rommapp/romm:4.5.0
container_name: romm
restart: unless-stopped
depends_on:
romm-db:
condition: service_healthy
romm-redis:
condition: service_started
entrypoint: ["/bin/sh", "-c"]
command:
- |
if [ ! -f /romm/config/config.yml ]; then
echo "Creating default config.yml..."
cat > /romm/config/config.yml << 'CONF'
exclude:
platforms: []
roms: []
system:
log_level: INFO
CONF
fi
exec /docker-entrypoint.sh /init
environment:
- ROMM_AUTH_SECRET_KEY=${ROMM_AUTH_SECRET_KEY}
- DB_PASSWD=${DB_PASSWORD}
- DB_HOST=romm-db
- DB_PORT=3306
- DB_NAME=romm
- DB_USER=romm
- REDIS_HOST=romm-redis
- REDIS_PORT=6379
- ROMM_PORT=8080
- IGDB_CLIENT_ID=${IGDB_CLIENT_ID:-}
- IGDB_CLIENT_SECRET=${IGDB_CLIENT_SECRET:-}
- STEAMGRIDDB_API_KEY=${STEAMGRIDDB_API_KEY:-}
- TZ=Europe/Budapest
volumes:
- romm_library:/romm/library
- romm_resources:/romm/resources
- romm_config:/romm/config
networks:
- traefik-public
- romm-internal
labels:
- "traefik.enable=true"
- "traefik.http.routers.romm.rule=Host(`arcade.{{DOMAIN}}`)"
- "traefik.http.routers.romm.entrypoints=websecure"
- "traefik.http.routers.romm.tls=true"
- "traefik.http.services.romm.loadbalancer.server.port=8080"
romm-db:
image: mariadb:11.4
container_name: romm-db
restart: unless-stopped
environment:
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
- MYSQL_DATABASE=romm
- MYSQL_USER=romm
- MYSQL_PASSWORD=${DB_PASSWORD}
- TZ=Europe/Budapest
volumes:
- romm_db_data:/var/lib/mysql
networks:
- romm-internal
healthcheck:
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
romm-redis:
image: redis:7-alpine
container_name: romm-redis
restart: unless-stopped
command: redis-server --appendonly yes
volumes:
- romm_redis_data:/data
networks:
- romm-internal
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 3
volumes:
romm_library:
romm_resources:
romm_config:
romm_db_data:
romm_redis_data:
networks:
traefik-public:
external: true
romm-internal:
+49
View File
@@ -0,0 +1,49 @@
# Stirling-PDF - PDF Manipulation Toolkit
# Domain: pdf.{{DOMAIN}}
# Database: None
# RAM: ~200MB | Pi-compatible: Yes
#
# Environment variables (set in Portainer):
# (none required for basic usage)
# SECURITY_ENABLELOGIN=true - Enable login (optional)
# SECURITY_INITIALLOGIN_USERNAME / SECURITY_INITIALLOGIN_PASSWORD - if login enabled
#
# First-time setup:
# No login by default — accessible immediately.
# Enable login via env vars if exposing externally.
services:
stirling-pdf:
image: stirlingtools/stirling-pdf:0.45.1
container_name: stirling-pdf
restart: unless-stopped
environment:
- TZ=Europe/Budapest
- DOCKER_ENABLE_SECURITY=false
- INSTALL_BOOK_AND_ADVANCED_HTML_OPS=false
- LANGS=en_GB
volumes:
- stirling_data:/configs
- stirling_training:/usr/share/tessdata
networks:
- traefik-public
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "http://localhost:8080/api/v1/info/status"]
interval: 30s
timeout: 5s
retries: 3
start_period: 20s
labels:
- "traefik.enable=true"
- "traefik.http.routers.stirling-pdf.rule=Host(`pdf.{{DOMAIN}}`)"
- "traefik.http.routers.stirling-pdf.entrypoints=websecure"
- "traefik.http.routers.stirling-pdf.tls=true"
- "traefik.http.services.stirling-pdf.loadbalancer.server.port=8080"
volumes:
stirling_data:
stirling_training:
networks:
traefik-public:
external: true
+53
View File
@@ -0,0 +1,53 @@
# Vaultwarden - Password Manager (Bitwarden-compatible)
# Domain: vault.{{DOMAIN}}
# Database: None (SQLite, built-in)
# RAM: ~50MB | Pi-compatible: Yes
#
# Environment variables (set in Portainer):
# ADMIN_TOKEN - Admin panel token (optional but recommended, generate with: openssl rand -hex 32)
# SIGNUPS_ALLOWED - Set to "false" after creating your account(s)
#
# First-time setup:
# 1. Visit https://vault.{{DOMAIN}} and create an account
# 2. Set SIGNUPS_ALLOWED=false in Portainer env vars
# 3. Redeploy stack
# 4. Admin panel at https://vault.{{DOMAIN}}/admin (if ADMIN_TOKEN set)
#
# Clients:
# Use any Bitwarden client (desktop, mobile, browser extension)
# Set server URL to: https://vault.{{DOMAIN}}
services:
vaultwarden:
image: vaultwarden/server:1.33.2-alpine
container_name: vaultwarden
restart: unless-stopped
environment:
- DOMAIN=https://vault.{{DOMAIN}}
- SIGNUPS_ALLOWED=${SIGNUPS_ALLOWED:-true}
- ADMIN_TOKEN=${ADMIN_TOKEN:-}
- WEBSOCKET_ENABLED=true
- TZ=Europe/Budapest
volumes:
- vaultwarden_data:/data
networks:
- traefik-public
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "http://localhost:80/alive"]
interval: 30s
timeout: 5s
retries: 3
start_period: 10s
labels:
- "traefik.enable=true"
- "traefik.http.routers.vaultwarden.rule=Host(`vault.{{DOMAIN}}`)"
- "traefik.http.routers.vaultwarden.entrypoints=websecure"
- "traefik.http.routers.vaultwarden.tls=true"
- "traefik.http.services.vaultwarden.loadbalancer.server.port=80"
volumes:
vaultwarden_data:
networks:
traefik-public:
external: true