diff --git a/CHANGELOG.md b/CHANGELOG.md index b4b6b95..a691a58 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,44 @@ +# v0.8.00-beta — 55 apps erbij, en drie kapotte images gevonden + +**De catalogus stond scheef.** Na het ARR-werk telde media 42 apps en downloaden +19, terwijl communicatie er 4 had, AI 4, financiën 3 en foto's 2. Wie de store +opende voor iets anders dan media, vond het vaak niet. Er zijn nu 55 apps bij, van +142 naar 197, gekozen op wat er in 2026 daadwerkelijk gedraaid wordt. + +**Drie nieuwe categorieën:** Statistiek (Umami, Matomo), Zakelijk (Odoo, +FreeScout, EspoCRM) en Spellen (RomM, Minecraft) — hoeken die er helemaal niet +waren. + +**Homelab-gereedschap:** Dockge, Komodo, Glance, Gatus, Scrutiny, Backrest, +Headscale, Zoraxy, CrowdSec, NetAlertX, Pocket ID en Authentik. +**Communicatie** gaat van 4 naar 12 met Mattermost, Synapse, Element, Listmonk, +Mumble, Roundcube en Stalwart. **Notities en documenten:** Outline, Trilium, +SilverBullet, Readeck, Docmost en Kiwix. Verder LibreChat, AnythingLLM, LocalAI, +Ghostfolio, Wallos, Maybe, Lychee, Piwigo, Homebox, wger, Donetick, Dawarich, +Gitea, Adminer, code-server, Woodpecker, Semaphore, Opengist, MinIO, Pingvin +Share, Leantime, PrivateBin, Emby en ConvertX. + +**Drie apps in de catalogus waren niet te installeren.** De controle die bij het +ARR-werk Huntarr ontmaskerde, is nu over alle 213 images in de catalogus gehaald. +Daaruit kwamen drie stille fouten: Forgejo wees naar `:latest` terwijl dat project +helemaal geen latest-tag publiceert, Planka naar een tag `1` die niet bestaat, en +Baby Buddy naar `ghcr.io/babybuddy/babybuddy` — een pad dat er niet is, terwijl +het sjabloon met zijn PUID/PGID al voor de linuxserver-variant geschreven was. Alle +drie rechtgezet. + +**Twee testregels waren te krap.** Een `config.yaml` in `files/` die geen +compose-bestand is, viel tussen wal en schip: hij werd niet als compose gescand en +overgeslagen omdat hij op `.yaml` eindigt — velden die alleen dáár gebruikt werden, +gingen door voor ongebruikt. En een verplicht geheim dat de gebruiker ergens anders +vandaan haalt, stond in een handmatige lijst met veldnamen. Dat is nu een vlag in +het sjabloon zelf: `"eigen_invoer": true`. + +**Nieuwe controles.** Zesendertig apps brengen inmiddels hun eigen database mee. +Daarvoor geldt nu: elke extra container draagt de servicenaam als voorvoegsel +(anders botsen twee installaties van dezelfde app), geen enkel databasewachtwoord +staat vast in een sjabloon, en er wacht altijd iemand met `depends_on` op de +database. + # v0.7.90-beta — De ARR-stack uit elkaar, en netwerkopties per container **Elk *arr-onderdeel is nu een losse app.** Wie alleen Sonarr wil, hoefde eerst diff --git a/README.md b/README.md index 1f8fd45..e32b564 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ IP-adres in je netwerk geven. | | | |---|---| -| **App-catalogus** | 96 kant-en-klare apps, ingedeeld in categorieën met kleur. Zoeken, filteren en installeren met een formulier in plaats van YAML. | +| **App-catalogus** | 197 kant-en-klare apps, ingedeeld in categorieën met kleur. Zoeken, filteren en installeren met een formulier in plaats van YAML. | | **Stacks beheren** | Starten, stoppen, bijwerken en herstarten — per stack of per losse container, met logs en live CPU-/geheugengebruik. | | **Apps koppelen** | Stacks komen op een gedeeld netwerk, zodat ze elkaar op naam bereiken. Een veld dat naar een andere app verwijst toont een keuzelijst met wat je al draait. | | **Eigen IP per stack** | Met macvlan of ipvlan krijgt een app een eigen adres in je LAN in plaats van poorten op de host. | diff --git a/VERSION b/VERSION index 8d57ee5..752fcfd 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.7.90-beta +0.8.00-beta diff --git a/apps/adminer/files/compose.yaml b/apps/adminer/files/compose.yaml new file mode 100644 index 0000000..6b42604 --- /dev/null +++ b/apps/adminer/files/compose.yaml @@ -0,0 +1,9 @@ +services: + << service_name >>: + image: adminer:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + ports: + - "<< port >>:8080" + restart: unless-stopped diff --git a/apps/adminer/template.json b/apps/adminer/template.json new file mode 100644 index 0000000..85d89a2 --- /dev/null +++ b/apps/adminer/template.json @@ -0,0 +1,51 @@ +{ + "kind": "compose", + "metadata": { + "name": "Adminer", + "description": "Databasebeheer in één bestand: MySQL, PostgreSQL, SQLite en meer, zonder installatie per database. Let op: Adminer geeft volledige toegang tot elke database die hij kan bereiken. Zet hem niet zomaar op internet.", + "tags": [ + "database", + "beheer", + "ontwikkeling" + ], + "icon": { + "provider": "selfhst", + "id": "adminer" + }, + "version": { + "name": "latest" + }, + "categories": [ + "ontwikkeling" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "adminer", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8160, + "required": true, + "description": "Standaard 8080; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + } + ] +} diff --git a/apps/anythingllm/files/compose.yaml b/apps/anythingllm/files/compose.yaml new file mode 100644 index 0000000..3320684 --- /dev/null +++ b/apps/anythingllm/files/compose.yaml @@ -0,0 +1,14 @@ +services: + << service_name >>: + image: mintplexlabs/anythingllm:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + - STORAGE_DIR=/app/server/storage + volumes: + - << appdata_dir >>/<< service_name >>:/app/server/storage + ports: + - "<< port >>:3001" + cap_add: + - SYS_ADMIN + restart: unless-stopped diff --git a/apps/anythingllm/template.json b/apps/anythingllm/template.json new file mode 100644 index 0000000..a085536 --- /dev/null +++ b/apps/anythingllm/template.json @@ -0,0 +1,61 @@ +{ + "kind": "compose", + "metadata": { + "name": "AnythingLLM", + "description": "Praat met je eigen documenten: laadt bestanden in een vectordatabase en gebruikt die als context. Werkt met Ollama.", + "tags": [ + "ai", + "llm", + "rag", + "documenten" + ], + "icon": { + "provider": "selfhst", + "id": "anythingllm" + }, + "version": { + "name": "latest" + }, + "categories": [ + "ai", + "documenten" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "anythingllm", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8142, + "required": true, + "description": "Standaard 3001; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + } + ] +} diff --git a/apps/authentik/files/compose.yaml b/apps/authentik/files/compose.yaml new file mode 100644 index 0000000..d473e6f --- /dev/null +++ b/apps/authentik/files/compose.yaml @@ -0,0 +1,58 @@ +services: + << service_name >>: + image: ghcr.io/goauthentik/server:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + - AUTHENTIK_SECRET_KEY=<< secret_key >> + - AUTHENTIK_POSTGRESQL__HOST=<< service_name >>-db + - AUTHENTIK_POSTGRESQL__USER=authentik + - AUTHENTIK_POSTGRESQL__NAME=authentik + - AUTHENTIK_POSTGRESQL__PASSWORD=<< db_password >> + - AUTHENTIK_REDIS__HOST=<< service_name >>-redis + volumes: + - << appdata_dir >>/<< service_name >>:/media + - << appdata_dir >>/<< service_name >>-templates:/templates + command: server + ports: + - "<< port >>:9000" + depends_on: + - << service_name >>-db + - << service_name >>-redis + restart: unless-stopped + << service_name >>-worker: + image: ghcr.io/goauthentik/server:latest + container_name: << service_name >>-worker + command: worker + environment: + - AUTHENTIK_SECRET_KEY=<< secret_key >> + - AUTHENTIK_POSTGRESQL__HOST=<< service_name >>-db + - AUTHENTIK_POSTGRESQL__USER=authentik + - AUTHENTIK_POSTGRESQL__NAME=authentik + - AUTHENTIK_POSTGRESQL__PASSWORD=<< db_password >> + - AUTHENTIK_REDIS__HOST=<< service_name >>-redis + volumes: + - << appdata_dir >>/<< service_name >>/media:/media + - << appdata_dir >>/<< service_name >>-templates:/templates + - /var/run/docker.sock:/var/run/docker.sock + depends_on: + - << service_name >>-db + - << service_name >>-redis + restart: unless-stopped + << service_name >>-db: + image: postgres:16-alpine + container_name: << service_name >>-db + environment: + - POSTGRES_DB=authentik + - POSTGRES_USER=authentik + - POSTGRES_PASSWORD=<< db_password >> + volumes: + - << appdata_dir >>/<< service_name >>-db:/var/lib/postgresql/data + restart: unless-stopped + << service_name >>-redis: + image: valkey/valkey:8-alpine + container_name: << service_name >>-redis + command: valkey-server --save 60 1 + volumes: + - << appdata_dir >>/<< service_name >>-redis:/data + restart: unless-stopped diff --git a/apps/authentik/template.json b/apps/authentik/template.json new file mode 100644 index 0000000..7579807 --- /dev/null +++ b/apps/authentik/template.json @@ -0,0 +1,86 @@ +{ + "kind": "compose", + "metadata": { + "name": "Authentik", + "description": "Volledige identiteitsserver: OIDC, SAML, LDAP en passkeys, met een visuele opbouw van je inlogstappen. De zwaardere broer van Authelia.", + "tags": [ + "sso", + "oidc", + "saml", + "ldap", + "authenticatie" + ], + "icon": { + "provider": "selfhst", + "id": "authentik" + }, + "version": { + "name": "latest" + }, + "categories": [ + "beveiliging" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "authentik", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8133, + "required": true, + "description": "Standaard 9000; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + }, + { + "title": "Toegang", + "items": [ + { + "name": "db_password", + "type": "str", + "title": "Databasewachtwoord", + "default": "", + "required": true, + "secret": true, + "generate": "auto", + "description": "Wordt automatisch ingevuld en in .env bewaard" + }, + { + "name": "secret_key", + "type": "str", + "title": "Geheime sleutel", + "default": "", + "required": true, + "secret": true, + "generate": "auto", + "description": "Ondertekent de sessies; verlies je hem, dan moet iedereen opnieuw inloggen" + } + ] + } + ] +} diff --git a/apps/baby-buddy/files/compose.yaml b/apps/baby-buddy/files/compose.yaml index 04b966f..2ac12d8 100644 --- a/apps/baby-buddy/files/compose.yaml +++ b/apps/baby-buddy/files/compose.yaml @@ -1,6 +1,6 @@ services: << service_name >>: - image: ghcr.io/babybuddy/babybuddy:latest + image: lscr.io/linuxserver/babybuddy:latest container_name: << service_name >> ports: - "<< port >>:8000" @@ -12,5 +12,5 @@ services: - ALLOWED_HOSTS=<< allowed_hosts >> - CSRF_TRUSTED_ORIGINS=http://<< allowed_hosts >> volumes: - - << appdata_dir >>/<< service_name >>/config:/app/data + - << appdata_dir >>/<< service_name >>:/config restart: unless-stopped diff --git a/apps/backrest/files/compose.yaml b/apps/backrest/files/compose.yaml new file mode 100644 index 0000000..df4b601 --- /dev/null +++ b/apps/backrest/files/compose.yaml @@ -0,0 +1,14 @@ +services: + << service_name >>: + image: garethgeorge/backrest:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + volumes: + - << appdata_dir >>/<< service_name >>:/config + - << appdata_dir >>/<< service_name >>-data:/data + - << appdata_dir >>/<< service_name >>-cache:/cache + - << bron_dir >>:/userdata:ro + ports: + - "<< port >>:9898" + restart: unless-stopped diff --git a/apps/backrest/template.json b/apps/backrest/template.json new file mode 100644 index 0000000..91ad7a0 --- /dev/null +++ b/apps/backrest/template.json @@ -0,0 +1,72 @@ +{ + "kind": "compose", + "metadata": { + "name": "Backrest", + "description": "Webinterface voor restic: back-upschema's, snapshots doorbladeren en terugzetten, zonder de commandoregel.", + "tags": [ + "backup", + "restic", + "opslag" + ], + "icon": { + "provider": "selfhst", + "id": "backrest" + }, + "version": { + "name": "latest" + }, + "categories": [ + "opslag" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "backrest", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8127, + "required": true, + "description": "Standaard 9898; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + }, + { + "title": "Instellingen", + "items": [ + { + "name": "bron_dir", + "type": "str", + "title": "Map om te back-uppen", + "default": "/opt/serverup", + "required": true, + "description": "Wordt alleen-lezen gekoppeld als /userdata" + } + ] + } + ] +} diff --git a/apps/code-server/files/compose.yaml b/apps/code-server/files/compose.yaml new file mode 100644 index 0000000..781f96c --- /dev/null +++ b/apps/code-server/files/compose.yaml @@ -0,0 +1,16 @@ +services: + << service_name >>: + image: lscr.io/linuxserver/code-server:latest + container_name: << service_name >> + environment: + - PUID=<< puid >> + - PGID=<< pgid >> + - TZ=<< timezone >> + - UMASK=002 + - PASSWORD=<< wachtwoord >> + - DEFAULT_WORKSPACE=/config/workspace + volumes: + - << appdata_dir >>/<< service_name >>:/config + ports: + - "<< port >>:8443" + restart: unless-stopped diff --git a/apps/code-server/template.json b/apps/code-server/template.json new file mode 100644 index 0000000..cf5be6c --- /dev/null +++ b/apps/code-server/template.json @@ -0,0 +1,93 @@ +{ + "kind": "compose", + "metadata": { + "name": "code-server", + "description": "Visual Studio Code in je browser, draaiend op de server. Handig om vanaf een tablet of een andere machine te werken.", + "tags": [ + "editor", + "ontwikkeling", + "code" + ], + "icon": { + "provider": "selfhst", + "id": "vscode" + }, + "version": { + "name": "latest" + }, + "categories": [ + "ontwikkeling" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "codeserver", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8161, + "required": true, + "description": "Standaard 8443; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + }, + { + "title": "Gebruiker", + "items": [ + { + "name": "puid", + "type": "int", + "title": "Gebruikers-ID (PUID)", + "default": 1000, + "required": true, + "description": "`id -u` op je server; bepaalt de eigenaar van de bestanden" + }, + { + "name": "pgid", + "type": "int", + "title": "Groeps-ID (PGID)", + "default": 1000, + "required": true + } + ] + }, + { + "title": "Toegang", + "items": [ + { + "name": "wachtwoord", + "type": "str", + "title": "Wachtwoord voor de editor", + "default": "", + "required": true, + "secret": true, + "eigen_invoer": true + } + ] + } + ] +} diff --git a/apps/convertx/files/compose.yaml b/apps/convertx/files/compose.yaml new file mode 100644 index 0000000..2bd9b6a --- /dev/null +++ b/apps/convertx/files/compose.yaml @@ -0,0 +1,13 @@ +services: + << service_name >>: + image: ghcr.io/c4illin/convertx:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + - JWT_SECRET=<< jwt_secret >> + - ACCOUNT_REGISTRATION=false + volumes: + - << appdata_dir >>/<< service_name >>:/app/data + ports: + - "<< port >>:3000" + restart: unless-stopped diff --git a/apps/convertx/template.json b/apps/convertx/template.json new file mode 100644 index 0000000..2ff62ca --- /dev/null +++ b/apps/convertx/template.json @@ -0,0 +1,73 @@ +{ + "kind": "compose", + "metadata": { + "name": "ConvertX", + "description": "Zet bestanden om naar een ander formaat in je browser: afbeeldingen, documenten, video en geluid, zonder uploaddienst van derden.", + "tags": [ + "conversie", + "bestanden", + "gereedschap" + ], + "icon": { + "provider": "selfhst", + "id": "convertx" + }, + "version": { + "name": "latest" + }, + "categories": [ + "productiviteit" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "convertx", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8176, + "required": true, + "description": "Standaard 3000; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + }, + { + "title": "Toegang", + "items": [ + { + "name": "jwt_secret", + "type": "str", + "title": "JWT-sleutel", + "default": "", + "required": true, + "secret": true, + "generate": "auto" + } + ] + } + ] +} diff --git a/apps/crowdsec/files/compose.yaml b/apps/crowdsec/files/compose.yaml new file mode 100644 index 0000000..27eef0d --- /dev/null +++ b/apps/crowdsec/files/compose.yaml @@ -0,0 +1,14 @@ +services: + << service_name >>: + image: crowdsecurity/crowdsec:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + - COLLECTIONS=crowdsecurity/linux crowdsecurity/nginx + volumes: + - << appdata_dir >>/<< service_name >>:/etc/crowdsec + - << appdata_dir >>/<< service_name >>-data:/var/lib/crowdsec/data + - << log_dir >>:/var/log/host:ro + ports: + - "<< port >>:8080" + restart: unless-stopped diff --git a/apps/crowdsec/template.json b/apps/crowdsec/template.json new file mode 100644 index 0000000..d89201a --- /dev/null +++ b/apps/crowdsec/template.json @@ -0,0 +1,72 @@ +{ + "kind": "compose", + "metadata": { + "name": "CrowdSec", + "description": "Leest je logbestanden mee en blokkeert aanvallers, met een blocklijst die door alle gebruikers samen wordt opgebouwd.", + "tags": [ + "beveiliging", + "firewall", + "logs" + ], + "icon": { + "provider": "selfhst", + "id": "crowdsec" + }, + "version": { + "name": "latest" + }, + "categories": [ + "beveiliging" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "crowdsec", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "API-poort", + "default": 8130, + "required": true, + "description": "Standaard 8080; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + }, + { + "title": "Instellingen", + "items": [ + { + "name": "log_dir", + "type": "str", + "title": "Logmap van de host", + "default": "/var/log", + "required": true, + "description": "Wordt alleen-lezen gekoppeld; hier leest CrowdSec in mee" + } + ] + } + ] +} diff --git a/apps/dawarich/files/compose.yaml b/apps/dawarich/files/compose.yaml new file mode 100644 index 0000000..09dd6b5 --- /dev/null +++ b/apps/dawarich/files/compose.yaml @@ -0,0 +1,40 @@ +services: + << service_name >>: + image: freikin/dawarich:latest + container_name: << service_name >> + environment: + - RAILS_ENV=development + - DATABASE_HOST=<< service_name >>-db + - DATABASE_USERNAME=dawarich + - DATABASE_PASSWORD=<< db_password >> + - DATABASE_NAME=dawarich + - REDIS_URL=redis://<< service_name >>-redis:6379 + - APPLICATION_HOSTS=<< app_hosts >> + - TIME_ZONE=<< timezone >> + - SECRET_KEY_BASE=<< secret_key_base >> + volumes: + - << appdata_dir >>/<< service_name >>:/var/app/public + command: ["web-entrypoint.sh", "bin/rails", "server", "-p", "3000", "-b", "::"] + ports: + - "<< port >>:3000" + depends_on: + - << service_name >>-db + - << service_name >>-redis + restart: unless-stopped + << service_name >>-db: + image: postgis/postgis:16-3.4-alpine + container_name: << service_name >>-db + environment: + - POSTGRES_DB=dawarich + - POSTGRES_USER=dawarich + - POSTGRES_PASSWORD=<< db_password >> + volumes: + - << appdata_dir >>/<< service_name >>-db:/var/lib/postgresql/data + restart: unless-stopped + << service_name >>-redis: + image: valkey/valkey:8-alpine + container_name: << service_name >>-redis + command: valkey-server --save 60 1 + volumes: + - << appdata_dir >>/<< service_name >>-redis:/data + restart: unless-stopped diff --git a/apps/dawarich/template.json b/apps/dawarich/template.json new file mode 100644 index 0000000..f0c2937 --- /dev/null +++ b/apps/dawarich/template.json @@ -0,0 +1,97 @@ +{ + "kind": "compose", + "metadata": { + "name": "Dawarich", + "description": "Je eigen locatiegeschiedenis, als vervanging van Google Maps Timeline. Importeert je oude Google-export.", + "tags": [ + "locatie", + "kaart", + "privacy" + ], + "icon": { + "provider": "selfhst", + "id": "dawarich" + }, + "version": { + "name": "latest" + }, + "categories": [ + "gezin", + "beveiliging" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "dawarich", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8152, + "required": true, + "description": "Standaard 3000; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + }, + { + "title": "Instellingen", + "items": [ + { + "name": "app_hosts", + "type": "str", + "title": "Toegestane adressen", + "default": "localhost", + "required": true, + "description": "Komma-gescheiden; Rails weigert verzoeken van andere namen" + } + ] + }, + { + "title": "Toegang", + "items": [ + { + "name": "db_password", + "type": "str", + "title": "Databasewachtwoord", + "default": "", + "required": true, + "secret": true, + "generate": "auto", + "description": "Wordt automatisch ingevuld en in .env bewaard" + }, + { + "name": "secret_key_base", + "type": "str", + "title": "Rails-sleutel", + "default": "", + "required": true, + "secret": true, + "generate": "auto" + } + ] + } + ] +} diff --git a/apps/dockge/files/compose.yaml b/apps/dockge/files/compose.yaml new file mode 100644 index 0000000..82c8724 --- /dev/null +++ b/apps/dockge/files/compose.yaml @@ -0,0 +1,14 @@ +services: + << service_name >>: + image: louislam/dockge:1 + container_name: << service_name >> + environment: + - TZ=<< timezone >> + - DOCKGE_STACKS_DIR=/opt/stacks + volumes: + - << appdata_dir >>/<< service_name >>:/app/data + - /var/run/docker.sock:/var/run/docker.sock + - << stacks_dir >>:/opt/stacks + ports: + - "<< port >>:5001" + restart: unless-stopped diff --git a/apps/dockge/template.json b/apps/dockge/template.json new file mode 100644 index 0000000..e1118d3 --- /dev/null +++ b/apps/dockge/template.json @@ -0,0 +1,73 @@ +{ + "kind": "compose", + "metadata": { + "name": "Dockge", + "description": "Beheert je compose-stacks met een interface die het compose-bestand laat zien in plaats van te verstoppen. Lichter dan Portainer.", + "tags": [ + "docker", + "beheer", + "containers" + ], + "icon": { + "provider": "selfhst", + "id": "dockge" + }, + "version": { + "name": "latest" + }, + "categories": [ + "beheer" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "dockge", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8121, + "required": true, + "description": "Standaard 5001; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + }, + { + "title": "Instellingen", + "items": [ + { + "name": "stacks_dir", + "type": "str", + "title": "Stacks-map", + "default": "/opt/stacks", + "required": true, + "description": "Waar Dockge de compose-bestanden neerzet", + "help": "Dockge bewaart hier zijn eigen stacks. Wijs dit niet naar de library van Server Up: dan beheren twee programma's dezelfde mappen en overschrijven ze elkaars werk." + } + ] + } + ] +} diff --git a/apps/docmost/files/compose.yaml b/apps/docmost/files/compose.yaml new file mode 100644 index 0000000..1fcee05 --- /dev/null +++ b/apps/docmost/files/compose.yaml @@ -0,0 +1,35 @@ +services: + << service_name >>: + image: docmost/docmost:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + - APP_URL=<< app_url >> + - APP_SECRET=<< app_secret >> + - DATABASE_URL=postgresql://docmost:<< db_password >>@<< service_name >>-db:5432/docmost?schema=public + - REDIS_URL=redis://<< service_name >>-redis:6379 + volumes: + - << appdata_dir >>/<< service_name >>:/app/data/storage + ports: + - "<< port >>:3000" + depends_on: + - << service_name >>-db + - << service_name >>-redis + restart: unless-stopped + << service_name >>-db: + image: postgres:16-alpine + container_name: << service_name >>-db + environment: + - POSTGRES_DB=docmost + - POSTGRES_USER=docmost + - POSTGRES_PASSWORD=<< db_password >> + volumes: + - << appdata_dir >>/<< service_name >>-db:/var/lib/postgresql/data + restart: unless-stopped + << service_name >>-redis: + image: valkey/valkey:8-alpine + container_name: << service_name >>-redis + command: valkey-server --save 60 1 + volumes: + - << appdata_dir >>/<< service_name >>-redis:/data + restart: unless-stopped diff --git a/apps/docmost/template.json b/apps/docmost/template.json new file mode 100644 index 0000000..75c5232 --- /dev/null +++ b/apps/docmost/template.json @@ -0,0 +1,96 @@ +{ + "kind": "compose", + "metadata": { + "name": "Docmost", + "description": "Documenten samen bewerken in realtime, met werkruimtes en rechten. Vergelijkbaar met Confluence of Notion.", + "tags": [ + "wiki", + "documenten", + "samenwerken" + ], + "icon": { + "provider": "selfhst", + "id": "docmost" + }, + "version": { + "name": "latest" + }, + "categories": [ + "documenten", + "productiviteit" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "docmost", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8157, + "required": true, + "description": "Standaard 3000; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + }, + { + "title": "Instellingen", + "items": [ + { + "name": "app_url", + "type": "str", + "title": "Publiek adres", + "default": "http://localhost:8157", + "required": true + } + ] + }, + { + "title": "Toegang", + "items": [ + { + "name": "db_password", + "type": "str", + "title": "Databasewachtwoord", + "default": "", + "required": true, + "secret": true, + "generate": "auto", + "description": "Wordt automatisch ingevuld en in .env bewaard" + }, + { + "name": "app_secret", + "type": "str", + "title": "Geheime sleutel", + "default": "", + "required": true, + "secret": true, + "generate": "auto" + } + ] + } + ] +} diff --git a/apps/donetick/files/compose.yaml b/apps/donetick/files/compose.yaml new file mode 100644 index 0000000..afdb1c9 --- /dev/null +++ b/apps/donetick/files/compose.yaml @@ -0,0 +1,14 @@ +services: + << service_name >>: + image: donetick/donetick:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + - DT_ENV=selfhosted + - DT_SQLITE_PATH=/donetick-data/donetick.db + - DT_JWT_SECRET=<< jwt_secret >> + volumes: + - << appdata_dir >>/<< service_name >>:/donetick-data + ports: + - "<< port >>:2021" + restart: unless-stopped diff --git a/apps/donetick/template.json b/apps/donetick/template.json new file mode 100644 index 0000000..85a3597 --- /dev/null +++ b/apps/donetick/template.json @@ -0,0 +1,74 @@ +{ + "kind": "compose", + "metadata": { + "name": "Donetick", + "description": "Terugkerende klusjes verdelen in huis, met beurten die doorschuiven en een melding als jij aan de beurt bent.", + "tags": [ + "taken", + "huishouden", + "klusjes" + ], + "icon": { + "provider": "selfhst", + "id": "donetick" + }, + "version": { + "name": "latest" + }, + "categories": [ + "gezin", + "productiviteit" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "donetick", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8151, + "required": true, + "description": "Standaard 2021; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + }, + { + "title": "Toegang", + "items": [ + { + "name": "jwt_secret", + "type": "str", + "title": "JWT-sleutel", + "default": "", + "required": true, + "secret": true, + "generate": "auto" + } + ] + } + ] +} diff --git a/apps/element/files/compose.yaml b/apps/element/files/compose.yaml new file mode 100644 index 0000000..d705ac5 --- /dev/null +++ b/apps/element/files/compose.yaml @@ -0,0 +1,11 @@ +services: + << service_name >>: + image: vectorim/element-web:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + volumes: + - ./config.json:/app/config.json:ro + ports: + - "<< port >>:80" + restart: unless-stopped diff --git a/apps/element/files/config.json b/apps/element/files/config.json new file mode 100644 index 0000000..4e01b03 --- /dev/null +++ b/apps/element/files/config.json @@ -0,0 +1,10 @@ +{ + "default_server_config": { + "m.homeserver": { + "base_url": "<< homeserver >>", + "server_name": "<< server_name >>" + } + }, + "brand": "Element", + "disable_guests": true +} diff --git a/apps/element/template.json b/apps/element/template.json new file mode 100644 index 0000000..59780a5 --- /dev/null +++ b/apps/element/template.json @@ -0,0 +1,77 @@ +{ + "kind": "compose", + "metadata": { + "name": "Element", + "description": "Webclient voor Matrix. Wijst standaard naar matrix.org; koppel hem aan je eigen Synapse.", + "tags": [ + "matrix", + "chat", + "communicatie" + ], + "icon": { + "provider": "selfhst", + "id": "element" + }, + "version": { + "name": "latest" + }, + "categories": [ + "communicatie" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "element", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8136, + "required": true, + "description": "Standaard 80; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + }, + { + "title": "Instellingen", + "items": [ + { + "name": "homeserver", + "type": "str", + "title": "Adres van je homeserver", + "default": "https://matrix.example.com", + "required": true, + "connect": { + "app": "synapse", + "scheme": "http", + "port": 8008 + }, + "help": "Het adres van de Matrix-server waar deze client op inlogt. Draai je Synapse zelf, kies die dan hier." + }, + { + "name": "server_name", + "type": "str", + "title": "Servernaam", + "default": "matrix.example.com", + "required": true, + "description": "Wordt getoond op het inlogscherm" + } + ] + } + ] +} diff --git a/apps/emby/files/compose.yaml b/apps/emby/files/compose.yaml new file mode 100644 index 0000000..e5e575a --- /dev/null +++ b/apps/emby/files/compose.yaml @@ -0,0 +1,14 @@ +services: + << service_name >>: + image: emby/embyserver:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + - UID=<< puid >> + - GID=<< pgid >> + volumes: + - << appdata_dir >>/<< service_name >>:/config + - << data_root >>/media:/data/media:ro + ports: + - "<< port >>:8096" + restart: unless-stopped diff --git a/apps/emby/template.json b/apps/emby/template.json new file mode 100644 index 0000000..c93acd1 --- /dev/null +++ b/apps/emby/template.json @@ -0,0 +1,89 @@ +{ + "kind": "compose", + "metadata": { + "name": "Emby", + "description": "Mediaserver voor films, series en muziek, met eigen apps voor tv en telefoon. Alternatief voor Jellyfin en Plex.", + "tags": [ + "media", + "streaming", + "films", + "series" + ], + "icon": { + "provider": "selfhst", + "id": "emby" + }, + "version": { + "name": "latest" + }, + "categories": [ + "media" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "emby", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8175, + "required": true, + "description": "Standaard 8096; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "data_root", + "type": "str", + "title": "Gedeelde datamap", + "default": "/mnt/data", + "required": true, + "description": "Eén map met je media, gekoppeld als /data", + "help": "Media en downloads horen onder één map te staan, die als /data in elke container komt. Alleen dan kan een voltooide download met een hardlink naar je bibliotheek: geen kopie, geen dubbele opslag, en je torrent blijft seeden. Zet je ze op gescheiden paden, dan kopieert elke download opnieuw. Eronder: media/films, media/series, torrents/ en usenet/." + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + }, + { + "title": "Gebruiker", + "items": [ + { + "name": "puid", + "type": "int", + "title": "Gebruikers-ID (PUID)", + "default": 1000, + "required": true, + "description": "`id -u` op je server; bepaalt de eigenaar van de bestanden" + }, + { + "name": "pgid", + "type": "int", + "title": "Groeps-ID (PGID)", + "default": 1000, + "required": true + } + ] + } + ] +} diff --git a/apps/espocrm/files/compose.yaml b/apps/espocrm/files/compose.yaml new file mode 100644 index 0000000..96588fb --- /dev/null +++ b/apps/espocrm/files/compose.yaml @@ -0,0 +1,31 @@ +services: + << service_name >>: + image: espocrm/espocrm:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + - ESPOCRM_DATABASE_HOST=<< service_name >>-db + - ESPOCRM_DATABASE_NAME=espocrm + - ESPOCRM_DATABASE_USER=espocrm + - ESPOCRM_DATABASE_PASSWORD=<< db_password >> + - ESPOCRM_ADMIN_USERNAME=<< admin_user >> + - ESPOCRM_ADMIN_PASSWORD=<< admin_password >> + - ESPOCRM_SITE_URL=<< app_url >> + volumes: + - << appdata_dir >>/<< service_name >>:/var/www/html + ports: + - "<< port >>:80" + depends_on: + - << service_name >>-db + restart: unless-stopped + << service_name >>-db: + image: mariadb:11 + container_name: << service_name >>-db + environment: + - MARIADB_DATABASE=espocrm + - MARIADB_USER=espocrm + - MARIADB_PASSWORD=<< db_password >> + - MARIADB_ROOT_PASSWORD=<< db_password >> + volumes: + - << appdata_dir >>/<< service_name >>-db:/var/lib/mysql + restart: unless-stopped diff --git a/apps/espocrm/template.json b/apps/espocrm/template.json new file mode 100644 index 0000000..7547291 --- /dev/null +++ b/apps/espocrm/template.json @@ -0,0 +1,102 @@ +{ + "kind": "compose", + "metadata": { + "name": "EspoCRM", + "description": "Klantrelatiebeheer: contacten, kansen, offertes en e-mail op één plek, met eigen velden en schermen.", + "tags": [ + "crm", + "klanten", + "verkoop" + ], + "icon": { + "provider": "selfhst", + "id": "espocrm" + }, + "version": { + "name": "latest" + }, + "categories": [ + "zakelijk" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "espocrm", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8171, + "required": true, + "description": "Standaard 80; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + }, + { + "title": "Instellingen", + "items": [ + { + "name": "admin_user", + "type": "str", + "title": "Beheerdersnaam", + "default": "admin", + "required": true + }, + { + "name": "app_url", + "type": "str", + "title": "Publiek adres", + "default": "http://localhost:8171", + "required": true + } + ] + }, + { + "title": "Toegang", + "items": [ + { + "name": "db_password", + "type": "str", + "title": "Databasewachtwoord", + "default": "", + "required": true, + "secret": true, + "generate": "auto", + "description": "Wordt automatisch ingevuld en in .env bewaard" + }, + { + "name": "admin_password", + "type": "str", + "title": "Beheerderswachtwoord", + "default": "", + "required": true, + "secret": true, + "eigen_invoer": true + } + ] + } + ] +} diff --git a/apps/forgejo/files/compose.yaml b/apps/forgejo/files/compose.yaml index 6d96d0a..2b8ce42 100644 --- a/apps/forgejo/files/compose.yaml +++ b/apps/forgejo/files/compose.yaml @@ -1,6 +1,6 @@ services: << service_name >>: - image: codeberg.org/forgejo/forgejo:latest + image: codeberg.org/forgejo/forgejo:13 container_name: << service_name >> ports: - "<< port_web >>:3000" diff --git a/apps/freescout/files/compose.yaml b/apps/freescout/files/compose.yaml new file mode 100644 index 0000000..5013bb3 --- /dev/null +++ b/apps/freescout/files/compose.yaml @@ -0,0 +1,33 @@ +services: + << service_name >>: + image: tiredofit/freescout:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + - SITE_URL=<< app_url >> + - DB_TYPE=mariadb + - DB_HOST=<< service_name >>-db + - DB_NAME=freescout + - DB_USER=freescout + - DB_PASS=<< db_password >> + - ADMIN_EMAIL=<< admin_email >> + - ADMIN_PASS=<< admin_password >> + - DISPLAY_ERRORS=FALSE + volumes: + - << appdata_dir >>/<< service_name >>:/data + ports: + - "<< port >>:80" + depends_on: + - << service_name >>-db + restart: unless-stopped + << service_name >>-db: + image: mariadb:11 + container_name: << service_name >>-db + environment: + - MARIADB_DATABASE=freescout + - MARIADB_USER=freescout + - MARIADB_PASSWORD=<< db_password >> + - MARIADB_ROOT_PASSWORD=<< db_password >> + volumes: + - << appdata_dir >>/<< service_name >>-db:/var/lib/mysql + restart: unless-stopped diff --git a/apps/freescout/template.json b/apps/freescout/template.json new file mode 100644 index 0000000..1126828 --- /dev/null +++ b/apps/freescout/template.json @@ -0,0 +1,104 @@ +{ + "kind": "compose", + "metadata": { + "name": "FreeScout", + "description": "Gedeelde postbus voor klantvragen: e-mails worden tickets, met notities en toewijzing per medewerker.", + "tags": [ + "helpdesk", + "tickets", + "e-mail", + "klanten" + ], + "icon": { + "provider": "selfhst", + "id": "freescout" + }, + "version": { + "name": "latest" + }, + "categories": [ + "zakelijk", + "communicatie" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "freescout", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8170, + "required": true, + "description": "Standaard 80; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + }, + { + "title": "Instellingen", + "items": [ + { + "name": "app_url", + "type": "str", + "title": "Publiek adres", + "default": "http://localhost:8170", + "required": true + }, + { + "name": "admin_email", + "type": "str", + "title": "E-mailadres beheerder", + "default": "admin@example.com", + "required": true + } + ] + }, + { + "title": "Toegang", + "items": [ + { + "name": "db_password", + "type": "str", + "title": "Databasewachtwoord", + "default": "", + "required": true, + "secret": true, + "generate": "auto", + "description": "Wordt automatisch ingevuld en in .env bewaard" + }, + { + "name": "admin_password", + "type": "str", + "title": "Beheerderswachtwoord", + "default": "", + "required": true, + "secret": true, + "eigen_invoer": true + } + ] + } + ] +} diff --git a/apps/gatus/files/compose.yaml b/apps/gatus/files/compose.yaml new file mode 100644 index 0000000..c185b38 --- /dev/null +++ b/apps/gatus/files/compose.yaml @@ -0,0 +1,12 @@ +services: + << service_name >>: + image: twinproduction/gatus:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + volumes: + - << appdata_dir >>/<< service_name >>:/config + - ./config.yaml:/config/config.yaml + ports: + - "<< port >>:8080" + restart: unless-stopped diff --git a/apps/gatus/files/config.yaml b/apps/gatus/files/config.yaml new file mode 100644 index 0000000..a7d805f --- /dev/null +++ b/apps/gatus/files/config.yaml @@ -0,0 +1,6 @@ +endpoints: + - name: server-up + url: "http://<< service_name >>:8080/health" + interval: 60s + conditions: + - "[STATUS] == 200" diff --git a/apps/gatus/template.json b/apps/gatus/template.json new file mode 100644 index 0000000..9677644 --- /dev/null +++ b/apps/gatus/template.json @@ -0,0 +1,59 @@ +{ + "kind": "compose", + "metadata": { + "name": "Gatus", + "description": "Bewaakt je diensten en toont per dienst een statuspagina met geschiedenis. Stuurt bericht als iets eruit ligt.", + "tags": [ + "monitoring", + "status", + "uptime" + ], + "icon": { + "provider": "selfhst", + "id": "gatus" + }, + "version": { + "name": "latest" + }, + "categories": [ + "monitoring" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "gatus", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8125, + "required": true, + "description": "Standaard 8080; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + } + ] +} diff --git a/apps/ghostfolio/files/compose.yaml b/apps/ghostfolio/files/compose.yaml new file mode 100644 index 0000000..9d56f22 --- /dev/null +++ b/apps/ghostfolio/files/compose.yaml @@ -0,0 +1,37 @@ +services: + << service_name >>: + image: ghostfolio/ghostfolio:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + - DATABASE_URL=postgresql://ghostfolio:<< db_password >>@<< service_name >>-db:5432/ghostfolio?sslmode=prefer + - REDIS_HOST=<< service_name >>-redis + - REDIS_PORT=6379 + - ACCESS_TOKEN_SALT=<< access_token_salt >> + - JWT_SECRET_KEY=<< jwt_secret >> + - NODE_ENV=production + volumes: + - << appdata_dir >>/<< service_name >>:/tmp/ghostfolio + ports: + - "<< port >>:3333" + depends_on: + - << service_name >>-db + - << service_name >>-redis + restart: unless-stopped + << service_name >>-db: + image: postgres:16-alpine + container_name: << service_name >>-db + environment: + - POSTGRES_DB=ghostfolio + - POSTGRES_USER=ghostfolio + - POSTGRES_PASSWORD=<< db_password >> + volumes: + - << appdata_dir >>/<< service_name >>-db:/var/lib/postgresql/data + restart: unless-stopped + << service_name >>-redis: + image: valkey/valkey:8-alpine + container_name: << service_name >>-redis + command: valkey-server --save 60 1 + volumes: + - << appdata_dir >>/<< service_name >>-redis:/data + restart: unless-stopped diff --git a/apps/ghostfolio/template.json b/apps/ghostfolio/template.json new file mode 100644 index 0000000..491062b --- /dev/null +++ b/apps/ghostfolio/template.json @@ -0,0 +1,92 @@ +{ + "kind": "compose", + "metadata": { + "name": "Ghostfolio", + "description": "Houdt je beleggingen bij over meerdere rekeningen heen, met spreiding, rendement en een tijdlijn.", + "tags": [ + "beleggen", + "portefeuille", + "financien" + ], + "icon": { + "provider": "selfhst", + "id": "ghostfolio" + }, + "version": { + "name": "latest" + }, + "categories": [ + "financien" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "ghostfolio", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8144, + "required": true, + "description": "Standaard 3333; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + }, + { + "title": "Toegang", + "items": [ + { + "name": "db_password", + "type": "str", + "title": "Databasewachtwoord", + "default": "", + "required": true, + "secret": true, + "generate": "auto", + "description": "Wordt automatisch ingevuld en in .env bewaard" + }, + { + "name": "access_token_salt", + "type": "str", + "title": "Salt voor toegangstokens", + "default": "", + "required": true, + "secret": true, + "generate": "auto" + }, + { + "name": "jwt_secret", + "type": "str", + "title": "JWT-sleutel", + "default": "", + "required": true, + "secret": true, + "generate": "auto" + } + ] + } + ] +} diff --git a/apps/gitea/files/compose.yaml b/apps/gitea/files/compose.yaml new file mode 100644 index 0000000..ac9e2e7 --- /dev/null +++ b/apps/gitea/files/compose.yaml @@ -0,0 +1,17 @@ +services: + << service_name >>: + image: gitea/gitea:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + - USER_UID=<< puid >> + - USER_GID=<< pgid >> + - GITEA__database__DB_TYPE=sqlite3 + - GITEA__server__ROOT_URL=<< root_url >> + - GITEA__server__SSH_PORT=<< port_ssh >> + volumes: + - << appdata_dir >>/<< service_name >>:/data + ports: + - "<< port >>:3000" + - "<< port_ssh >>:22" + restart: unless-stopped diff --git a/apps/gitea/template.json b/apps/gitea/template.json new file mode 100644 index 0000000..d19af93 --- /dev/null +++ b/apps/gitea/template.json @@ -0,0 +1,100 @@ +{ + "kind": "compose", + "metadata": { + "name": "Gitea", + "description": "Git-hosting met issues, pull requests en een ingebouwde registry. Het project waar Forgejo uit voortkwam.", + "tags": [ + "git", + "code", + "ontwikkeling" + ], + "icon": { + "provider": "selfhst", + "id": "gitea" + }, + "version": { + "name": "latest" + }, + "categories": [ + "ontwikkeling" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "gitea", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8159, + "required": true, + "description": "Standaard 3000; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "port_ssh", + "type": "int", + "title": "SSH-poort", + "default": 2223, + "required": true, + "description": "Voor git via ssh" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + }, + { + "title": "Gebruiker", + "items": [ + { + "name": "puid", + "type": "int", + "title": "Gebruikers-ID (PUID)", + "default": 1000, + "required": true, + "description": "`id -u` op je server; bepaalt de eigenaar van de bestanden" + }, + { + "name": "pgid", + "type": "int", + "title": "Groeps-ID (PGID)", + "default": 1000, + "required": true + } + ] + }, + { + "title": "Instellingen", + "items": [ + { + "name": "root_url", + "type": "str", + "title": "Publiek adres", + "default": "http://localhost:8159/", + "required": true, + "description": "Met een schuine streep aan het eind" + } + ] + } + ] +} diff --git a/apps/glance/files/compose.yaml b/apps/glance/files/compose.yaml new file mode 100644 index 0000000..036f784 --- /dev/null +++ b/apps/glance/files/compose.yaml @@ -0,0 +1,13 @@ +services: + << service_name >>: + image: glanceapp/glance:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + volumes: + - << appdata_dir >>/<< service_name >>:/app/config + - /var/run/docker.sock:/var/run/docker.sock:ro + - ./glance.yml:/app/config/glance.yml + ports: + - "<< port >>:8080" + restart: unless-stopped diff --git a/apps/glance/files/glance.yml b/apps/glance/files/glance.yml new file mode 100644 index 0000000..542e317 --- /dev/null +++ b/apps/glance/files/glance.yml @@ -0,0 +1,7 @@ +pages: + - name: Start + columns: + - size: full + widgets: + - type: docker-containers + - type: server-stats diff --git a/apps/glance/template.json b/apps/glance/template.json new file mode 100644 index 0000000..56a46db --- /dev/null +++ b/apps/glance/template.json @@ -0,0 +1,59 @@ +{ + "kind": "compose", + "metadata": { + "name": "Glance", + "description": "Startpagina die je feeds, servercijfers, weer en agenda's op één scherm zet. Volledig in te richten met een configuratiebestand.", + "tags": [ + "dashboard", + "startpagina", + "overzicht" + ], + "icon": { + "provider": "selfhst", + "id": "glance" + }, + "version": { + "name": "latest" + }, + "categories": [ + "beheer" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "glance", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8124, + "required": true, + "description": "Standaard 8080; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + } + ] +} diff --git a/apps/headscale/files/compose.yaml b/apps/headscale/files/compose.yaml new file mode 100644 index 0000000..2257590 --- /dev/null +++ b/apps/headscale/files/compose.yaml @@ -0,0 +1,14 @@ +services: + << service_name >>: + image: headscale/headscale:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + volumes: + - << appdata_dir >>/<< service_name >>:/etc/headscale + - << appdata_dir >>/<< service_name >>-lib:/var/lib/headscale + - ./config.yaml:/etc/headscale/config.yaml + command: serve + ports: + - "<< port >>:8080" + restart: unless-stopped diff --git a/apps/headscale/files/config.yaml b/apps/headscale/files/config.yaml new file mode 100644 index 0000000..fe2ae48 --- /dev/null +++ b/apps/headscale/files/config.yaml @@ -0,0 +1,11 @@ +server_url: http://<< server_url >> +listen_addr: 0.0.0.0:8080 +metrics_listen_addr: 127.0.0.1:9090 +noise: + private_key_path: /var/lib/headscale/noise_private.key +prefixes: + v4: 100.64.0.0/10 +database: + type: sqlite + sqlite: + path: /var/lib/headscale/db.sqlite diff --git a/apps/headscale/template.json b/apps/headscale/template.json new file mode 100644 index 0000000..7ccdd62 --- /dev/null +++ b/apps/headscale/template.json @@ -0,0 +1,74 @@ +{ + "kind": "compose", + "metadata": { + "name": "Headscale", + "description": "Eigen coördinatieserver voor Tailscale-clients, zodat je mesh-VPN niet van een externe dienst afhangt. Let op: Zet Headscale niet achter een andere reverse proxy van jezelf zonder websockets door te laten; de clients houden een verbinding open.", + "tags": [ + "vpn", + "netwerk", + "tailscale", + "wireguard" + ], + "icon": { + "provider": "selfhst", + "id": "headscale" + }, + "version": { + "name": "latest" + }, + "categories": [ + "netwerk", + "beveiliging" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "headscale", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8128, + "required": true, + "description": "Standaard 8080; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + }, + { + "title": "Instellingen", + "items": [ + { + "name": "server_url", + "type": "str", + "title": "Publiek adres", + "default": "headscale.example.com:8128", + "required": true, + "description": "Het adres waarop je clients Headscale bereiken" + } + ] + } + ] +} diff --git a/apps/homebox/files/compose.yaml b/apps/homebox/files/compose.yaml new file mode 100644 index 0000000..4b5f979 --- /dev/null +++ b/apps/homebox/files/compose.yaml @@ -0,0 +1,13 @@ +services: + << service_name >>: + image: ghcr.io/sysadminsmedia/homebox:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + - HBOX_LOG_LEVEL=info + - HBOX_OPTIONS_ALLOW_REGISTRATION=false + volumes: + - << appdata_dir >>/<< service_name >>:/data + ports: + - "<< port >>:7745" + restart: unless-stopped diff --git a/apps/homebox/template.json b/apps/homebox/template.json new file mode 100644 index 0000000..dad2fda --- /dev/null +++ b/apps/homebox/template.json @@ -0,0 +1,59 @@ +{ + "kind": "compose", + "metadata": { + "name": "Homebox", + "description": "Houdt bij wat je in huis hebt: waar het ligt, wat het kostte, wanneer de garantie afloopt. Met etiketten en QR-codes.", + "tags": [ + "inventaris", + "huishouden", + "spullen" + ], + "icon": { + "provider": "selfhst", + "id": "homebox" + }, + "version": { + "name": "latest" + }, + "categories": [ + "gezin" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "homebox", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8149, + "required": true, + "description": "Standaard 7745; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + } + ] +} diff --git a/apps/kiwix/files/compose.yaml b/apps/kiwix/files/compose.yaml new file mode 100644 index 0000000..c0c44ac --- /dev/null +++ b/apps/kiwix/files/compose.yaml @@ -0,0 +1,12 @@ +services: + << service_name >>: + image: ghcr.io/kiwix/kiwix-serve:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + volumes: + - << appdata_dir >>/<< service_name >>:/data + command: "*.zim" + ports: + - "<< port >>:8080" + restart: unless-stopped diff --git a/apps/kiwix/template.json b/apps/kiwix/template.json new file mode 100644 index 0000000..9ff4204 --- /dev/null +++ b/apps/kiwix/template.json @@ -0,0 +1,59 @@ +{ + "kind": "compose", + "metadata": { + "name": "Kiwix", + "description": "Serveert offline kopieën van Wikipedia, Stack Overflow en meer uit zim-bestanden. Werkt zonder internet. Let op: Zet eerst een of meer .zim-bestanden in de datamap; download ze op library.kiwix.org. Zonder bestand start de container niet.", + "tags": [ + "offline", + "wikipedia", + "naslag" + ], + "icon": { + "provider": "selfhst", + "id": "kiwix" + }, + "version": { + "name": "latest" + }, + "categories": [ + "documenten" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "kiwix", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8158, + "required": true, + "description": "Standaard 8080; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + } + ] +} diff --git a/apps/leantime/files/compose.yaml b/apps/leantime/files/compose.yaml new file mode 100644 index 0000000..273ed80 --- /dev/null +++ b/apps/leantime/files/compose.yaml @@ -0,0 +1,30 @@ +services: + << service_name >>: + image: leantime/leantime:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + - LEAN_DB_HOST=<< service_name >>-db + - LEAN_DB_USER=leantime + - LEAN_DB_PASSWORD=<< db_password >> + - LEAN_DB_DATABASE=leantime + - LEAN_APP_URL=<< app_url >> + - LEAN_SESSION_PASSWORD=<< session_password >> + volumes: + - << appdata_dir >>/<< service_name >>:/var/www/html/public/userfiles + ports: + - "<< port >>:8080" + depends_on: + - << service_name >>-db + restart: unless-stopped + << service_name >>-db: + image: mariadb:11 + container_name: << service_name >>-db + environment: + - MARIADB_DATABASE=leantime + - MARIADB_USER=leantime + - MARIADB_PASSWORD=<< db_password >> + - MARIADB_ROOT_PASSWORD=<< db_password >> + volumes: + - << appdata_dir >>/<< service_name >>-db:/var/lib/mysql + restart: unless-stopped diff --git a/apps/leantime/template.json b/apps/leantime/template.json new file mode 100644 index 0000000..b720bed --- /dev/null +++ b/apps/leantime/template.json @@ -0,0 +1,96 @@ +{ + "kind": "compose", + "metadata": { + "name": "Leantime", + "description": "Projectbeheer voor kleine teams: doelen, taken, tijdregistratie en een planbord, zonder de overdaad van de grote pakketten.", + "tags": [ + "projecten", + "taken", + "planning" + ], + "icon": { + "provider": "selfhst", + "id": "leantime" + }, + "version": { + "name": "latest" + }, + "categories": [ + "productiviteit", + "zakelijk" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "leantime", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8173, + "required": true, + "description": "Standaard 8080; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + }, + { + "title": "Instellingen", + "items": [ + { + "name": "app_url", + "type": "str", + "title": "Publiek adres", + "default": "http://localhost:8173", + "required": true + } + ] + }, + { + "title": "Toegang", + "items": [ + { + "name": "db_password", + "type": "str", + "title": "Databasewachtwoord", + "default": "", + "required": true, + "secret": true, + "generate": "auto", + "description": "Wordt automatisch ingevuld en in .env bewaard" + }, + { + "name": "session_password", + "type": "str", + "title": "Sleutel voor de sessies", + "default": "", + "required": true, + "secret": true, + "generate": "auto" + } + ] + } + ] +} diff --git a/apps/librechat/files/compose.yaml b/apps/librechat/files/compose.yaml new file mode 100644 index 0000000..88e7a1e --- /dev/null +++ b/apps/librechat/files/compose.yaml @@ -0,0 +1,29 @@ +services: + << service_name >>: + image: ghcr.io/danny-avila/librechat:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + - HOST=0.0.0.0 + - PORT=3080 + - MONGO_URI=mongodb://app:<< db_password >>@<< service_name >>-db:27017/LibreChat?authSource=admin + - CREDS_KEY=<< creds_key >> + - CREDS_IV=<< creds_iv >> + - JWT_SECRET=<< jwt_secret >> + - JWT_REFRESH_SECRET=<< jwt_refresh_secret >> + volumes: + - << appdata_dir >>/<< service_name >>:/app/client/public/images + ports: + - "<< port >>:3080" + depends_on: + - << service_name >>-db + restart: unless-stopped + << service_name >>-db: + image: mongo:8 + container_name: << service_name >>-db + environment: + - MONGO_INITDB_ROOT_USERNAME=app + - MONGO_INITDB_ROOT_PASSWORD=<< db_password >> + volumes: + - << appdata_dir >>/<< service_name >>-db:/data/db + restart: unless-stopped diff --git a/apps/librechat/template.json b/apps/librechat/template.json new file mode 100644 index 0000000..66741d4 --- /dev/null +++ b/apps/librechat/template.json @@ -0,0 +1,110 @@ +{ + "kind": "compose", + "metadata": { + "name": "LibreChat", + "description": "Chatinterface voor meerdere AI-aanbieders tegelijk, met gesprekken, presets en gedeelde prompts.", + "tags": [ + "ai", + "llm", + "chat" + ], + "icon": { + "provider": "selfhst", + "id": "librechat" + }, + "version": { + "name": "latest" + }, + "categories": [ + "ai" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "librechat", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8141, + "required": true, + "description": "Standaard 3080; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + }, + { + "title": "Toegang", + "items": [ + { + "name": "db_password", + "type": "str", + "title": "Databasewachtwoord", + "default": "", + "required": true, + "secret": true, + "generate": "auto", + "description": "Wordt automatisch ingevuld en in .env bewaard" + }, + { + "name": "creds_key", + "type": "str", + "title": "Sleutel voor opgeslagen gegevens", + "default": "", + "required": true, + "secret": true, + "generate": "auto" + }, + { + "name": "creds_iv", + "type": "str", + "title": "Beginwaarde voor de versleuteling", + "default": "", + "required": true, + "secret": true, + "generate": "auto" + }, + { + "name": "jwt_secret", + "type": "str", + "title": "JWT-sleutel", + "default": "", + "required": true, + "secret": true, + "generate": "auto" + }, + { + "name": "jwt_refresh_secret", + "type": "str", + "title": "JWT-vernieuwsleutel", + "default": "", + "required": true, + "secret": true, + "generate": "auto" + } + ] + } + ] +} diff --git a/apps/listmonk/files/compose.yaml b/apps/listmonk/files/compose.yaml new file mode 100644 index 0000000..c16888e --- /dev/null +++ b/apps/listmonk/files/compose.yaml @@ -0,0 +1,33 @@ +services: + << service_name >>: + image: listmonk/listmonk:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + - LISTMONK_app__address=0.0.0.0:9000 + - LISTMONK_db__host=<< service_name >>-db + - LISTMONK_db__port=5432 + - LISTMONK_db__user=listmonk + - LISTMONK_db__password=<< db_password >> + - LISTMONK_db__database=listmonk + - LISTMONK_db__ssl_mode=disable + - LISTMONK_app__admin_username=<< admin_user >> + - LISTMONK_app__admin_password=<< admin_password >> + volumes: + - << appdata_dir >>/<< service_name >>:/listmonk/uploads + command: sh -c "./listmonk --install --idempotent --yes --config '' && ./listmonk --config ''" + ports: + - "<< port >>:9000" + depends_on: + - << service_name >>-db + restart: unless-stopped + << service_name >>-db: + image: postgres:16-alpine + container_name: << service_name >>-db + environment: + - POSTGRES_DB=listmonk + - POSTGRES_USER=listmonk + - POSTGRES_PASSWORD=<< db_password >> + volumes: + - << appdata_dir >>/<< service_name >>-db:/var/lib/postgresql/data + restart: unless-stopped diff --git a/apps/listmonk/template.json b/apps/listmonk/template.json new file mode 100644 index 0000000..f762da0 --- /dev/null +++ b/apps/listmonk/template.json @@ -0,0 +1,97 @@ +{ + "kind": "compose", + "metadata": { + "name": "Listmonk", + "description": "Nieuwsbrieven en mailinglijsten versturen, met sjablonen, segmenten en statistieken per campagne.", + "tags": [ + "nieuwsbrief", + "e-mail", + "campagnes" + ], + "icon": { + "provider": "selfhst", + "id": "listmonk" + }, + "version": { + "name": "latest" + }, + "categories": [ + "communicatie", + "zakelijk" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "listmonk", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8137, + "required": true, + "description": "Standaard 9000; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + }, + { + "title": "Instellingen", + "items": [ + { + "name": "admin_user", + "type": "str", + "title": "Beheerdersnaam", + "default": "admin", + "required": true + } + ] + }, + { + "title": "Toegang", + "items": [ + { + "name": "db_password", + "type": "str", + "title": "Databasewachtwoord", + "default": "", + "required": true, + "secret": true, + "generate": "auto", + "description": "Wordt automatisch ingevuld en in .env bewaard" + }, + { + "name": "admin_password", + "type": "str", + "title": "Beheerderswachtwoord", + "default": "", + "required": true, + "secret": true, + "eigen_invoer": true, + "description": "Minimaal 8 tekens" + } + ] + } + ] +} diff --git a/apps/localai/files/compose.yaml b/apps/localai/files/compose.yaml new file mode 100644 index 0000000..fbbb692 --- /dev/null +++ b/apps/localai/files/compose.yaml @@ -0,0 +1,13 @@ +services: + << service_name >>: + image: localai/localai:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + - MODELS_PATH=/models + - THREADS=4 + volumes: + - << appdata_dir >>/<< service_name >>:/models + ports: + - "<< port >>:8080" + restart: unless-stopped diff --git a/apps/localai/template.json b/apps/localai/template.json new file mode 100644 index 0000000..cea9ff9 --- /dev/null +++ b/apps/localai/template.json @@ -0,0 +1,59 @@ +{ + "kind": "compose", + "metadata": { + "name": "LocalAI", + "description": "Draait taalmodellen lokaal achter een API die dezelfde vorm heeft als die van OpenAI, zodat bestaande tools er zo op aansluiten.", + "tags": [ + "ai", + "llm", + "api" + ], + "icon": { + "provider": "selfhst", + "id": "localai" + }, + "version": { + "name": "latest" + }, + "categories": [ + "ai" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "localai", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8143, + "required": true, + "description": "Standaard 8080; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + } + ] +} diff --git a/apps/lychee/files/compose.yaml b/apps/lychee/files/compose.yaml new file mode 100644 index 0000000..5993bd5 --- /dev/null +++ b/apps/lychee/files/compose.yaml @@ -0,0 +1,15 @@ +services: + << service_name >>: + image: lycheeorg/lychee:latest + container_name: << service_name >> + environment: + - DB_CONNECTION=sqlite + - APP_URL=<< app_url >> + - TIMEZONE=<< timezone >> + volumes: + - << appdata_dir >>/<< service_name >>:/conf + - << appdata_dir >>/<< service_name >>-uploads:/uploads + - << appdata_dir >>/<< service_name >>-sym:/sym + ports: + - "<< port >>:80" + restart: unless-stopped diff --git a/apps/lychee/template.json b/apps/lychee/template.json new file mode 100644 index 0000000..d8abca8 --- /dev/null +++ b/apps/lychee/template.json @@ -0,0 +1,71 @@ +{ + "kind": "compose", + "metadata": { + "name": "Lychee", + "description": "Fotoalbums die je kunt delen, met wachtwoorden per album en een importmap. Lichter dan Immich als je geen telefoonsynchronisatie nodig hebt.", + "tags": [ + "fotos", + "albums", + "delen" + ], + "icon": { + "provider": "selfhst", + "id": "lychee" + }, + "version": { + "name": "latest" + }, + "categories": [ + "fotos" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "lychee", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8147, + "required": true, + "description": "Standaard 80; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + }, + { + "title": "Instellingen", + "items": [ + { + "name": "app_url", + "type": "str", + "title": "Publiek adres", + "default": "http://localhost:8147", + "required": true + } + ] + } + ] +} diff --git a/apps/matomo/files/compose.yaml b/apps/matomo/files/compose.yaml new file mode 100644 index 0000000..70cfbba --- /dev/null +++ b/apps/matomo/files/compose.yaml @@ -0,0 +1,28 @@ +services: + << service_name >>: + image: matomo:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + - MATOMO_DATABASE_HOST=<< service_name >>-db + - MATOMO_DATABASE_USERNAME=matomo + - MATOMO_DATABASE_PASSWORD=<< db_password >> + - MATOMO_DATABASE_DBNAME=matomo + volumes: + - << appdata_dir >>/<< service_name >>:/var/www/html + ports: + - "<< port >>:80" + depends_on: + - << service_name >>-db + restart: unless-stopped + << service_name >>-db: + image: mariadb:11 + container_name: << service_name >>-db + environment: + - MARIADB_DATABASE=matomo + - MARIADB_USER=matomo + - MARIADB_PASSWORD=<< db_password >> + - MARIADB_ROOT_PASSWORD=<< db_password >> + volumes: + - << appdata_dir >>/<< service_name >>-db:/var/lib/mysql + restart: unless-stopped diff --git a/apps/matomo/template.json b/apps/matomo/template.json new file mode 100644 index 0000000..7904a1e --- /dev/null +++ b/apps/matomo/template.json @@ -0,0 +1,74 @@ +{ + "kind": "compose", + "metadata": { + "name": "Matomo", + "description": "Uitgebreide webstatistieken met trechters, doelen en heatmaps, waarbij de gegevens bij jou blijven.", + "tags": [ + "analytics", + "bezoekers", + "privacy" + ], + "icon": { + "provider": "selfhst", + "id": "matomo" + }, + "version": { + "name": "latest" + }, + "categories": [ + "analytics" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "matomo", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8168, + "required": true, + "description": "Standaard 80; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + }, + { + "title": "Toegang", + "items": [ + { + "name": "db_password", + "type": "str", + "title": "Databasewachtwoord", + "default": "", + "required": true, + "secret": true, + "generate": "auto", + "description": "Wordt automatisch ingevuld en in .env bewaard" + } + ] + } + ] +} diff --git a/apps/mattermost/files/compose.yaml b/apps/mattermost/files/compose.yaml new file mode 100644 index 0000000..228d249 --- /dev/null +++ b/apps/mattermost/files/compose.yaml @@ -0,0 +1,29 @@ +services: + << service_name >>: + image: mattermost/mattermost-team-edition:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + - MM_SQLSETTINGS_DRIVERNAME=postgres + - MM_SQLSETTINGS_DATASOURCE=postgres://mattermost:<< db_password >>@<< service_name >>-db:5432/mattermost?sslmode=disable + - MM_SERVICESETTINGS_SITEURL=<< site_url >> + volumes: + - << appdata_dir >>/<< service_name >>:/mattermost/config + - << appdata_dir >>/<< service_name >>-data:/mattermost/data + - << appdata_dir >>/<< service_name >>-logs:/mattermost/logs + - << appdata_dir >>/<< service_name >>-plugins:/mattermost/plugins + ports: + - "<< port >>:8065" + depends_on: + - << service_name >>-db + restart: unless-stopped + << service_name >>-db: + image: postgres:16-alpine + container_name: << service_name >>-db + environment: + - POSTGRES_DB=mattermost + - POSTGRES_USER=mattermost + - POSTGRES_PASSWORD=<< db_password >> + volumes: + - << appdata_dir >>/<< service_name >>-db:/var/lib/postgresql/data + restart: unless-stopped diff --git a/apps/mattermost/template.json b/apps/mattermost/template.json new file mode 100644 index 0000000..a86787f --- /dev/null +++ b/apps/mattermost/template.json @@ -0,0 +1,88 @@ +{ + "kind": "compose", + "metadata": { + "name": "Mattermost", + "description": "Teamchat in kanalen, met threads, zoeken en koppelingen. Het zelfgehoste alternatief voor Slack.", + "tags": [ + "chat", + "team", + "communicatie" + ], + "icon": { + "provider": "selfhst", + "id": "mattermost" + }, + "version": { + "name": "latest" + }, + "categories": [ + "communicatie", + "productiviteit" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "mattermost", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8134, + "required": true, + "description": "Standaard 8065; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + }, + { + "title": "Instellingen", + "items": [ + { + "name": "site_url", + "type": "str", + "title": "Publiek adres", + "default": "http://localhost:8134", + "required": true, + "description": "Nodig voor uitnodigingen en meldingen" + } + ] + }, + { + "title": "Toegang", + "items": [ + { + "name": "db_password", + "type": "str", + "title": "Databasewachtwoord", + "default": "", + "required": true, + "secret": true, + "generate": "auto", + "description": "Wordt automatisch ingevuld en in .env bewaard" + } + ] + } + ] +} diff --git a/apps/maybe/files/compose.yaml b/apps/maybe/files/compose.yaml new file mode 100644 index 0000000..56050fd --- /dev/null +++ b/apps/maybe/files/compose.yaml @@ -0,0 +1,31 @@ +services: + << service_name >>: + image: ghcr.io/maybe-finance/maybe:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + - SELF_HOSTED=true + - RAILS_FORCE_SSL=false + - RAILS_ASSUME_SSL=false + - SECRET_KEY_BASE=<< secret_key_base >> + - DB_HOST=<< service_name >>-db + - POSTGRES_DB=maybe + - POSTGRES_USER=maybe + - POSTGRES_PASSWORD=<< db_password >> + volumes: + - << appdata_dir >>/<< service_name >>:/rails/storage + ports: + - "<< port >>:3000" + depends_on: + - << service_name >>-db + restart: unless-stopped + << service_name >>-db: + image: postgres:16-alpine + container_name: << service_name >>-db + environment: + - POSTGRES_DB=maybe + - POSTGRES_USER=maybe + - POSTGRES_PASSWORD=<< db_password >> + volumes: + - << appdata_dir >>/<< service_name >>-db:/var/lib/postgresql/data + restart: unless-stopped diff --git a/apps/maybe/template.json b/apps/maybe/template.json new file mode 100644 index 0000000..de23230 --- /dev/null +++ b/apps/maybe/template.json @@ -0,0 +1,83 @@ +{ + "kind": "compose", + "metadata": { + "name": "Maybe", + "description": "Persoonlijke financiën op één plek: rekeningen, uitgaven, vermogen en waar het naartoe gaat.", + "tags": [ + "budget", + "vermogen", + "financien" + ], + "icon": { + "provider": "selfhst", + "id": "maybe" + }, + "version": { + "name": "latest" + }, + "categories": [ + "financien" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "maybe", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8146, + "required": true, + "description": "Standaard 3000; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + }, + { + "title": "Toegang", + "items": [ + { + "name": "db_password", + "type": "str", + "title": "Databasewachtwoord", + "default": "", + "required": true, + "secret": true, + "generate": "auto", + "description": "Wordt automatisch ingevuld en in .env bewaard" + }, + { + "name": "secret_key_base", + "type": "str", + "title": "Rails-sleutel", + "default": "", + "required": true, + "secret": true, + "generate": "auto" + } + ] + } + ] +} diff --git a/apps/minecraft/files/compose.yaml b/apps/minecraft/files/compose.yaml new file mode 100644 index 0000000..538db09 --- /dev/null +++ b/apps/minecraft/files/compose.yaml @@ -0,0 +1,14 @@ +services: + << service_name >>: + image: itzg/minecraft-server:latest + container_name: << service_name >> + environment: + - EULA=<< eula >> + - TYPE=<< server_type >> + - MEMORY=<< geheugen >> + - TZ=<< timezone >> + volumes: + - << appdata_dir >>/<< service_name >>:/data + ports: + - "<< port >>:25565" + restart: unless-stopped diff --git a/apps/minecraft/template.json b/apps/minecraft/template.json new file mode 100644 index 0000000..7ac389f --- /dev/null +++ b/apps/minecraft/template.json @@ -0,0 +1,96 @@ +{ + "kind": "compose", + "metadata": { + "name": "Minecraft-server", + "description": "Eigen Minecraft-server, met keuze uit vanilla, Paper, Fabric en Forge. Werkt met mods en plugins.", + "tags": [ + "spellen", + "minecraft", + "gameserver" + ], + "icon": { + "provider": "selfhst", + "id": "minecraft" + }, + "version": { + "name": "latest" + }, + "categories": [ + "spellen" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "minecraft", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Serverpoort", + "default": 25565, + "required": true, + "description": "Zet deze poort open in je router als je van buitenaf wilt spelen" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + }, + { + "title": "Instellingen", + "items": [ + { + "name": "eula", + "type": "bool", + "title": "Ik ga akkoord met de Minecraft-EULA", + "default": false, + "required": false, + "description": "Zonder akkoord start de server niet — zie minecraft.net/eula" + }, + { + "name": "server_type", + "type": "enum", + "title": "Serversoort", + "default": "PAPER", + "required": true, + "config": { + "options": [ + "VANILLA", + "PAPER", + "FABRIC", + "FORGE", + "SPIGOT" + ] + } + }, + { + "name": "geheugen", + "type": "str", + "title": "Geheugen", + "default": "2G", + "required": true, + "description": "Bijvoorbeeld 2G of 4G" + } + ] + } + ] +} diff --git a/apps/minio/files/compose.yaml b/apps/minio/files/compose.yaml new file mode 100644 index 0000000..380b007 --- /dev/null +++ b/apps/minio/files/compose.yaml @@ -0,0 +1,15 @@ +services: + << service_name >>: + image: minio/minio:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + - MINIO_ROOT_USER=<< root_user >> + - MINIO_ROOT_PASSWORD=<< root_password >> + volumes: + - << appdata_dir >>/<< service_name >>:/data + command: server /data --console-address ":9001" + ports: + - "<< port >>:9000" + - "<< port_console >>:9001" + restart: unless-stopped diff --git a/apps/minio/template.json b/apps/minio/template.json new file mode 100644 index 0000000..a5be599 --- /dev/null +++ b/apps/minio/template.json @@ -0,0 +1,94 @@ +{ + "kind": "compose", + "metadata": { + "name": "MinIO", + "description": "Objectopslag die de S3-API spreekt, zodat back-uptools en applicaties er zonder aanpassing op aansluiten.", + "tags": [ + "opslag", + "s3", + "objecten" + ], + "icon": { + "provider": "selfhst", + "id": "minio" + }, + "version": { + "name": "latest" + }, + "categories": [ + "opslag", + "ontwikkeling" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "minio", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "API-poort", + "default": 8164, + "required": true, + "description": "Standaard 9000; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "port_console", + "type": "int", + "title": "Beheerinterface", + "default": 8165, + "required": true + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + }, + { + "title": "Instellingen", + "items": [ + { + "name": "root_user", + "type": "str", + "title": "Beheerdersnaam", + "default": "minioadmin", + "required": true + } + ] + }, + { + "title": "Toegang", + "items": [ + { + "name": "root_password", + "type": "str", + "title": "Beheerderswachtwoord", + "default": "", + "required": true, + "secret": true, + "generate": "auto", + "description": "Minimaal 8 tekens" + } + ] + } + ] +} diff --git a/apps/mumble/files/compose.yaml b/apps/mumble/files/compose.yaml new file mode 100644 index 0000000..69cdbd1 --- /dev/null +++ b/apps/mumble/files/compose.yaml @@ -0,0 +1,14 @@ +services: + << service_name >>: + image: mumblevoip/mumble-server:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + - MUMBLE_CONFIG_welcometext=<< welkomsttekst >> + - MUMBLE_SUPERUSER_PASSWORD=<< superuser_password >> + volumes: + - << appdata_dir >>/<< service_name >>:/data + ports: + - "<< port >>:64738" + - "<< port >>:64738/udp" + restart: unless-stopped diff --git a/apps/mumble/template.json b/apps/mumble/template.json new file mode 100644 index 0000000..bfce8de --- /dev/null +++ b/apps/mumble/template.json @@ -0,0 +1,86 @@ +{ + "kind": "compose", + "metadata": { + "name": "Mumble", + "description": "Spraakserver met lage vertraging, oorspronkelijk voor gamers maar prima voor elk gesprek waar geluid telt.", + "tags": [ + "spraak", + "voip", + "communicatie" + ], + "icon": { + "provider": "selfhst", + "id": "mumble" + }, + "version": { + "name": "latest" + }, + "categories": [ + "communicatie" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "mumble", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Serverpoort", + "default": 64738, + "required": true, + "description": "TCP en UDP op hetzelfde nummer" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + }, + { + "title": "Instellingen", + "items": [ + { + "name": "welkomsttekst", + "type": "str", + "title": "Welkomsttekst", + "default": "Welkom op deze Mumble-server", + "required": false + } + ] + }, + { + "title": "Toegang", + "items": [ + { + "name": "superuser_password", + "type": "str", + "title": "SuperUser-wachtwoord", + "default": "", + "required": true, + "secret": true, + "generate": "auto", + "description": "Waarmee je de server beheert" + } + ] + } + ] +} diff --git a/apps/netalertx/files/compose.yaml b/apps/netalertx/files/compose.yaml new file mode 100644 index 0000000..b6491c0 --- /dev/null +++ b/apps/netalertx/files/compose.yaml @@ -0,0 +1,12 @@ +services: + << service_name >>: + image: jokobsk/netalertx:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + - PORT=20211 + volumes: + - << appdata_dir >>/<< service_name >>:/app/config + - << appdata_dir >>/<< service_name >>-db:/app/db + network_mode: host + restart: unless-stopped diff --git a/apps/netalertx/template.json b/apps/netalertx/template.json new file mode 100644 index 0000000..856b89c --- /dev/null +++ b/apps/netalertx/template.json @@ -0,0 +1,52 @@ +{ + "kind": "compose", + "metadata": { + "name": "NetAlertX", + "description": "Scant je netwerk en meldt het zodra er een apparaat bijkomt dat je niet kent. Let op: Draait op het netwerk van de host, want anders ziet de scanner alleen het Docker-netwerk. Bereikbaar op poort 20211 van je server.", + "tags": [ + "netwerk", + "monitoring", + "beveiliging" + ], + "icon": { + "provider": "selfhst", + "id": "netalertx" + }, + "version": { + "name": "latest" + }, + "categories": [ + "netwerk", + "monitoring" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "netalertx", + "required": true + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + } + ] +} diff --git a/apps/odoo/files/compose.yaml b/apps/odoo/files/compose.yaml new file mode 100644 index 0000000..2acac30 --- /dev/null +++ b/apps/odoo/files/compose.yaml @@ -0,0 +1,26 @@ +services: + << service_name >>: + image: odoo:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + - HOST=<< service_name >>-db + - USER=odoo + - PASSWORD=<< db_password >> + volumes: + - << appdata_dir >>/<< service_name >>:/var/lib/odoo + ports: + - "<< port >>:8069" + depends_on: + - << service_name >>-db + restart: unless-stopped + << service_name >>-db: + image: postgres:16-alpine + container_name: << service_name >>-db + environment: + - POSTGRES_DB=postgres + - POSTGRES_USER=odoo + - POSTGRES_PASSWORD=<< db_password >> + volumes: + - << appdata_dir >>/<< service_name >>-db:/var/lib/postgresql/data + restart: unless-stopped diff --git a/apps/odoo/template.json b/apps/odoo/template.json new file mode 100644 index 0000000..de90a35 --- /dev/null +++ b/apps/odoo/template.json @@ -0,0 +1,75 @@ +{ + "kind": "compose", + "metadata": { + "name": "Odoo", + "description": "Bedrijfssoftware in modules: verkoop, voorraad, facturen, CRM en boekhouding. Je zet aan wat je nodig hebt.", + "tags": [ + "erp", + "crm", + "facturen", + "boekhouding" + ], + "icon": { + "provider": "selfhst", + "id": "odoo" + }, + "version": { + "name": "latest" + }, + "categories": [ + "zakelijk" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "odoo", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8169, + "required": true, + "description": "Standaard 8069; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + }, + { + "title": "Toegang", + "items": [ + { + "name": "db_password", + "type": "str", + "title": "Databasewachtwoord", + "default": "", + "required": true, + "secret": true, + "generate": "auto", + "description": "Wordt automatisch ingevuld en in .env bewaard" + } + ] + } + ] +} diff --git a/apps/opengist/files/compose.yaml b/apps/opengist/files/compose.yaml new file mode 100644 index 0000000..0cab4c4 --- /dev/null +++ b/apps/opengist/files/compose.yaml @@ -0,0 +1,15 @@ +services: + << service_name >>: + image: ghcr.io/thomiceli/opengist:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + - OG_EXTERNAL_URL=<< app_url >> + - OG_SSH_GIT_ENABLED=true + - OG_SSH_GIT_PORT=<< port_ssh >> + volumes: + - << appdata_dir >>/<< service_name >>:/opengist + ports: + - "<< port >>:6157" + - "<< port_ssh >>:2222" + restart: unless-stopped diff --git a/apps/opengist/template.json b/apps/opengist/template.json new file mode 100644 index 0000000..50200fa --- /dev/null +++ b/apps/opengist/template.json @@ -0,0 +1,79 @@ +{ + "kind": "compose", + "metadata": { + "name": "Opengist", + "description": "Eigen plek voor codefragmenten, met versiegeschiedenis via git. Zelfgehoste GitHub Gist.", + "tags": [ + "code", + "snippets", + "git" + ], + "icon": { + "provider": "selfhst", + "id": "opengist" + }, + "version": { + "name": "latest" + }, + "categories": [ + "ontwikkeling" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "opengist", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8177, + "required": true, + "description": "Standaard 6157; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "port_ssh", + "type": "int", + "title": "SSH-poort", + "default": 2224, + "required": true, + "description": "Voor git via ssh" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + }, + { + "title": "Instellingen", + "items": [ + { + "name": "app_url", + "type": "str", + "title": "Publiek adres", + "default": "http://localhost:8177", + "required": true + } + ] + } + ] +} diff --git a/apps/outline/files/compose.yaml b/apps/outline/files/compose.yaml new file mode 100644 index 0000000..17d7476 --- /dev/null +++ b/apps/outline/files/compose.yaml @@ -0,0 +1,47 @@ +services: + << service_name >>: + image: outlinewiki/outline:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + - NODE_ENV=production + - URL=<< app_url >> + - PORT=3000 + - SECRET_KEY=<< secret_key >> + - UTILS_SECRET=<< utils_secret >> + - DATABASE_URL=postgres://outline:<< db_password >>@<< service_name >>-db:5432/outline + - PGSSLMODE=disable + - REDIS_URL=redis://<< service_name >>-redis:6379 + - FILE_STORAGE=local + - FILE_STORAGE_LOCAL_ROOT_DIR=/var/lib/outline/data + - OIDC_CLIENT_ID=<< oidc_client_id >> + - OIDC_CLIENT_SECRET=<< oidc_client_secret >> + - OIDC_AUTH_URI=<< oidc_url_inloggen >> + - OIDC_TOKEN_URI=<< oidc_url_uitwisselen >> + - OIDC_USERINFO_URI=<< oidc_url_profiel >> + - OIDC_DISPLAY_NAME=<< oidc_naam >> + volumes: + - << appdata_dir >>/<< service_name >>:/var/lib/outline/data + ports: + - "<< port >>:3000" + depends_on: + - << service_name >>-db + - << service_name >>-redis + restart: unless-stopped + << service_name >>-db: + image: postgres:16-alpine + container_name: << service_name >>-db + environment: + - POSTGRES_DB=outline + - POSTGRES_USER=outline + - POSTGRES_PASSWORD=<< db_password >> + volumes: + - << appdata_dir >>/<< service_name >>-db:/var/lib/postgresql/data + restart: unless-stopped + << service_name >>-redis: + image: valkey/valkey:8-alpine + container_name: << service_name >>-redis + command: valkey-server --save 60 1 + volumes: + - << appdata_dir >>/<< service_name >>-redis:/data + restart: unless-stopped diff --git a/apps/outline/template.json b/apps/outline/template.json new file mode 100644 index 0000000..608d240 --- /dev/null +++ b/apps/outline/template.json @@ -0,0 +1,156 @@ +{ + "kind": "compose", + "metadata": { + "name": "Outline", + "description": "Kennisbank voor teams: gedeelde documenten met versies, rechten per collectie en goed zoeken. Let op: Outline kent geen eigen wachtwoorden. Zonder werkende OIDC-instellingen kom je niet voorbij het inlogscherm.", + "tags": [ + "wiki", + "kennis", + "documenten", + "samenwerken" + ], + "icon": { + "provider": "selfhst", + "id": "outline" + }, + "version": { + "name": "latest" + }, + "categories": [ + "documenten", + "productiviteit" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "outline", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8153, + "required": true, + "description": "Standaard 3000; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + }, + { + "title": "Instellingen", + "items": [ + { + "name": "app_url", + "type": "str", + "title": "Publiek adres", + "default": "http://localhost:8153", + "required": true + }, + { + "name": "oidc_naam", + "type": "str", + "title": "Naam van je inlogdienst", + "default": "Authentik", + "required": true + }, + { + "name": "oidc_client_id", + "type": "str", + "title": "OIDC client-id", + "default": "", + "required": true, + "connect": { + "app": "authentik", + "scheme": "http", + "port": 9000 + }, + "help": "Outline heeft geen eigen accounts: je logt altijd in via een externe dienst. Maak in Authentik, Keycloak of Pocket ID een OIDC-toepassing aan en neem de gegevens hier over." + }, + { + "name": "oidc_url_inloggen", + "type": "str", + "title": "OIDC-adres om in te loggen", + "default": "", + "required": true + }, + { + "name": "oidc_url_uitwisselen", + "type": "str", + "title": "OIDC-adres om de code in te wisselen", + "default": "", + "required": true + }, + { + "name": "oidc_url_profiel", + "type": "str", + "title": "OIDC-adres met de profielgegevens", + "default": "", + "required": true + } + ] + }, + { + "title": "Toegang", + "items": [ + { + "name": "db_password", + "type": "str", + "title": "Databasewachtwoord", + "default": "", + "required": true, + "secret": true, + "generate": "auto", + "description": "Wordt automatisch ingevuld en in .env bewaard" + }, + { + "name": "secret_key", + "type": "str", + "title": "Geheime sleutel", + "default": "", + "required": true, + "secret": true, + "generate": "auto" + }, + { + "name": "utils_secret", + "type": "str", + "title": "Sleutel voor hulpfuncties", + "default": "", + "required": true, + "secret": true, + "generate": "auto" + }, + { + "name": "oidc_client_secret", + "type": "str", + "title": "OIDC client-secret", + "default": "", + "required": true, + "secret": true, + "eigen_invoer": true + } + ] + } + ] +} diff --git a/apps/pingvin-share/files/compose.yaml b/apps/pingvin-share/files/compose.yaml new file mode 100644 index 0000000..db1464f --- /dev/null +++ b/apps/pingvin-share/files/compose.yaml @@ -0,0 +1,12 @@ +services: + << service_name >>: + image: stonith404/pingvin-share:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + volumes: + - << appdata_dir >>/<< service_name >>:/opt/app/backend/data + - << appdata_dir >>/<< service_name >>-img:/opt/app/frontend/public/img + ports: + - "<< port >>:3000" + restart: unless-stopped diff --git a/apps/pingvin-share/template.json b/apps/pingvin-share/template.json new file mode 100644 index 0000000..7dab939 --- /dev/null +++ b/apps/pingvin-share/template.json @@ -0,0 +1,59 @@ +{ + "kind": "compose", + "metadata": { + "name": "Pingvin Share", + "description": "Bestanden delen via een link die vanzelf verloopt, met een limiet op het aantal downloads.", + "tags": [ + "bestanden", + "delen", + "opslag" + ], + "icon": { + "provider": "selfhst", + "id": "pingvin-share" + }, + "version": { + "name": "latest" + }, + "categories": [ + "opslag" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "pingvinshare", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8166, + "required": true, + "description": "Standaard 3000; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + } + ] +} diff --git a/apps/piwigo/files/compose.yaml b/apps/piwigo/files/compose.yaml new file mode 100644 index 0000000..52e735e --- /dev/null +++ b/apps/piwigo/files/compose.yaml @@ -0,0 +1,27 @@ +services: + << service_name >>: + image: lscr.io/linuxserver/piwigo:latest + container_name: << service_name >> + environment: + - PUID=<< puid >> + - PGID=<< pgid >> + - TZ=<< timezone >> + - UMASK=002 + volumes: + - << appdata_dir >>/<< service_name >>:/config + ports: + - "<< port >>:80" + depends_on: + - << service_name >>-db + restart: unless-stopped + << service_name >>-db: + image: mariadb:11 + container_name: << service_name >>-db + environment: + - MARIADB_DATABASE=piwigo + - MARIADB_USER=piwigo + - MARIADB_PASSWORD=<< db_password >> + - MARIADB_ROOT_PASSWORD=<< db_password >> + volumes: + - << appdata_dir >>/<< service_name >>-db:/var/lib/mysql + restart: unless-stopped diff --git a/apps/piwigo/template.json b/apps/piwigo/template.json new file mode 100644 index 0000000..9c8ca01 --- /dev/null +++ b/apps/piwigo/template.json @@ -0,0 +1,93 @@ +{ + "kind": "compose", + "metadata": { + "name": "Piwigo", + "description": "Fotobibliotheek met een eigen database, tags, gebruikersrechten en een groot aanbod aan uitbreidingen.", + "tags": [ + "fotos", + "albums" + ], + "icon": { + "provider": "selfhst", + "id": "piwigo" + }, + "version": { + "name": "latest" + }, + "categories": [ + "fotos" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "piwigo", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8148, + "required": true, + "description": "Standaard 80; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + }, + { + "title": "Gebruiker", + "items": [ + { + "name": "puid", + "type": "int", + "title": "Gebruikers-ID (PUID)", + "default": 1000, + "required": true, + "description": "`id -u` op je server; bepaalt de eigenaar van de bestanden" + }, + { + "name": "pgid", + "type": "int", + "title": "Groeps-ID (PGID)", + "default": 1000, + "required": true + } + ] + }, + { + "title": "Toegang", + "items": [ + { + "name": "db_password", + "type": "str", + "title": "Databasewachtwoord", + "default": "", + "required": true, + "secret": true, + "generate": "auto", + "description": "Wordt automatisch ingevuld en in .env bewaard" + } + ] + } + ] +} diff --git a/apps/planka/files/compose.yaml b/apps/planka/files/compose.yaml index b2a3653..91fa3d6 100644 --- a/apps/planka/files/compose.yaml +++ b/apps/planka/files/compose.yaml @@ -1,6 +1,6 @@ services: << service_name >>: - image: ghcr.io/plankanban/planka:1 + image: ghcr.io/plankanban/planka:latest container_name: << service_name >> ports: - "<< port >>:1337" diff --git a/apps/pocket-id/files/compose.yaml b/apps/pocket-id/files/compose.yaml new file mode 100644 index 0000000..86fd5c6 --- /dev/null +++ b/apps/pocket-id/files/compose.yaml @@ -0,0 +1,13 @@ +services: + << service_name >>: + image: ghcr.io/pocket-id/pocket-id:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + - APP_URL=<< app_url >> + - TRUST_PROXY=true + volumes: + - << appdata_dir >>/<< service_name >>:/app/data + ports: + - "<< port >>:1411" + restart: unless-stopped diff --git a/apps/pocket-id/template.json b/apps/pocket-id/template.json new file mode 100644 index 0000000..fb1b103 --- /dev/null +++ b/apps/pocket-id/template.json @@ -0,0 +1,74 @@ +{ + "kind": "compose", + "metadata": { + "name": "Pocket ID", + "description": "Inloggen met passkeys voor al je apps. Eenvoudiger dan Authentik of Keycloak als je alleen OIDC nodig hebt.", + "tags": [ + "sso", + "oidc", + "passkeys", + "authenticatie" + ], + "icon": { + "provider": "selfhst", + "id": "pocket-id" + }, + "version": { + "name": "latest" + }, + "categories": [ + "beveiliging" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "pocketid", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8132, + "required": true, + "description": "Standaard 1411; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + }, + { + "title": "Instellingen", + "items": [ + { + "name": "app_url", + "type": "str", + "title": "Publiek adres", + "default": "https://id.example.com", + "required": true, + "description": "Passkeys zijn aan het exacte adres gebonden", + "help": "Een passkey wordt vastgelegd op het domein waar je hem aanmaakt. Verandert dit adres later, dan werken bestaande passkeys niet meer en moet iedereen opnieuw registreren." + } + ] + } + ] +} diff --git a/apps/privatebin/files/compose.yaml b/apps/privatebin/files/compose.yaml new file mode 100644 index 0000000..ed6549c --- /dev/null +++ b/apps/privatebin/files/compose.yaml @@ -0,0 +1,11 @@ +services: + << service_name >>: + image: privatebin/nginx-fpm-alpine:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + volumes: + - << appdata_dir >>/<< service_name >>:/srv/data + ports: + - "<< port >>:8080" + restart: unless-stopped diff --git a/apps/privatebin/template.json b/apps/privatebin/template.json new file mode 100644 index 0000000..9130411 --- /dev/null +++ b/apps/privatebin/template.json @@ -0,0 +1,60 @@ +{ + "kind": "compose", + "metadata": { + "name": "PrivateBin", + "description": "Tekst delen die in je browser versleuteld wordt, zodat de server zelf niet kan lezen wat erin staat.", + "tags": [ + "pastebin", + "delen", + "privacy" + ], + "icon": { + "provider": "selfhst", + "id": "privatebin" + }, + "version": { + "name": "latest" + }, + "categories": [ + "productiviteit", + "beveiliging" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "privatebin", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8174, + "required": true, + "description": "Standaard 8080; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + } + ] +} diff --git a/apps/readeck/files/compose.yaml b/apps/readeck/files/compose.yaml new file mode 100644 index 0000000..4fc2d5c --- /dev/null +++ b/apps/readeck/files/compose.yaml @@ -0,0 +1,13 @@ +services: + << service_name >>: + image: codeberg.org/readeck/readeck:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + - READECK_LOG_LEVEL=info + - READECK_ALLOWED_HOSTS=<< toegestane_hosts >> + volumes: + - << appdata_dir >>/<< service_name >>:/readeck + ports: + - "<< port >>:8000" + restart: unless-stopped diff --git a/apps/readeck/template.json b/apps/readeck/template.json new file mode 100644 index 0000000..0fdae70 --- /dev/null +++ b/apps/readeck/template.json @@ -0,0 +1,72 @@ +{ + "kind": "compose", + "metadata": { + "name": "Readeck", + "description": "Bewaart artikelen om later te lezen, ontdaan van reclame en opmaak. Met markeringen en eigen labels.", + "tags": [ + "lezen", + "artikelen", + "bladwijzers" + ], + "icon": { + "provider": "selfhst", + "id": "readeck" + }, + "version": { + "name": "latest" + }, + "categories": [ + "documenten" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "readeck", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8156, + "required": true, + "description": "Standaard 8000; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + }, + { + "title": "Instellingen", + "items": [ + { + "name": "toegestane_hosts", + "type": "str", + "title": "Toegestane adressen", + "default": "localhost", + "required": true, + "description": "Komma-gescheiden lijst van namen waarop je Readeck opent" + } + ] + } + ] +} diff --git a/apps/romm/files/compose.yaml b/apps/romm/files/compose.yaml new file mode 100644 index 0000000..9fd3203 --- /dev/null +++ b/apps/romm/files/compose.yaml @@ -0,0 +1,32 @@ +services: + << service_name >>: + image: rommapp/romm:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + - DB_HOST=<< service_name >>-db + - DB_NAME=romm + - DB_USER=romm + - DB_PASSWD=<< db_password >> + - ROMM_AUTH_SECRET_KEY=<< auth_secret >> + volumes: + - << appdata_dir >>/<< service_name >>:/romm/config + - << data_root >>:/data + - << appdata_dir >>/<< service_name >>-resources:/romm/resources + - << appdata_dir >>/<< service_name >>-redis:/redis-data + ports: + - "<< port >>:8080" + depends_on: + - << service_name >>-db + restart: unless-stopped + << service_name >>-db: + image: mariadb:11 + container_name: << service_name >>-db + environment: + - MARIADB_DATABASE=romm + - MARIADB_USER=romm + - MARIADB_PASSWORD=<< db_password >> + - MARIADB_ROOT_PASSWORD=<< db_password >> + volumes: + - << appdata_dir >>/<< service_name >>-db:/var/lib/mysql + restart: unless-stopped diff --git a/apps/romm/template.json b/apps/romm/template.json new file mode 100644 index 0000000..73840cd --- /dev/null +++ b/apps/romm/template.json @@ -0,0 +1,93 @@ +{ + "kind": "compose", + "metadata": { + "name": "RomM", + "description": "Beheert je verzameling retro-spellen, haalt er omslagen en gegevens bij, en laat je ze in de browser spelen. Let op: Zet je roms onder /data/roms, met een submap per platform (bijvoorbeeld /data/roms/snes).", + "tags": [ + "retro", + "spellen", + "emulator" + ], + "icon": { + "provider": "selfhst", + "id": "romm" + }, + "version": { + "name": "latest" + }, + "categories": [ + "spellen", + "media" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "romm", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8172, + "required": true, + "description": "Standaard 8080; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "data_root", + "type": "str", + "title": "Gedeelde datamap", + "default": "/mnt/data", + "required": true, + "description": "Eén map met je media, gekoppeld als /data", + "help": "Media en downloads horen onder één map te staan, die als /data in elke container komt. Alleen dan kan een voltooide download met een hardlink naar je bibliotheek: geen kopie, geen dubbele opslag, en je torrent blijft seeden. Zet je ze op gescheiden paden, dan kopieert elke download opnieuw. Eronder: media/films, media/series, torrents/ en usenet/." + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + }, + { + "title": "Toegang", + "items": [ + { + "name": "db_password", + "type": "str", + "title": "Databasewachtwoord", + "default": "", + "required": true, + "secret": true, + "generate": "auto", + "description": "Wordt automatisch ingevuld en in .env bewaard" + }, + { + "name": "auth_secret", + "type": "str", + "title": "Sleutel voor de inlogsessies", + "default": "", + "required": true, + "secret": true, + "generate": "auto" + } + ] + } + ] +} diff --git a/apps/roundcube/files/compose.yaml b/apps/roundcube/files/compose.yaml new file mode 100644 index 0000000..b998afc --- /dev/null +++ b/apps/roundcube/files/compose.yaml @@ -0,0 +1,14 @@ +services: + << service_name >>: + image: roundcube/roundcubemail:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + - ROUNDCUBEMAIL_DB_TYPE=sqlite + - ROUNDCUBEMAIL_DEFAULT_HOST=<< imap_server >> + - ROUNDCUBEMAIL_SMTP_SERVER=<< smtp_server >> + volumes: + - << appdata_dir >>/<< service_name >>:/var/www/html + ports: + - "<< port >>:80" + restart: unless-stopped diff --git a/apps/roundcube/template.json b/apps/roundcube/template.json new file mode 100644 index 0000000..0778c1c --- /dev/null +++ b/apps/roundcube/template.json @@ -0,0 +1,79 @@ +{ + "kind": "compose", + "metadata": { + "name": "Roundcube", + "description": "Webmail voor een bestaande mailserver. Geen mailserver zelf: je logt in op je eigen IMAP-account.", + "tags": [ + "e-mail", + "webmail", + "imap" + ], + "icon": { + "provider": "selfhst", + "id": "roundcube" + }, + "version": { + "name": "latest" + }, + "categories": [ + "communicatie" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "roundcube", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8139, + "required": true, + "description": "Standaard 80; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + }, + { + "title": "Instellingen", + "items": [ + { + "name": "imap_server", + "type": "str", + "title": "IMAP-server", + "default": "ssl://imap.example.com", + "required": true, + "description": "Met ssl:// of tls:// ervoor" + }, + { + "name": "smtp_server", + "type": "str", + "title": "SMTP-server", + "default": "tls://smtp.example.com", + "required": true + } + ] + } + ] +} diff --git a/apps/scrutiny/files/compose.yaml b/apps/scrutiny/files/compose.yaml new file mode 100644 index 0000000..6bdfc25 --- /dev/null +++ b/apps/scrutiny/files/compose.yaml @@ -0,0 +1,17 @@ +services: + << service_name >>: + image: ghcr.io/analogj/scrutiny:master-omnibus + container_name: << service_name >> + environment: + - TZ=<< timezone >> + volumes: + - << appdata_dir >>/<< service_name >>:/opt/scrutiny/config + - << appdata_dir >>/<< service_name >>-influxdb:/opt/scrutiny/influxdb + - /run/udev:/run/udev:ro + ports: + - "<< port >>:8080" + cap_add: + - SYS_RAWIO + devices: + - /dev/sda:/dev/sda + restart: unless-stopped diff --git a/apps/scrutiny/template.json b/apps/scrutiny/template.json new file mode 100644 index 0000000..e8c7e93 --- /dev/null +++ b/apps/scrutiny/template.json @@ -0,0 +1,61 @@ +{ + "kind": "compose", + "metadata": { + "name": "Scrutiny", + "description": "Leest de SMART-gegevens van je schijven uit en waarschuwt vóórdat er een stukgaat, in plaats van erna. Let op: Pas de lijst onder `devices` aan naar de schijven in jouw server; zonder toegang tot het apparaat zelf kan Scrutiny niets uitlezen.", + "tags": [ + "schijven", + "smart", + "monitoring", + "hardware" + ], + "icon": { + "provider": "selfhst", + "id": "scrutiny" + }, + "version": { + "name": "latest" + }, + "categories": [ + "monitoring", + "opslag" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "scrutiny", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8126, + "required": true, + "description": "Standaard 8080; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + } + ] +} diff --git a/apps/semaphore/files/compose.yaml b/apps/semaphore/files/compose.yaml new file mode 100644 index 0000000..b5fa26a --- /dev/null +++ b/apps/semaphore/files/compose.yaml @@ -0,0 +1,34 @@ +services: + << service_name >>: + image: semaphoreui/semaphore:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + - SEMAPHORE_DB_DIALECT=postgres + - SEMAPHORE_DB_HOST=<< service_name >>-db + - SEMAPHORE_DB_PORT=5432 + - SEMAPHORE_DB_USER=semaphore + - SEMAPHORE_DB_PASS=<< db_password >> + - SEMAPHORE_DB=semaphore + - SEMAPHORE_ADMIN=<< admin_user >> + - SEMAPHORE_ADMIN_PASSWORD=<< admin_password >> + - SEMAPHORE_ADMIN_NAME=Beheerder + - SEMAPHORE_ADMIN_EMAIL=<< admin_email >> + - SEMAPHORE_ACCESS_KEY_ENCRYPTION=<< access_key_encryption >> + volumes: + - << appdata_dir >>/<< service_name >>:/etc/semaphore + ports: + - "<< port >>:3000" + depends_on: + - << service_name >>-db + restart: unless-stopped + << service_name >>-db: + image: postgres:16-alpine + container_name: << service_name >>-db + environment: + - POSTGRES_DB=semaphore + - POSTGRES_USER=semaphore + - POSTGRES_PASSWORD=<< db_password >> + volumes: + - << appdata_dir >>/<< service_name >>-db:/var/lib/postgresql/data + restart: unless-stopped diff --git a/apps/semaphore/template.json b/apps/semaphore/template.json new file mode 100644 index 0000000..5211f50 --- /dev/null +++ b/apps/semaphore/template.json @@ -0,0 +1,112 @@ +{ + "kind": "compose", + "metadata": { + "name": "Semaphore UI", + "description": "Webinterface voor Ansible: playbooks draaien, inventarissen beheren en zien wie wat wanneer uitvoerde.", + "tags": [ + "ansible", + "automatisering", + "ontwikkeling" + ], + "icon": { + "provider": "selfhst", + "id": "semaphore" + }, + "version": { + "name": "latest" + }, + "categories": [ + "ontwikkeling", + "beheer" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "semaphore", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8163, + "required": true, + "description": "Standaard 3000; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + }, + { + "title": "Instellingen", + "items": [ + { + "name": "admin_user", + "type": "str", + "title": "Beheerdersnaam", + "default": "admin", + "required": true + }, + { + "name": "admin_email", + "type": "str", + "title": "E-mailadres beheerder", + "default": "admin@example.com", + "required": true + } + ] + }, + { + "title": "Toegang", + "items": [ + { + "name": "db_password", + "type": "str", + "title": "Databasewachtwoord", + "default": "", + "required": true, + "secret": true, + "generate": "auto", + "description": "Wordt automatisch ingevuld en in .env bewaard" + }, + { + "name": "access_key_encryption", + "type": "str", + "title": "Sleutel voor opgeslagen inloggegevens", + "default": "", + "required": true, + "secret": true, + "generate": "auto" + }, + { + "name": "admin_password", + "type": "str", + "title": "Beheerderswachtwoord", + "default": "", + "required": true, + "secret": true, + "eigen_invoer": true + } + ] + } + ] +} diff --git a/apps/silverbullet/files/compose.yaml b/apps/silverbullet/files/compose.yaml new file mode 100644 index 0000000..5c041bb --- /dev/null +++ b/apps/silverbullet/files/compose.yaml @@ -0,0 +1,12 @@ +services: + << service_name >>: + image: ghcr.io/silverbulletmd/silverbullet:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + - SB_USER=<< gebruiker >>:<< wachtwoord >> + volumes: + - << appdata_dir >>/<< service_name >>:/space + ports: + - "<< port >>:3000" + restart: unless-stopped diff --git a/apps/silverbullet/template.json b/apps/silverbullet/template.json new file mode 100644 index 0000000..0af56d4 --- /dev/null +++ b/apps/silverbullet/template.json @@ -0,0 +1,86 @@ +{ + "kind": "compose", + "metadata": { + "name": "SilverBullet", + "description": "Notitieprogramma dat gewone markdown-bestanden op schijf gebruikt en offline doorwerkt in je browser.", + "tags": [ + "notities", + "markdown", + "documenten" + ], + "icon": { + "provider": "selfhst", + "id": "silverbullet" + }, + "version": { + "name": "latest" + }, + "categories": [ + "documenten", + "productiviteit" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "silverbullet", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8155, + "required": true, + "description": "Standaard 3000; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + }, + { + "title": "Instellingen", + "items": [ + { + "name": "gebruiker", + "type": "str", + "title": "Gebruikersnaam", + "default": "admin", + "required": true + } + ] + }, + { + "title": "Toegang", + "items": [ + { + "name": "wachtwoord", + "type": "str", + "title": "Wachtwoord", + "default": "", + "required": true, + "secret": true, + "eigen_invoer": true + } + ] + } + ] +} diff --git a/apps/stalwart/files/compose.yaml b/apps/stalwart/files/compose.yaml new file mode 100644 index 0000000..f906b50 --- /dev/null +++ b/apps/stalwart/files/compose.yaml @@ -0,0 +1,15 @@ +services: + << service_name >>: + image: stalwartlabs/stalwart:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + volumes: + - << appdata_dir >>/<< service_name >>:/opt/stalwart + ports: + - "<< port >>:8080" + - "<< port_smtp >>:25" + - "<< port_submission >>:587" + - "<< port_imap >>:143" + - "<< port_imaps >>:993" + restart: unless-stopped diff --git a/apps/stalwart/template.json b/apps/stalwart/template.json new file mode 100644 index 0000000..5ee0a9c --- /dev/null +++ b/apps/stalwart/template.json @@ -0,0 +1,92 @@ +{ + "kind": "compose", + "metadata": { + "name": "Stalwart", + "description": "Complete mailserver in één container: IMAP, JMAP, SMTP, spamfilter en een webinterface om het te beheren. Let op: Een mailserver draaien vraagt meer dan een container: je hebt een vast IP-adres nodig, kloppende SPF-, DKIM- en DMARC-records, en een reverse-DNS die op je domein uitkomt. Zonder dat komt je post niet aan.", + "tags": [ + "e-mail", + "mailserver", + "imap", + "smtp" + ], + "icon": { + "provider": "selfhst", + "id": "stalwart" + }, + "version": { + "name": "latest" + }, + "categories": [ + "communicatie" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "stalwart", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Beheerinterface", + "default": 8140, + "required": true, + "description": "Standaard 8080; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "port_smtp", + "type": "int", + "title": "SMTP", + "default": 25, + "required": true, + "advanced": true + }, + { + "name": "port_submission", + "type": "int", + "title": "SMTP (submission)", + "default": 587, + "required": true, + "advanced": true + }, + { + "name": "port_imap", + "type": "int", + "title": "IMAP", + "default": 143, + "required": true, + "advanced": true + }, + { + "name": "port_imaps", + "type": "int", + "title": "IMAP (TLS)", + "default": 993, + "required": true, + "advanced": true + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + } + ] +} diff --git a/apps/synapse/files/compose.yaml b/apps/synapse/files/compose.yaml new file mode 100644 index 0000000..57d412d --- /dev/null +++ b/apps/synapse/files/compose.yaml @@ -0,0 +1,13 @@ +services: + << service_name >>: + image: ghcr.io/element-hq/synapse:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + - SYNAPSE_SERVER_NAME=<< server_name >> + - SYNAPSE_REPORT_STATS=no + volumes: + - << appdata_dir >>/<< service_name >>:/data + ports: + - "<< port >>:8008" + restart: unless-stopped diff --git a/apps/synapse/template.json b/apps/synapse/template.json new file mode 100644 index 0000000..421fb20 --- /dev/null +++ b/apps/synapse/template.json @@ -0,0 +1,74 @@ +{ + "kind": "compose", + "metadata": { + "name": "Synapse (Matrix)", + "description": "Matrix-homeserver: versleutelde chat die met elke andere Matrix-server praat. Combineer met Element als webclient. Let op: Bij de eerste start maakt Synapse zelf een configuratiebestand aan in de datamap. Maak daarna een gebruiker met `docker exec -it register_new_matrix_user`.", + "tags": [ + "matrix", + "chat", + "federatie", + "communicatie" + ], + "icon": { + "provider": "selfhst", + "id": "matrix" + }, + "version": { + "name": "latest" + }, + "categories": [ + "communicatie" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "synapse", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8135, + "required": true, + "description": "Standaard 8008; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + }, + { + "title": "Instellingen", + "items": [ + { + "name": "server_name", + "type": "str", + "title": "Servernaam", + "default": "matrix.example.com", + "required": true, + "description": "Het domein in je Matrix-adressen (@jij:dit-domein)", + "help": "Dit staat vast zodra er accounts zijn aangemaakt: het zit in het adres van elke gebruiker en in elke kamer-id. Later wijzigen betekent opnieuw beginnen." + } + ] + } + ] +} diff --git a/apps/trilium/files/compose.yaml b/apps/trilium/files/compose.yaml new file mode 100644 index 0000000..0753efd --- /dev/null +++ b/apps/trilium/files/compose.yaml @@ -0,0 +1,11 @@ +services: + << service_name >>: + image: triliumnext/notes:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + volumes: + - << appdata_dir >>/<< service_name >>:/home/node/trilium-data + ports: + - "<< port >>:8080" + restart: unless-stopped diff --git a/apps/trilium/template.json b/apps/trilium/template.json new file mode 100644 index 0000000..ccb3eb8 --- /dev/null +++ b/apps/trilium/template.json @@ -0,0 +1,60 @@ +{ + "kind": "compose", + "metadata": { + "name": "Trilium Notes", + "description": "Notities in een boomstructuur, met onderlinge verwijzingen, versies en scripts. Sterk als je archief groot wordt.", + "tags": [ + "notities", + "kennis", + "documenten" + ], + "icon": { + "provider": "selfhst", + "id": "trilium" + }, + "version": { + "name": "latest" + }, + "categories": [ + "documenten", + "productiviteit" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "trilium", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8154, + "required": true, + "description": "Standaard 8080; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + } + ] +} diff --git a/apps/umami/files/compose.yaml b/apps/umami/files/compose.yaml new file mode 100644 index 0000000..ec29546 --- /dev/null +++ b/apps/umami/files/compose.yaml @@ -0,0 +1,24 @@ +services: + << service_name >>: + image: ghcr.io/umami-software/umami:postgresql-latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + - DATABASE_URL=postgresql://umami:<< db_password >>@<< service_name >>-db:5432/umami + - DATABASE_TYPE=postgresql + - APP_SECRET=<< app_secret >> + ports: + - "<< port >>:3000" + depends_on: + - << service_name >>-db + restart: unless-stopped + << service_name >>-db: + image: postgres:16-alpine + container_name: << service_name >>-db + environment: + - POSTGRES_DB=umami + - POSTGRES_USER=umami + - POSTGRES_PASSWORD=<< db_password >> + volumes: + - << appdata_dir >>/<< service_name >>-db:/var/lib/postgresql/data + restart: unless-stopped diff --git a/apps/umami/template.json b/apps/umami/template.json new file mode 100644 index 0000000..a6d304f --- /dev/null +++ b/apps/umami/template.json @@ -0,0 +1,83 @@ +{ + "kind": "compose", + "metadata": { + "name": "Umami", + "description": "Bezoekersstatistieken voor je websites zonder cookies en zonder persoonsgegevens. Lichtgewicht alternatief voor Google Analytics.", + "tags": [ + "analytics", + "bezoekers", + "privacy" + ], + "icon": { + "provider": "selfhst", + "id": "umami" + }, + "version": { + "name": "latest" + }, + "categories": [ + "analytics" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "umami", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8167, + "required": true, + "description": "Standaard 3000; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + }, + { + "title": "Toegang", + "items": [ + { + "name": "db_password", + "type": "str", + "title": "Databasewachtwoord", + "default": "", + "required": true, + "secret": true, + "generate": "auto", + "description": "Wordt automatisch ingevuld en in .env bewaard" + }, + { + "name": "app_secret", + "type": "str", + "title": "Geheime sleutel", + "default": "", + "required": true, + "secret": true, + "generate": "auto" + } + ] + } + ] +} diff --git a/apps/wallos/files/compose.yaml b/apps/wallos/files/compose.yaml new file mode 100644 index 0000000..c599cae --- /dev/null +++ b/apps/wallos/files/compose.yaml @@ -0,0 +1,12 @@ +services: + << service_name >>: + image: bellamy/wallos:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + volumes: + - << appdata_dir >>/<< service_name >>:/var/www/html/db + - << appdata_dir >>/<< service_name >>-logos:/var/www/html/images/uploads/logos + ports: + - "<< port >>:80" + restart: unless-stopped diff --git a/apps/wallos/template.json b/apps/wallos/template.json new file mode 100644 index 0000000..56a9c43 --- /dev/null +++ b/apps/wallos/template.json @@ -0,0 +1,60 @@ +{ + "kind": "compose", + "metadata": { + "name": "Wallos", + "description": "Houdt bij op welke abonnementen je zit, wat ze kosten en wanneer ze verlengen. Waarschuwt vóór de verlenging.", + "tags": [ + "abonnementen", + "kosten", + "financien" + ], + "icon": { + "provider": "selfhst", + "id": "wallos" + }, + "version": { + "name": "latest" + }, + "categories": [ + "financien", + "gezin" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "wallos", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8145, + "required": true, + "description": "Standaard 80; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + } + ] +} diff --git a/apps/wger/files/compose.yaml b/apps/wger/files/compose.yaml new file mode 100644 index 0000000..a601d6d --- /dev/null +++ b/apps/wger/files/compose.yaml @@ -0,0 +1,17 @@ +services: + << service_name >>: + image: wger/server:latest + container_name: << service_name >> + environment: + - SECRET_KEY=<< secret_key >> + - DJANGO_DB_ENGINE=django.db.backends.sqlite3 + - DJANGO_DB_DATABASE=/home/wger/media/db.sqlite3 + - TIME_ZONE=<< timezone >> + - ALLOW_REGISTRATION=False + - ALLOW_GUEST_USERS=False + - CSRF_TRUSTED_ORIGINS=<< app_url >> + volumes: + - << appdata_dir >>/<< service_name >>:/home/wger/media + ports: + - "<< port >>:8000" + restart: unless-stopped diff --git a/apps/wger/template.json b/apps/wger/template.json new file mode 100644 index 0000000..fa50043 --- /dev/null +++ b/apps/wger/template.json @@ -0,0 +1,85 @@ +{ + "kind": "compose", + "metadata": { + "name": "wger", + "description": "Trainingsschema's, gewicht en voeding bijhouden, met een oefeningendatabase die je zelf aanvult.", + "tags": [ + "fitness", + "gezondheid", + "training" + ], + "icon": { + "provider": "selfhst", + "id": "wger" + }, + "version": { + "name": "latest" + }, + "categories": [ + "gezin" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "wger", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8150, + "required": true, + "description": "Standaard 8000; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + }, + { + "title": "Instellingen", + "items": [ + { + "name": "app_url", + "type": "str", + "title": "Publiek adres", + "default": "http://localhost:8150", + "required": true + } + ] + }, + { + "title": "Toegang", + "items": [ + { + "name": "secret_key", + "type": "str", + "title": "Django-sleutel", + "default": "", + "required": true, + "secret": true, + "generate": "auto" + } + ] + } + ] +} diff --git a/apps/woodpecker/files/compose.yaml b/apps/woodpecker/files/compose.yaml new file mode 100644 index 0000000..7f5b2d1 --- /dev/null +++ b/apps/woodpecker/files/compose.yaml @@ -0,0 +1,31 @@ +services: + << service_name >>: + image: woodpeckerci/woodpecker-server:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + - WOODPECKER_OPEN=false + - WOODPECKER_HOST=<< host >> + - WOODPECKER_AGENT_SECRET=<< agent_secret >> + - WOODPECKER_FORGEJO=true + - WOODPECKER_FORGEJO_URL=<< forgejo_url >> + - WOODPECKER_FORGEJO_CLIENT=<< forgejo_client >> + - WOODPECKER_FORGEJO_SECRET=<< forgejo_secret >> + - WOODPECKER_ADMIN=<< beheerder >> + volumes: + - << appdata_dir >>/<< service_name >>:/var/lib/woodpecker + ports: + - "<< port >>:8000" + restart: unless-stopped + << service_name >>-agent: + image: woodpeckerci/woodpecker-agent:latest + container_name: << service_name >>-agent + command: agent + environment: + - WOODPECKER_SERVER=<< service_name >>:9000 + - WOODPECKER_AGENT_SECRET=<< agent_secret >> + volumes: + - /var/run/docker.sock:/var/run/docker.sock + depends_on: + - << service_name >> + restart: unless-stopped diff --git a/apps/woodpecker/template.json b/apps/woodpecker/template.json new file mode 100644 index 0000000..631cca9 --- /dev/null +++ b/apps/woodpecker/template.json @@ -0,0 +1,122 @@ +{ + "kind": "compose", + "metadata": { + "name": "Woodpecker CI", + "description": "Bouwserver die je pipelines uit de repo leest. Werkt samen met Forgejo, Gitea en GitHub.", + "tags": [ + "ci", + "bouwen", + "ontwikkeling" + ], + "icon": { + "provider": "selfhst", + "id": "woodpecker" + }, + "version": { + "name": "latest" + }, + "categories": [ + "ontwikkeling" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "woodpecker", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8162, + "required": true, + "description": "Standaard 8000; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + }, + { + "title": "Instellingen", + "items": [ + { + "name": "host", + "type": "str", + "title": "Publiek adres", + "default": "http://localhost:8162", + "required": true + }, + { + "name": "forgejo_url", + "type": "str", + "title": "Adres van Forgejo", + "default": "http://forgejo:3000", + "required": true, + "connect": { + "app": "forgejo", + "scheme": "http", + "port": 3000 + }, + "help": "Woodpecker logt in via je git-server. Maak daar een OAuth2-toepassing aan en neem client-id en secret hier over." + }, + { + "name": "forgejo_client", + "type": "str", + "title": "OAuth2 client-id", + "default": "", + "required": true + }, + { + "name": "beheerder", + "type": "str", + "title": "Beheerdersaccount", + "default": "", + "required": true, + "description": "Gebruikersnaam in Forgejo die beheerder wordt" + } + ] + }, + { + "title": "Toegang", + "items": [ + { + "name": "agent_secret", + "type": "str", + "title": "Sleutel tussen server en agent", + "default": "", + "required": true, + "secret": true, + "generate": "auto" + }, + { + "name": "forgejo_secret", + "type": "str", + "title": "OAuth2 client-secret", + "default": "", + "required": true, + "secret": true, + "eigen_invoer": true + } + ] + } + ] +} diff --git a/apps/zoraxy/files/compose.yaml b/apps/zoraxy/files/compose.yaml new file mode 100644 index 0000000..1f896f6 --- /dev/null +++ b/apps/zoraxy/files/compose.yaml @@ -0,0 +1,13 @@ +services: + << service_name >>: + image: zoraxydocker/zoraxy:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + volumes: + - << appdata_dir >>/<< service_name >>:/opt/zoraxy/config + ports: + - "<< port >>:8000" + - "<< port_http >>:80" + - "<< port_https >>:443" + restart: unless-stopped diff --git a/apps/zoraxy/template.json b/apps/zoraxy/template.json new file mode 100644 index 0000000..2c396b7 --- /dev/null +++ b/apps/zoraxy/template.json @@ -0,0 +1,74 @@ +{ + "kind": "compose", + "metadata": { + "name": "Zoraxy", + "description": "Reverse proxy met een webinterface in plaats van configuratiebestanden. Regelt zelf certificaten en heeft ingebouwde toegangsregels. Let op: Draai dit niet naast een andere reverse proxy op dezelfde poorten: 80 en 443 kunnen maar door één programma tegelijk gebruikt worden.", + "tags": [ + "proxy", + "https", + "netwerk", + "certificaten" + ], + "icon": { + "provider": "selfhst", + "id": "zoraxy" + }, + "version": { + "name": "latest" + }, + "categories": [ + "netwerk" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "zoraxy", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Beheerinterface", + "default": 8129, + "required": true, + "description": "Standaard 8000; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "port_http", + "type": "int", + "title": "HTTP", + "default": 80, + "required": true + }, + { + "name": "port_https", + "type": "int", + "title": "HTTPS", + "default": 443, + "required": true + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + } + ] +} diff --git a/docs/apps-maken.md b/docs/apps-maken.md index 098f612..7915c2c 100644 --- a/docs/apps-maken.md +++ b/docs/apps-maken.md @@ -356,6 +356,28 @@ delen; die staan in een allowlist in `tests/test_apps.py`. Een onderdeel van de ARR-stack mag dezelfde poort hebben als zijn losse sjabloon — dat is dezelfde container, alleen anders verpakt. +**Een app met een eigen database.** Zet de database als tweede service in +hetzelfde compose-bestand, met het voorvoegsel van de app ervoor: + +```yaml + << service_name >>-db: + image: postgres:16-alpine + container_name: << service_name >>-db + environment: + - POSTGRES_PASSWORD=<< db_password >> +``` + +Dat voorvoegsel is geen opmaak: installeer je de app twee keer, dan botsen de +containernamen zonder. Het wachtwoord is een veld met `"secret": true` en +`"generate": "auto"`, zodat het formulier het invult en de waarde in `.env` +belandt in plaats van in het compose-bestand. Vergeet `depends_on` niet, anders +start de app vóór zijn database en valt hij om op de eerste verbinding. + +**Een geheim dat je nergens vandaan kunt genereren** — het client-secret van een +OIDC-toepassing, een wachtwoord dat de gebruiker zelf kiest — markeer je met +`"eigen_invoer": true`. Anders klaagt de testsuite terecht dat er een verplicht +geheim zonder waarde en zonder generator in staat. + **De appdata-map heet `appdata_dir`, de gedeelde datamap `data_root`.** De eerste is de plek waar déze app zijn instellingen bewaart (`/config`), de tweede is de gedeelde berg met media en downloads die als `/data` in elke container komt. Zit diff --git a/server-up/core/boilerplates.py b/server-up/core/boilerplates.py index 4f9fff2..d7943cc 100644 --- a/server-up/core/boilerplates.py +++ b/server-up/core/boilerplates.py @@ -152,6 +152,11 @@ def fields(d: Path) -> list[dict]: # willekeurigs. "auto" = ook meteen invullen, True = alleen een # knop (voor wachtwoorden waarmee je zelf inlogt). "generate": item.get("generate") or "", + # Een geheim dat de gebruiker ergens anders vandaan haalt: het + # client-secret van een OIDC-toepassing, een wachtwoord dat hij + # zelf kiest. Daar valt niets voor te genereren, en het is geen + # vergeten instelling. + "eigen_invoer": bool(item.get("eigen_invoer")), # In welke stap van het invulmenu dit veld thuishoort. "step": _stap_van(item, toggle), # "username" of "password": wordt getoond in het paneel diff --git a/server-up/core/categories.py b/server-up/core/categories.py index 4312416..d969c74 100644 --- a/server-up/core/categories.py +++ b/server-up/core/categories.py @@ -26,6 +26,9 @@ CATEGORIES: dict[str, dict] = { "financien": {"nl": "Financiën", "en": "Finance", "color": "#10b981", "icon": "mdi-cash-multiple"}, "gezin": {"nl": "Gezin & huishouden", "en": "Family & home", "color": "#f472b6", "icon": "mdi-home-heart"}, "monitoring": {"nl": "Monitoring", "en": "Monitoring", "color": "#f97316", "icon": "mdi-chart-line"}, + "analytics": {"nl": "Statistiek", "en": "Analytics", "color": "#d946ef", "icon": "mdi-chart-box-outline"}, + "zakelijk": {"nl": "Zakelijk", "en": "Business", "color": "#0d9488", "icon": "mdi-briefcase-outline"}, + "spellen": {"nl": "Spellen", "en": "Games", "color": "#e11d48", "icon": "mdi-gamepad-variant-outline"}, "ontwikkeling": {"nl": "Ontwikkeling", "en": "Development", "color": "#06b6d4", "icon": "mdi-code-braces"}, "ai": {"nl": "AI", "en": "AI", "color": "#a855f7", "icon": "mdi-brain"}, "beheer": {"nl": "Systeembeheer", "en": "System management", "color": "#64748b", "icon": "mdi-cog-outline"}, @@ -54,8 +57,12 @@ _TREFWOORDEN: list[tuple[tuple[str, ...], str]] = [ (("meldingen", "push", "chat", "communicatie", "e-mail"), "communicatie"), (("financien", "budget", "administratie"), "financien"), (("gezin", "huishouden", "recepten", "voorraad", "gezondheid", "logboek"), "gezin"), - (("monitoring", "metrics", "systeem", "dashboard", "statistiek", + (("monitoring", "metrics", "systeem", "dashboard", "realtime", "rapportage"), "monitoring"), + (("analytics", "bezoekers", "webstatistiek", "statistiek"), "analytics"), + (("crm", "helpdesk", "tickets", "facturen", "boekhouding", "assetbeheer", + "voorraadbeheer", "klanten"), "zakelijk"), + (("spellen", "games", "retro", "emulator", "gameserver", "minecraft"), "spellen"), (("git", "ontwikkelaar", "code", "ci", "database", "spreadsheet", "no-code", "encoding"), "ontwikkeling"), (("ai", "llm", "machine-learning"), "ai"), diff --git a/tests/test_app_templates.py b/tests/test_app_templates.py index e79275e..be28005 100644 --- a/tests/test_app_templates.py +++ b/tests/test_app_templates.py @@ -92,9 +92,13 @@ def test_geen_velden_die_nergens_gebruikt_worden(app): gebruikt |= set(VAR_RE.findall(ruw)) for blok in BLOK_RE.findall(ruw): gebruikt |= set(re.findall(r"[a-zA-Z_][a-zA-Z0-9_]*", blok)) - # Ook andere bestanden in files/ mogen variabelen gebruiken. + # Ook andere bestanden in files/ mogen variabelen gebruiken — inclusief + # YAML dat geen compose is, zoals de config.yaml die Headscale en Gatus + # meekrijgen. Die vielen eerder tussen wal en schip: niet gescand als + # compose, en overgeslagen omdat ze op .yaml eindigen. + composes = set(_compose_bestanden(app)) for p in (app / "files").rglob("*"): - if p.is_file() and p.suffix not in (".yaml", ".yml"): + if p.is_file() and p not in composes: try: gebruikt |= set(VAR_RE.findall(p.read_text(encoding="utf-8"))) except (UnicodeDecodeError, OSError): @@ -211,7 +215,8 @@ def test_verplichte_geheimen_zijn_invulbaar_of_worden_gegenereerd(app): worden, óf iets zijn dat de gebruiker zelf aanlevert. Wat overblijft is een veld waar niemand een geldige waarde voor kan verzinnen.""" # Wachtwoorden waarmee je zelf inlogt en tokens die je elders ophaalt vult - # de gebruiker bewust zelf in. + # de gebruiker bewust zelf in. Nieuwe sjablonen zeggen dat met + # `"eigen_invoer": true`; de namen hieronder zijn van vóór die vlag. eigen_invoer = ("admin_password", "web_password", "ui_password", "superuser_password", "password_hash", "hass_token", "forgejo_token", "adminpass") @@ -220,6 +225,8 @@ def test_verplichte_geheimen_zijn_invulbaar_of_worden_gegenereerd(app): continue if str(f.get("default") or "").strip(): continue + if f.get("eigen_invoer"): + continue # Een API-sleutel komt per definitie uit de app waar je naartoe wijst; # die kun je hier niet verzinnen, alleen overtypen. if f["name"].endswith(("_apikey", "_api_key")): diff --git a/tests/test_apps.py b/tests/test_apps.py index 53bce5f..576f009 100644 --- a/tests/test_apps.py +++ b/tests/test_apps.py @@ -32,7 +32,7 @@ def _render(d: Path, tmp: Path) -> dict: def test_er_zijn_apps(): - assert len(APPS) >= 60 + assert len(APPS) >= 190 @pytest.mark.parametrize("app", APPS, ids=NAMEN) @@ -86,11 +86,74 @@ def test_geen_onvervangen_variabelen(app): assert "<<" not in tekst and ">>" not in tekst, "onvervangen variabele" +# ── Apps die hun eigen database meebrengen ─────────────────────────────────── + +_DATABASE_IMAGES = ("postgres", "postgis", "mariadb", "mysql", "mongo", + "redis", "valkey") + + +def _bron(app: Path) -> str: + return (app / "files" / "compose.yaml").read_text(encoding="utf-8") + + +@pytest.mark.parametrize("app", APPS, ids=NAMEN) +def test_extra_containers_dragen_de_servicenaam(app): + """Een tweede container moet `-…` heten. + + De instantienaam is het enige wat een gebruiker kiest als hij een app twee + keer installeert. Heet de database dan gewoon `db`, dan botsen de twee + installaties op de containernaam en start de tweede niet. + """ + snaam = next((f.get("default") for f in bp.fields(app) + if f["name"] == "service_name"), None) or app.name + with tempfile.TemporaryDirectory() as t: + doc = _render(app, Path(t)) + for naam in doc["services"]: + assert naam == snaam or naam.startswith(f"{snaam}-"), \ + f"'{naam}' draagt de servicenaam '{snaam}' niet" + + +@pytest.mark.parametrize("app", APPS, ids=NAMEN) +def test_bijgeleverde_database_heeft_geen_vast_wachtwoord(app): + """Een database met een wachtwoord dat in het sjabloon staat, heeft bij + iedereen hetzelfde wachtwoord. Dat is geen wachtwoord.""" + ruw = _bron(app) + heeft_db = any(f"image: {i}" in ruw for i in _DATABASE_IMAGES) + if not heeft_db: + return + for regel in ruw.splitlines(): + r = regel.strip() + if not any(r.startswith(f"- {k}") for k in + ("POSTGRES_PASSWORD", "MARIADB_PASSWORD", "MARIADB_ROOT_PASSWORD", + "MYSQL_PASSWORD", "MYSQL_ROOT_PASSWORD", + "MONGO_INITDB_ROOT_PASSWORD")): + continue + waarde = r.split("=", 1)[1] if "=" in r else "" + assert "<<" in waarde, f"vast databasewachtwoord: {r}" + + +@pytest.mark.parametrize("app", APPS, ids=NAMEN) +def test_bijgeleverde_database_wordt_afgewacht(app): + """Zonder depends_on start de app vóór zijn database en valt hij om op de + eerste verbinding.""" + with tempfile.TemporaryDirectory() as t: + doc = _render(app, Path(t)) + diensten = doc["services"] + dbs = {n for n, s in diensten.items() + if isinstance(s, dict) + and any(str(s.get("image", "")).startswith(i) for i in _DATABASE_IMAGES)} + if not dbs: + return + wacht = {d for s in diensten.values() if isinstance(s, dict) + for d in (s.get("depends_on") or [])} + assert dbs <= wacht, f"niemand wacht op {sorted(dbs - wacht)}" + + # Poorten die meerdere apps bewust delen: alternatieven voor dezelfde taak, # die je nooit tegelijk draait. Alles daarbuiten hoort uniek te zijn. GEDEELDE_POORTEN = { - 80: {"nginx-proxy-manager", "traefik", "caddy"}, # reverse proxies - 443: {"nginx-proxy-manager", "traefik", "caddy"}, + 80: {"nginx-proxy-manager", "traefik", "caddy", "zoraxy"}, # reverse proxies + 443: {"nginx-proxy-manager", "traefik", "caddy", "zoraxy"}, 53: {"adguard-home", "pihole"}, # dns-blokkers # Hieronder: botsingen die er al waren vóór deze testsuite. De # vrije-poortsuggestie bij installeren vangt ze op, dus ze zijn hinderlijk