diff --git a/README.md b/README.md index 44d1518..d395c6f 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,11 @@ Central repository for Felhom customer application templates. ``` app-catalog-felhom.eu/ <- This repo (source of truth) -├── templates.json # Portainer App Templates index (generic, with env var prompts) +├── templates.json # Portainer App Templates index (LEGACY — Portainer-only setups) ├── templates/ # Docker Compose templates with ${VAR} env var syntax │ ├── actualbudget/ +│ │ ├── docker-compose.yml +│ │ └── .felhom.yml # App metadata for felhom-controller │ ├── docmost/ │ ├── filebrowser/ │ ├── homebox/ @@ -19,112 +21,103 @@ app-catalog-felhom.eu/ <- This repo (source of truth) │ ├── stirling-pdf/ │ └── vaultwarden/ └── scripts/ - └── generate-customer.sh # Generates customer-specific templates with baked-in secrets + └── generate-customer.sh # LEGACY — generates customer-specific templates for Portainer ``` -The output is pushed to: -**https://gitea.dooplex.hu/admin/customers-felhom.eu** +## How It Works (Controller-based deployments) -``` -customers-felhom.eu/ <- Generated per-customer deployments -├── demo-felhom/ -│ ├── templates.json # Customer Portainer templates (zero env vars, zero-touch deploy) -│ ├── secrets.env # Reference copy of all generated secrets -│ ├── actualbudget/docker-compose.yml -│ ├── docmost/docker-compose.yml -│ └── ... -└── pi-customer-1/ - ├── templates.json - ├── secrets.env - ├── actualbudget/docker-compose.yml - └── ... +The **felhom-controller** syncs directly from this repo: + +1. Controller periodically pulls this repo (configurable interval, default 15m) +2. Copies `docker-compose.yml` and `.felhom.yml` from `templates//` to `/opt/docker/stacks//` +3. **Never overwrites** `app.yaml` (deployed config/secrets) or `.env` files +4. Only copies files if content has actually changed (SHA-256 comparison) +5. After sync, triggers a stack rescan so new/updated apps appear on the dashboard +6. Manual sync available via "Sablonok frissítése" button on the Alkalmazások page + +### Controller git config (in controller.yaml) + +```yaml +git: + repo_url: "https://gitea.dooplex.hu/admin/app-catalog-felhom.eu.git" + branch: "main" + sync_interval: "15m" + username: "" # Optional, for private repos + token: "" # Optional, for private repos ``` -## How It Works +## .felhom.yml Format -1. **Templates** in this repo contain Docker Compose files with `${DOMAIN}`, `${HDD_PATH}`, and `${SECRET}` placeholders -2. **`generate-customer.sh`** substitutes all values (domain, HDD path, auto-generated passwords) and produces customer-specific compose files + a Portainer `templates.json` with zero env vars -3. **`docker-setup.sh`** on the customer node starts Portainer with `--templates` pointing at the customer's generated `templates.json` -4. **Customer** opens Portainer -> Templates -> picks an app -> clicks Deploy -> **done** +Each app template has a `.felhom.yml` metadata file that the controller uses for: +- Display info on the dashboard (name, description, category, subdomain) +- Resource hints (memory request/limit, Pi compatibility, HDD requirement) +- Deploy fields (what the user fills in during first deployment) -## Workflow +### Field types -### 1. Generate customer templates (on your workstation) +| Type | Description | +|------|-------------| +| `domain` | Auto-filled from controller config, read-only | +| `secret` | Auto-generated, hidden from user (user sees "Generated ✓") | +| `password` | Auto-generated but shown, user can override | +| `path` | Filesystem path (validated for existence) | +| `text` | Free text input | +| `select` | Dropdown with predefined options | +| `boolean` | Toggle switch | -```bash -# Full setup: all apps, with HDD -./scripts/generate-customer.sh --customer demo-felhom \ - --domain demo-felhom.eu --hdd-path /mnt/hdd_1 --push +### Generator types (for secret/password fields) -# Raspberry Pi: lightweight apps only, no HDD yet -./scripts/generate-customer.sh --customer pi-customer-1 \ - --domain pi-customer-1.local \ - --apps actualbudget,filebrowser,mealie,stirling-pdf,vaultwarden --push +| Generator | Description | +|-----------|-------------| +| `password:N` | N chars alphanumeric | +| `hex:N` | N bytes hex-encoded | +| `static:VAL` | Fixed value | -# Preview without creating files -./scripts/generate-customer.sh --customer test --domain test.local --dry-run +### Example .felhom.yml + +```yaml +display_name: "Paperless-ngx" +description: "Dokumentumok digitalizálása és rendszerezése" +category: "productivity" +subdomain: "paperless" +slug: "paperless-ngx" +resources: + mem_request: "500M" + mem_limit: "1152M" + pi_compatible: true + needs_hdd: true +deploy_fields: + - env_var: DOMAIN + label: "Domain" + type: domain + locked_after_deploy: true + - env_var: DB_PASSWORD + label: "Adatbázis jelszó" + type: secret + generate: "password:24" + locked_after_deploy: true + - env_var: HDD_PATH + label: "Adattárolási útvonal" + type: path + required: true + placeholder: "/mnt/hdd_1" + locked_after_deploy: true ``` -Options: -- `--customer ID` -- Customer identifier (required) -- `--domain DOMAIN` -- Customer domain (required) -- `--hdd-path PATH` -- External HDD mount path (optional; apps needing it show a field in Portainer if omitted) -- `--apps LIST` -- Comma-separated app list (default: all available) -- `--push` -- Git commit and push to customers-felhom.eu repo -- `--dry-run` -- Show what would be done -- `--debug` -- Verbose output +## App Catalog -### 2. Set up customer server - -```bash -sudo ./docker-setup.sh --domain demo-felhom.eu --customer demo-felhom \ - --email certs@felhom.eu --cf-token -``` - -### 3. Deploy apps - -Open `https://portainer.` -> **Templates** -> pick an app -> **Deploy the stack**. - -All fields (domain, passwords, secrets) are pre-filled. If HDD_PATH wasn't set during generation, apps that need it will show one field to fill in. - -### Re-generating after changes - -Re-running `generate-customer.sh` for an existing customer preserves all previously generated secrets (idempotent). Only new apps or new secrets are generated. - -```bash -# Add an app to an existing customer -./scripts/generate-customer.sh --customer demo-felhom \ - --domain demo-felhom.eu --hdd-path /mnt/hdd_1 --push -``` - -## Environment Variables & Secrets - -Secrets are auto-generated by `generate-customer.sh` and baked directly into the compose files and Portainer templates. They are **not** stored separately on the customer node -- they live in the customers-felhom.eu Git repo (which is private on your Gitea). - -A `secrets.env` reference file is generated alongside the compose files for easy lookup. - -### Secret definitions - -Defined in `generate-customer.sh` via the `APP_SECRET_DEFS` array: - -```bash -APP_SECRET_DEFS=( - "docmost:APP_SECRET:hex:32" - "docmost:DB_PASSWORD:password:24" - "immich:DB_PASSWORD:password:24" - "paperless-ngx:PAPERLESS_SECRET_KEY:hex:32" - "paperless-ngx:DB_PASSWORD:password:24" - "paperless-ngx:PAPERLESS_ADMIN_USER:static:admin" - "paperless-ngx:PAPERLESS_ADMIN_PASSWORD:password:16" - "romm:DB_PASSWORD:password:24" - "romm:MYSQL_ROOT_PASSWORD:password:24" - "romm:ROMM_AUTH_SECRET_KEY:hex:32" - "vaultwarden:ADMIN_TOKEN:hex:32" - "vaultwarden:SIGNUPS_ALLOWED:static:true" -) -``` - -Types: `password:LENGTH` (alphanumeric), `hex:LENGTH` (crypto), `static:VALUE` (fixed). +| App | DB Type | RAM (request / limit) | Pi | HDD Data | Subdomain | +|-----|---------|----------------------|-----|----------|-----------| +| ActualBudget | None (file) | 50M / 256M | yes | -- | budget.* | +| Docmost | PostgreSQL + Redis | 200M / 768M | no | -- | docs.* | +| FileBrowser | None (file) | 30M / 128M | yes | `${HDD_PATH}/storage/filebrowser/` | files.* | +| Homebox | None (SQLite) | 50M / 256M | yes | -- | inventory.* | +| Immich | PostgreSQL + Redis | 2048M / 4096M | no | `${HDD_PATH}/storage/immich/` | photos.* | +| Mealie | None (SQLite) | 200M / 1000M | yes | -- | recipes.* | +| Paperless-ngx | PostgreSQL + Redis | 500M / 1152M | yes | `${HDD_PATH}/storage/paperless/` | paperless.* | +| ROMM | MariaDB + Redis | 300M / 1024M | no | `${HDD_PATH}/storage/romm/` | arcade.* | +| Stirling-PDF | None | 200M / 512M | yes | -- | pdf.* | +| Vaultwarden | None (SQLite) | 50M / 256M | yes | -- | vault.* | ### Variable types per app @@ -141,63 +134,49 @@ Types: `password:LENGTH` (alphanumeric), `hex:LENGTH` (crypto), `static:VALUE` ( | Stirling-PDF | yes | -- | -- | | Vaultwarden | yes | -- | ADMIN_TOKEN | -## App Catalog - -| App | DB Type | RAM | Pi | HDD Data | Subdomain | -|-----|---------|-----|-----|----------|-----------| -| ActualBudget | None (file) | ~50MB | yes | -- | budget.* | -| Docmost | PostgreSQL + Redis | ~200MB | maybe | -- | docs.* | -| FileBrowser | None (file) | ~30MB | yes | `${HDD_PATH}/storage/filebrowser/` | files.* | -| Homebox | None (SQLite) | ~50MB | yes | -- | inventory.* | -| Immich | PostgreSQL + Redis | ~4GB | no | `${HDD_PATH}/storage/immich/` | photos.* | -| Mealie | None (SQLite) | ~200MB | yes | -- | recipes.* | -| Paperless-ngx | PostgreSQL + Redis | ~500MB | yes | `${HDD_PATH}/storage/paperless/` | paperless.* | -| ROMM | MariaDB + Redis | ~300MB | maybe | `${HDD_PATH}/storage/romm/` | arcade.* | -| Stirling-PDF | None | ~200MB | yes | -- | pdf.* | -| Vaultwarden | None (SQLite) | ~50MB | yes | -- | vault.* | - ### Storage strategy -- **HDD host paths** (`${HDD_PATH}/storage/...`): Large user data -- photos, documents, ROMs -- **Named Docker volumes** (on internal SSD): Databases, app config, caches -- need fast I/O +- **HDD host paths** (`${HDD_PATH}/storage/...`): Large user data — photos, documents, ROMs +- **Named Docker volumes** (on internal SSD): Databases, app config, caches — need fast I/O - Templates without `${HDD_PATH}` work without an external HDD (e.g., ActualBudget, Mealie) +### Docker Compose template standards + +All templates follow these standards (enforced via audit): +- `${DOMAIN}` variable syntax for all domain references (not hardcoded) +- `deploy.resources.limits.memory` on every service container +- Healthchecks on every service (appropriate for service type) +- `restart: unless-stopped` on every service +- `TZ=Europe/Budapest` on every service +- `traefik-public` external network + internal network for DB services +- Explicit `container_name:` on every service +- Header comment block with: app name, domain, DB type, RAM, Pi compatibility +- `depends_on` with `condition: service_healthy` for DB/Redis dependencies + +## Legacy: Portainer-based deployments + +The `generate-customer.sh` script and `templates.json` are kept for Portainer-only setups +where the felhom-controller is not used. For controller-based deployments, these are not needed. + +### Legacy workflow + +```bash +# Generate customer templates (on your workstation) +./scripts/generate-customer.sh --customer demo-felhom \ + --domain demo-felhom.eu --hdd-path /mnt/hdd_1 --push +``` + ## Adding a New App -1. Create `templates//docker-compose.yml` using `${DOMAIN}` and optionally `${HDD_PATH}` -2. Add a template entry in `templates.json` with env definitions, description, logo, and notes -3. If the app needs secrets, add entries to `APP_SECRET_DEFS` in `generate-customer.sh` -4. Re-run `generate-customer.sh --push` for each customer - -### templates.json entry format - -```json -{ - "type": 3, - "title": "App Name", - "description": "Short description.", - "categories": ["category"], - "platform": "linux", - "logo": "https://example.com/logo.png", - "note": "Access: https://subdomain.<DOMAIN>", - "repository": { - "url": "https://gitea.dooplex.hu/admin/app-catalog-felhom.eu", - "stackfile": "templates/appname/docker-compose.yml" - }, - "env": [ - { - "name": "DOMAIN", - "label": "Domain", - "description": "Your server domain (e.g., demo-felhom.eu)" - } - ] -} -``` +1. Create `templates//docker-compose.yml` following the template standards above +2. Create `templates//.felhom.yml` following the metadata format +3. Commit and push — the controller will pick it up on next sync +4. (Legacy) If also needed for Portainer: add entry to `templates.json` and `generate-customer.sh` ## Related Repositories | Repository | Purpose | |------------|---------| -| [app-catalog-felhom.eu](https://gitea.dooplex.hu/admin/app-catalog-felhom.eu) | This repo -- templates + generation script | -| [customers-felhom.eu](https://gitea.dooplex.hu/admin/customers-felhom.eu) | Generated per-customer compose files + templates | -| [deploy-portainer](https://gitea.dooplex.hu/admin/deploy-portainer) | `docker-setup.sh` -- server provisioning | \ No newline at end of file +| [app-catalog-felhom.eu](https://gitea.dooplex.hu/admin/app-catalog-felhom.eu) | This repo — templates + metadata | +| [deploy-felhom-compose](https://gitea.dooplex.hu/admin/deploy-felhom-compose) | felhom-controller + deploy scripts | +| [felhom.eu](https://gitea.dooplex.hu/admin/felhom.eu) | Website + k3s manifests | diff --git a/templates/actualbudget/.felhom.yml b/templates/actualbudget/.felhom.yml new file mode 100644 index 0000000..cc1ebf0 --- /dev/null +++ b/templates/actualbudget/.felhom.yml @@ -0,0 +1,30 @@ +# ============================================================================= +# .felhom.yml — App metadata for felhom-controller +# ============================================================================= +# Place alongside docker-compose.yml in each stack directory: +# /opt/docker/stacks/actualbudget/.felhom.yml +# ============================================================================= + +# --- Display info (shown on dashboard) --- +display_name: "ActualBudget" +description: "Személyes pénzügyek és költségvetés kezelése" +category: "finance" +subdomain: "budget" + +# --- Asset slug --- +slug: "actualbudget" + +# --- Resource hints (displayed on deploy screen) --- +resources: + mem_request: "50M" + mem_limit: "256M" + pi_compatible: true + needs_hdd: false + +# --- Deploy fields --- +deploy_fields: + - env_var: DOMAIN + label: "Domain" + type: domain + description: "A szerver domain neve" + locked_after_deploy: true diff --git a/templates/actualbudget/docker-compose.yml b/templates/actualbudget/docker-compose.yml index 6797dfc..418d157 100644 --- a/templates/actualbudget/docker-compose.yml +++ b/templates/actualbudget/docker-compose.yml @@ -1,9 +1,9 @@ # ActualBudget - Personal Finance / Budgeting # Domain: budget.${DOMAIN} # Database: None (file-based) -# RAM: ~50MB | Pi-compatible: Yes +# RAM: ~50MB (mem_limit: 256M) | Pi-compatible: Yes # -# Environment variables (set in Portainer): +# Environment variables: # DOMAIN - Your domain (e.g., demo-felhom.eu) # # First-time setup: @@ -20,6 +20,10 @@ services: - actualbudget_data:/data networks: - traefik-public + deploy: + resources: + limits: + memory: 256M healthcheck: test: ["CMD", "node", "-e", "const http = require('http'); http.get('http://localhost:5006/', (r) => { process.exit(r.statusCode === 200 ? 0 : 1) }).on('error', () => process.exit(1))"] interval: 30s @@ -39,4 +43,4 @@ volumes: networks: traefik-public: - external: true \ No newline at end of file + external: true diff --git a/templates/docmost/.felhom.yml b/templates/docmost/.felhom.yml new file mode 100644 index 0000000..048b938 --- /dev/null +++ b/templates/docmost/.felhom.yml @@ -0,0 +1,42 @@ +# ============================================================================= +# .felhom.yml — App metadata for felhom-controller +# ============================================================================= +# Place alongside docker-compose.yml in each stack directory: +# /opt/docker/stacks/docmost/.felhom.yml +# ============================================================================= + +# --- Display info (shown on dashboard) --- +display_name: "Docmost" +description: "Modern wiki és dokumentáció platform (Notion-szerű)" +category: "productivity" +subdomain: "docs" + +# --- Asset slug --- +slug: "docmost" + +# --- Resource hints (displayed on deploy screen) --- +resources: + mem_request: "200M" + mem_limit: "768M" + pi_compatible: false + needs_hdd: false + +# --- Deploy fields --- +deploy_fields: + - env_var: DOMAIN + label: "Domain" + type: domain + description: "A szerver domain neve" + locked_after_deploy: true + + - env_var: APP_SECRET + label: "Alkalmazás titkosítási kulcs" + type: secret + generate: "hex:32" + locked_after_deploy: true + + - env_var: DB_PASSWORD + label: "Adatbázis jelszó" + type: secret + generate: "password:24" + locked_after_deploy: true diff --git a/templates/docmost/docker-compose.yml b/templates/docmost/docker-compose.yml index 80cf922..a557474 100644 --- a/templates/docmost/docker-compose.yml +++ b/templates/docmost/docker-compose.yml @@ -1,12 +1,12 @@ # Docmost - Modern Wiki / Documentation (Notion-like) # Domain: docs.${DOMAIN} # Database: PostgreSQL + Redis -# RAM: ~200MB | Pi-compatible: Heavy but possible +# RAM: ~200MB (mem_limit: 768M total — docmost 384M + postgres 256M + redis 128M) | Pi-compatible: No (heavy) # -# Environment variables (set in Portainer): +# Environment variables: # DOMAIN - Your domain (e.g., demo-felhom.eu) -# APP_SECRET - Random secret for session signing (generate with: openssl rand -hex 32) -# DB_PASSWORD - PostgreSQL password +# APP_SECRET - Random secret for session signing (auto-generated) +# DB_PASSWORD - PostgreSQL password (auto-generated) # # First-time setup: # First registered user becomes admin. @@ -28,11 +28,16 @@ services: - APP_URL=https://docs.${DOMAIN} - STORAGE_DRIVER=local - FILE_UPLOAD_SIZE_LIMIT=50mb + - TZ=Europe/Budapest volumes: - docmost_storage:/app/data/storage networks: - traefik-public - docmost-internal + deploy: + resources: + limits: + memory: 384M healthcheck: test: ["CMD", "node", "-e", "const http = require('http'); http.get('http://localhost:3000/', (r) => { process.exit(r.statusCode === 200 ? 0 : 1) }).on('error', () => process.exit(1))"] interval: 30s @@ -55,10 +60,15 @@ services: - POSTGRES_USER=docmost - POSTGRES_PASSWORD=${DB_PASSWORD} - POSTGRES_DB=docmost + - TZ=Europe/Budapest volumes: - docmost_postgres_data:/var/lib/postgresql/data networks: - docmost-internal + deploy: + resources: + limits: + memory: 256M healthcheck: test: ["CMD-SHELL", "pg_isready -U docmost -d docmost"] interval: 10s @@ -71,10 +81,16 @@ services: container_name: docmost-redis restart: unless-stopped command: redis-server --appendonly yes + environment: + - TZ=Europe/Budapest volumes: - docmost_redis_data:/data networks: - docmost-internal + deploy: + resources: + limits: + memory: 128M healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s @@ -89,4 +105,4 @@ volumes: networks: traefik-public: external: true - docmost-internal: \ No newline at end of file + docmost-internal: diff --git a/templates/filebrowser/.felhom.yml b/templates/filebrowser/.felhom.yml new file mode 100644 index 0000000..5e20dce --- /dev/null +++ b/templates/filebrowser/.felhom.yml @@ -0,0 +1,38 @@ +# ============================================================================= +# .felhom.yml — App metadata for felhom-controller +# ============================================================================= +# Place alongside docker-compose.yml in each stack directory: +# /opt/docker/stacks/filebrowser/.felhom.yml +# ============================================================================= + +# --- Display info (shown on dashboard) --- +display_name: "FileBrowser" +description: "Egyszerű webes fájlkezelő" +category: "tools" +subdomain: "files" + +# --- Asset slug --- +slug: "filebrowser" + +# --- Resource hints (displayed on deploy screen) --- +resources: + mem_request: "30M" + mem_limit: "128M" + pi_compatible: true + needs_hdd: true + +# --- Deploy fields --- +deploy_fields: + - env_var: DOMAIN + label: "Domain" + type: domain + description: "A szerver domain neve" + locked_after_deploy: true + + - env_var: HDD_PATH + label: "Adattárolási útvonal" + type: path + required: true + placeholder: "/mnt/hdd_1" + description: "A külső merevlemez elérési útja, ahol a fájlok tárolódnak" + locked_after_deploy: true diff --git a/templates/filebrowser/docker-compose.yml b/templates/filebrowser/docker-compose.yml index a7bdf44..7e74487 100644 --- a/templates/filebrowser/docker-compose.yml +++ b/templates/filebrowser/docker-compose.yml @@ -1,9 +1,9 @@ # FileBrowser - Simple Web File Manager # Domain: files.${DOMAIN} # Database: None (file-based) -# RAM: ~30MB | Pi-compatible: Yes +# RAM: ~30MB (mem_limit: 128M) | Pi-compatible: Yes # -# Environment variables (set in Portainer): +# Environment variables: # DOMAIN - Your domain (e.g., demo-felhom.eu) # HDD_PATH - HDD mount path (e.g., /mnt/hdd_1) # @@ -28,6 +28,10 @@ services: - filebrowser_config:/database networks: - traefik-public + deploy: + resources: + limits: + memory: 128M healthcheck: test: ["CMD", "wget", "--spider", "-q", "http://localhost:80/health"] interval: 30s @@ -47,4 +51,4 @@ volumes: networks: traefik-public: - external: true \ No newline at end of file + external: true diff --git a/templates/homebox/.felhom.yml b/templates/homebox/.felhom.yml new file mode 100644 index 0000000..cbb6034 --- /dev/null +++ b/templates/homebox/.felhom.yml @@ -0,0 +1,30 @@ +# ============================================================================= +# .felhom.yml — App metadata for felhom-controller +# ============================================================================= +# Place alongside docker-compose.yml in each stack directory: +# /opt/docker/stacks/homebox/.felhom.yml +# ============================================================================= + +# --- Display info (shown on dashboard) --- +display_name: "Homebox" +description: "Otthoni leltár és eszköznyilvántartás" +category: "tools" +subdomain: "inventory" + +# --- Asset slug --- +slug: "homebox" + +# --- Resource hints (displayed on deploy screen) --- +resources: + mem_request: "50M" + mem_limit: "256M" + pi_compatible: true + needs_hdd: false + +# --- Deploy fields --- +deploy_fields: + - env_var: DOMAIN + label: "Domain" + type: domain + description: "A szerver domain neve" + locked_after_deploy: true diff --git a/templates/homebox/docker-compose.yml b/templates/homebox/docker-compose.yml index 938fcea..6b45ac0 100644 --- a/templates/homebox/docker-compose.yml +++ b/templates/homebox/docker-compose.yml @@ -1,10 +1,10 @@ # Homebox - Home Inventory Management -# Domain: inventory.{{DOMAIN}} +# Domain: inventory.${DOMAIN} # Database: None (SQLite, file-based) -# RAM: ~50MB | Pi-compatible: Yes +# RAM: ~50MB (mem_limit: 256M) | Pi-compatible: Yes # -# Environment variables (set in Portainer): -# (none required) +# Environment variables: +# DOMAIN - Your domain (e.g., demo-felhom.eu) # # First-time setup: # Register on first visit, first user becomes owner. @@ -23,6 +23,10 @@ services: - homebox_data:/data networks: - traefik-public + deploy: + resources: + limits: + memory: 256M healthcheck: test: ["CMD", "wget", "--spider", "-q", "http://localhost:7745/api/v1/status"] interval: 30s @@ -31,7 +35,7 @@ services: start_period: 10s labels: - "traefik.enable=true" - - "traefik.http.routers.homebox.rule=Host(`inventory.{{DOMAIN}}`)" + - "traefik.http.routers.homebox.rule=Host(`inventory.${DOMAIN}`)" - "traefik.http.routers.homebox.entrypoints=websecure" - "traefik.http.routers.homebox.tls=true" - "traefik.http.routers.homebox.tls.certresolver=letsencrypt" @@ -42,4 +46,4 @@ volumes: networks: traefik-public: - external: true \ No newline at end of file + external: true diff --git a/templates/immich/.felhom.yml b/templates/immich/.felhom.yml new file mode 100644 index 0000000..b341048 --- /dev/null +++ b/templates/immich/.felhom.yml @@ -0,0 +1,44 @@ +# ============================================================================= +# .felhom.yml — App metadata for felhom-controller +# ============================================================================= +# Place alongside docker-compose.yml in each stack directory: +# /opt/docker/stacks/immich/.felhom.yml +# ============================================================================= + +# --- Display info (shown on dashboard) --- +display_name: "Immich" +description: "Fotók és videók kezelése (Google Photos alternatíva)" +category: "media" +subdomain: "photos" + +# --- Asset slug --- +slug: "immich" + +# --- Resource hints (displayed on deploy screen) --- +resources: + mem_request: "2048M" + mem_limit: "4096M" + pi_compatible: false + needs_hdd: true + +# --- Deploy fields --- +deploy_fields: + - env_var: DOMAIN + label: "Domain" + type: domain + description: "A szerver domain neve" + locked_after_deploy: true + + - env_var: DB_PASSWORD + label: "Adatbázis jelszó" + type: secret + generate: "password:24" + locked_after_deploy: true + + - env_var: HDD_PATH + label: "Adattárolási útvonal" + type: path + required: true + placeholder: "/mnt/hdd_1" + description: "A külső merevlemez elérési útja, ahol a fotók és videók tárolódnak" + locked_after_deploy: true diff --git a/templates/immich/docker-compose.yml b/templates/immich/docker-compose.yml index bc12135..548b593 100644 --- a/templates/immich/docker-compose.yml +++ b/templates/immich/docker-compose.yml @@ -1,12 +1,12 @@ # Immich - Self-hosted Photo & Video Management # Domain: photos.${DOMAIN} # Database: PostgreSQL (with VectorChord) + Redis -# RAM: ~4GB minimum | Pi-compatible: No (ML too heavy) +# RAM: ~4GB minimum (mem_limit: 4096M total — server 2048M + ML 1536M + postgres 256M + redis 128M) | Pi-compatible: No (ML too heavy) # -# Environment variables (set in Portainer): +# Environment variables: # DOMAIN - Your domain (e.g., demo-felhom.eu) # HDD_PATH - HDD mount path (e.g., /mnt/hdd_1) -# DB_PASSWORD - PostgreSQL password +# DB_PASSWORD - PostgreSQL password (auto-generated) # # Storage layout: # User photos/videos → ${HDD_PATH}/storage/immich (HDD, host path) @@ -40,6 +40,10 @@ services: networks: - traefik-public - immich-internal + deploy: + resources: + limits: + memory: 2048M healthcheck: test: ["CMD", "wget", "--spider", "-q", "http://localhost:2283/api/server/ping"] interval: 30s @@ -65,6 +69,10 @@ services: - immich_ml_cache:/cache networks: - immich-internal + deploy: + resources: + limits: + memory: 1536M healthcheck: test: ["CMD", "python3", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:3003/ping')"] interval: 30s @@ -81,10 +89,15 @@ services: - POSTGRES_PASSWORD=${DB_PASSWORD} - POSTGRES_DB=immich - POSTGRES_INITDB_ARGS=--data-checksums + - TZ=Europe/Budapest volumes: - immich_postgres_data:/var/lib/postgresql/data networks: - immich-internal + deploy: + resources: + limits: + memory: 256M healthcheck: test: ["CMD-SHELL", "pg_isready -U immich -d immich"] interval: 10s @@ -97,10 +110,16 @@ services: container_name: immich-redis restart: unless-stopped command: redis-server --appendonly yes + environment: + - TZ=Europe/Budapest volumes: - immich_redis_data:/data networks: - immich-internal + deploy: + resources: + limits: + memory: 128M healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s @@ -115,4 +134,4 @@ volumes: networks: traefik-public: external: true - immich-internal: \ No newline at end of file + immich-internal: diff --git a/templates/mealie/.felhom.yml b/templates/mealie/.felhom.yml new file mode 100644 index 0000000..5c95048 --- /dev/null +++ b/templates/mealie/.felhom.yml @@ -0,0 +1,30 @@ +# ============================================================================= +# .felhom.yml — App metadata for felhom-controller +# ============================================================================= +# Place alongside docker-compose.yml in each stack directory: +# /opt/docker/stacks/mealie/.felhom.yml +# ============================================================================= + +# --- Display info (shown on dashboard) --- +display_name: "Mealie" +description: "Receptkezelő és étkezéstervező" +category: "productivity" +subdomain: "recipes" + +# --- Asset slug --- +slug: "mealie" + +# --- Resource hints (displayed on deploy screen) --- +resources: + mem_request: "200M" + mem_limit: "1000M" + pi_compatible: true + needs_hdd: false + +# --- Deploy fields --- +deploy_fields: + - env_var: DOMAIN + label: "Domain" + type: domain + description: "A szerver domain neve" + locked_after_deploy: true diff --git a/templates/mealie/docker-compose.yml b/templates/mealie/docker-compose.yml index 230b4aa..61c50b0 100644 --- a/templates/mealie/docker-compose.yml +++ b/templates/mealie/docker-compose.yml @@ -1,11 +1,10 @@ # Mealie - Recipe Manager & Meal Planner -# Domain: recipes.{{DOMAIN}} +# Domain: recipes.${DOMAIN} # Database: None (SQLite, built-in) -# RAM: ~200MB | Pi-compatible: Yes (arm64 only) +# RAM: ~200MB (mem_limit: 1000M) | 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) +# Environment variables: +# DOMAIN - Your domain (e.g., demo-felhom.eu) # # Storage layout: # Recipe data/images → mealie_data (named volume, NVMe — moderate size) @@ -26,7 +25,7 @@ services: - TZ=Europe/Budapest - MAX_WORKERS=1 - WEB_CONCURRENCY=1 - - BASE_URL=https://recipes.{{DOMAIN}} + - BASE_URL=https://recipes.${DOMAIN} volumes: - mealie_data:/app/data/ networks: @@ -43,7 +42,7 @@ services: start_period: 30s labels: - "traefik.enable=true" - - "traefik.http.routers.mealie.rule=Host(`recipes.{{DOMAIN}}`)" + - "traefik.http.routers.mealie.rule=Host(`recipes.${DOMAIN}`)" - "traefik.http.routers.mealie.entrypoints=websecure" - "traefik.http.routers.mealie.tls=true" - "traefik.http.routers.mealie.tls.certresolver=letsencrypt" @@ -54,4 +53,4 @@ volumes: networks: traefik-public: - external: true \ No newline at end of file + external: true diff --git a/templates/paperless-ngx/docker-compose.yml b/templates/paperless-ngx/docker-compose.yml index 24a30dd..18ad545 100644 --- a/templates/paperless-ngx/docker-compose.yml +++ b/templates/paperless-ngx/docker-compose.yml @@ -1,13 +1,13 @@ # Paperless-ngx - Document Management System (DMS) # Domain: paperless.${DOMAIN} # Database: PostgreSQL + Redis -# RAM: ~500MB (more with OCR/Tika) | Pi-compatible: Yes (arm64, 4GB+ RAM recommended) +# RAM: ~500MB (mem_limit: 1152M total — paperless 768M + postgres 256M + redis 128M) | Pi-compatible: Yes (arm64, 4GB+ RAM recommended) # -# Environment variables (set in Portainer): +# Environment variables: # DOMAIN - Your domain (e.g., demo-felhom.eu) # HDD_PATH - HDD mount path (e.g., /mnt/hdd_1) -# PAPERLESS_SECRET_KEY - Random secret (generate with: openssl rand -hex 32) -# DB_PASSWORD - PostgreSQL password +# PAPERLESS_SECRET_KEY - Random secret (auto-generated) +# DB_PASSWORD - PostgreSQL password (auto-generated) # PAPERLESS_ADMIN_USER - Initial admin username (default: admin) # PAPERLESS_ADMIN_PASSWORD - Initial admin password # @@ -51,6 +51,7 @@ services: - PAPERLESS_THREADS_PER_WORKER=1 - USERMAP_UID=1000 - USERMAP_GID=1000 + - TZ=Europe/Budapest volumes: - paperless_data:/usr/src/paperless/data - ${HDD_PATH}/storage/paperless/media:/usr/src/paperless/media @@ -85,6 +86,7 @@ services: - POSTGRES_USER=paperless - POSTGRES_PASSWORD=${DB_PASSWORD} - POSTGRES_DB=paperless + - TZ=Europe/Budapest volumes: - paperless_postgres_data:/var/lib/postgresql/data networks: @@ -105,6 +107,8 @@ services: container_name: paperless-redis restart: unless-stopped command: redis-server --appendonly yes + environment: + - TZ=Europe/Budapest volumes: - paperless_redis_data:/data networks: @@ -127,4 +131,4 @@ volumes: networks: traefik-public: external: true - paperless-internal: \ No newline at end of file + paperless-internal: diff --git a/templates/romm/.felhom.yml b/templates/romm/.felhom.yml new file mode 100644 index 0000000..2f08f7a --- /dev/null +++ b/templates/romm/.felhom.yml @@ -0,0 +1,56 @@ +# ============================================================================= +# .felhom.yml — App metadata for felhom-controller +# ============================================================================= +# Place alongside docker-compose.yml in each stack directory: +# /opt/docker/stacks/romm/.felhom.yml +# ============================================================================= + +# --- Display info (shown on dashboard) --- +display_name: "ROMM" +description: "Retro játékgyűjtemény kezelő" +category: "media" +subdomain: "arcade" + +# --- Asset slug --- +slug: "romm" + +# --- Resource hints (displayed on deploy screen) --- +resources: + mem_request: "300M" + mem_limit: "1024M" + pi_compatible: false + needs_hdd: true + +# --- Deploy fields --- +deploy_fields: + - env_var: DOMAIN + label: "Domain" + type: domain + description: "A szerver domain neve" + locked_after_deploy: true + + - env_var: DB_PASSWORD + label: "Adatbázis jelszó" + type: secret + generate: "password:24" + locked_after_deploy: true + + - env_var: MYSQL_ROOT_PASSWORD + label: "MariaDB root jelszó" + type: secret + generate: "password:24" + locked_after_deploy: true + + - env_var: ROMM_AUTH_SECRET_KEY + label: "Hitelesítési titkosítási kulcs" + type: secret + generate: "hex:32" + locked_after_deploy: true + + - env_var: HDD_PATH + label: "Adattárolási útvonal" + type: path + required: true + placeholder: "/mnt/hdd_1" + description: "A külső merevlemez elérési útja, ahol a ROM-ok és borítóképek tárolódnak" + locked_after_deploy: true diff --git a/templates/romm/docker-compose.yml b/templates/romm/docker-compose.yml index 6b7d218..7a61fff 100644 --- a/templates/romm/docker-compose.yml +++ b/templates/romm/docker-compose.yml @@ -1,19 +1,18 @@ # ROMM - ROM Manager for Game Libraries -# Domain: arcade.{{DOMAIN}} +# Domain: arcade.${DOMAIN} # Database: MariaDB + Redis -# RAM: ~300MB | Pi-compatible: Possible but heavy +# RAM: ~300MB (mem_limit: 1024M total — romm 512M + mariadb 384M + redis 128M) | Pi-compatible: No (MariaDB + 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) +# Environment variables: +# DOMAIN - Your domain (e.g., demo-felhom.eu) +# HDD_PATH - HDD mount path (e.g., /mnt/hdd_1) +# DB_PASSWORD - MariaDB user password (auto-generated) +# MYSQL_ROOT_PASSWORD - MariaDB root password (auto-generated) +# ROMM_AUTH_SECRET_KEY - Auth secret (auto-generated) # # Storage layout: -# ROM library → {{HDD_PATH}}/storage/romm/library (HDD, host path) -# Cover art etc → {{HDD_PATH}}/storage/romm/resources (HDD, host path) +# ROM library → ${HDD_PATH}/storage/romm/library (HDD, host path) +# Cover art etc → ${HDD_PATH}/storage/romm/resources (HDD, host path) # App config → romm_config (named volume, NVMe) # MariaDB data → romm_db_data (named volume, NVMe) # Redis data → romm_redis_data (named volume, NVMe) @@ -30,7 +29,7 @@ services: romm-db: condition: service_healthy romm-redis: - condition: service_started + condition: service_healthy entrypoint: ["/bin/sh", "-c"] command: - | @@ -60,15 +59,25 @@ services: - STEAMGRIDDB_API_KEY=${STEAMGRIDDB_API_KEY:-} - TZ=Europe/Budapest volumes: - - {{HDD_PATH}}/storage/romm/library:/romm/library - - {{HDD_PATH}}/storage/romm/resources:/romm/resources + - ${HDD_PATH}/storage/romm/library:/romm/library + - ${HDD_PATH}/storage/romm/resources:/romm/resources - romm_config:/romm/config networks: - traefik-public - romm-internal + deploy: + resources: + limits: + memory: 512M + healthcheck: + test: ["CMD", "wget", "--spider", "-q", "http://localhost:8080/"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 60s labels: - "traefik.enable=true" - - "traefik.http.routers.romm.rule=Host(`arcade.{{DOMAIN}}`)" + - "traefik.http.routers.romm.rule=Host(`arcade.${DOMAIN}`)" - "traefik.http.routers.romm.entrypoints=websecure" - "traefik.http.routers.romm.tls=true" - "traefik.http.routers.romm.tls.certresolver=letsencrypt" @@ -88,6 +97,10 @@ services: - romm_db_data:/var/lib/mysql networks: - romm-internal + deploy: + resources: + limits: + memory: 384M healthcheck: test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"] interval: 10s @@ -100,10 +113,16 @@ services: container_name: romm-redis restart: unless-stopped command: redis-server --appendonly yes + environment: + - TZ=Europe/Budapest volumes: - romm_redis_data:/data networks: - romm-internal + deploy: + resources: + limits: + memory: 128M healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s @@ -118,4 +137,4 @@ volumes: networks: traefik-public: external: true - romm-internal: \ No newline at end of file + romm-internal: diff --git a/templates/stirling-pdf/.felhom.yml b/templates/stirling-pdf/.felhom.yml new file mode 100644 index 0000000..02496b2 --- /dev/null +++ b/templates/stirling-pdf/.felhom.yml @@ -0,0 +1,30 @@ +# ============================================================================= +# .felhom.yml — App metadata for felhom-controller +# ============================================================================= +# Place alongside docker-compose.yml in each stack directory: +# /opt/docker/stacks/stirling-pdf/.felhom.yml +# ============================================================================= + +# --- Display info (shown on dashboard) --- +display_name: "Stirling-PDF" +description: "PDF szerkesztő és konvertáló eszköztár" +category: "tools" +subdomain: "pdf" + +# --- Asset slug --- +slug: "stirling-pdf" + +# --- Resource hints (displayed on deploy screen) --- +resources: + mem_request: "200M" + mem_limit: "512M" + pi_compatible: true + needs_hdd: false + +# --- Deploy fields --- +deploy_fields: + - env_var: DOMAIN + label: "Domain" + type: domain + description: "A szerver domain neve" + locked_after_deploy: true diff --git a/templates/stirling-pdf/docker-compose.yml b/templates/stirling-pdf/docker-compose.yml index a051c6f..c0411a2 100644 --- a/templates/stirling-pdf/docker-compose.yml +++ b/templates/stirling-pdf/docker-compose.yml @@ -1,12 +1,10 @@ # Stirling-PDF - PDF Manipulation Toolkit -# Domain: pdf.{{DOMAIN}} +# Domain: pdf.${DOMAIN} # Database: None -# RAM: ~200MB | Pi-compatible: Yes +# RAM: ~200MB (mem_limit: 512M) | 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 +# Environment variables: +# DOMAIN - Your domain (e.g., demo-felhom.eu) # # First-time setup: # No login by default — accessible immediately. @@ -27,6 +25,10 @@ services: - stirling_training:/usr/share/tessdata networks: - traefik-public + deploy: + resources: + limits: + memory: 512M healthcheck: test: ["CMD", "wget", "--spider", "-q", "http://localhost:8080/api/v1/info/status"] interval: 30s @@ -35,7 +37,7 @@ services: start_period: 20s labels: - "traefik.enable=true" - - "traefik.http.routers.stirling-pdf.rule=Host(`pdf.{{DOMAIN}}`)" + - "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.routers.stirling-pdf.tls.certresolver=letsencrypt" @@ -47,4 +49,4 @@ volumes: networks: traefik-public: - external: true \ No newline at end of file + external: true diff --git a/templates/vaultwarden/.felhom.yml b/templates/vaultwarden/.felhom.yml new file mode 100644 index 0000000..b709cb5 --- /dev/null +++ b/templates/vaultwarden/.felhom.yml @@ -0,0 +1,49 @@ +# ============================================================================= +# .felhom.yml — App metadata for felhom-controller +# ============================================================================= +# Place alongside docker-compose.yml in each stack directory: +# /opt/docker/stacks/vaultwarden/.felhom.yml +# ============================================================================= + +# --- Display info (shown on dashboard) --- +display_name: "Vaultwarden" +description: "Jelszókezelő (Bitwarden-kompatibilis)" +category: "security" +subdomain: "vault" + +# --- Asset slug --- +slug: "vaultwarden" + +# --- Resource hints (displayed on deploy screen) --- +resources: + mem_request: "50M" + mem_limit: "256M" + pi_compatible: true + needs_hdd: false + +# --- Deploy fields --- +deploy_fields: + - env_var: DOMAIN + label: "Domain" + type: domain + description: "A szerver domain neve" + locked_after_deploy: true + + - env_var: ADMIN_TOKEN + label: "Admin panel token" + type: secret + generate: "hex:32" + description: "Token az admin panel eléréséhez (https://vault./admin)" + locked_after_deploy: true + + - env_var: SIGNUPS_ALLOWED + label: "Regisztráció engedélyezése" + type: select + default: "true" + options: + - value: "true" + label: "Igen – regisztráció engedélyezve" + - value: "false" + label: "Nem – regisztráció lezárva" + description: "Új fiókok regisztrálásának engedélyezése. Az első fiók létrehozása után állítsd 'Nem'-re." + locked_after_deploy: false diff --git a/templates/vaultwarden/docker-compose.yml b/templates/vaultwarden/docker-compose.yml index 7ec4d77..e2ed38f 100644 --- a/templates/vaultwarden/docker-compose.yml +++ b/templates/vaultwarden/docker-compose.yml @@ -1,18 +1,17 @@ # Vaultwarden - Password Manager (Bitwarden-compatible) # Domain: vault.${DOMAIN} # Database: None (SQLite, built-in) -# RAM: ~50MB | Pi-compatible: Yes +# RAM: ~50MB (mem_limit: 256M) | Pi-compatible: Yes # -# Environment variables (set in Portainer): +# Environment variables: # DOMAIN - Your domain (e.g., demo-felhom.eu) -# ADMIN_TOKEN - Admin panel token (optional, generate with: openssl rand -hex 32) +# ADMIN_TOKEN - Admin panel token (auto-generated) # 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) +# 2. Set SIGNUPS_ALLOWED=false via the controller +# 3. Admin panel at https://vault.${DOMAIN}/admin (if ADMIN_TOKEN set) # # Clients: # Use any Bitwarden client (desktop, mobile, browser extension) @@ -33,6 +32,10 @@ services: - vaultwarden_data:/data networks: - traefik-public + deploy: + resources: + limits: + memory: 256M healthcheck: test: ["CMD", "wget", "--spider", "-q", "http://localhost:80/alive"] interval: 30s @@ -52,4 +55,4 @@ volumes: networks: traefik-public: - external: true \ No newline at end of file + external: true