- CSRF: HMAC-signed double-submit cookie (server-bound, not raw compare)
- Keychain: execFileSync with arg arrays to prevent command injection
- Caddy config: always use structured generation, never accept raw config
- Templates: replace {{GENERATED_SECRET}} with crypto.randomBytes
- Caddyfile removal: move regex inside ctx.caddy.modify() to fix TOCTOU race
- Credentials: proper-lockfile for all file operations, fix key rotation
to decrypt with old key before generating new key
- Service removal: filter by ID only, not AND with appTemplate
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2497 lines
67 KiB
JavaScript
2497 lines
67 KiB
JavaScript
// SAMI-CLOUD App Templates Database
|
|
// Pre-configured Docker applications for one-click deployment
|
|
|
|
const APP_TEMPLATES = {
|
|
// === MEDIA & ENTERTAINMENT ===
|
|
"plex": {
|
|
name: "Plex",
|
|
description: "Stream your personal media collection anywhere",
|
|
icon: "🎬",
|
|
logo: "/assets/plex.png",
|
|
category: "Media",
|
|
popularity: 95,
|
|
difficulty: "Easy",
|
|
docker: {
|
|
image: "plexinc/pms-docker:latest",
|
|
ports: ["{{PORT}}:32400"],
|
|
volumes: [
|
|
"/opt/plex/config:/config",
|
|
"/opt/plex/transcode:/transcode",
|
|
"{{MEDIA_PATH}}:/data"
|
|
],
|
|
environment: {
|
|
"PLEX_CLAIM": "",
|
|
"ADVERTISE_IP": "http://{{HOST_IP}}:{{PORT}}/",
|
|
"PLEX_UID": "1000",
|
|
"PLEX_GID": "1000"
|
|
}
|
|
},
|
|
subdomain: "plex",
|
|
defaultPort: 32400,
|
|
healthCheck: "/web/index.html",
|
|
subpathSupport: 'none',
|
|
mediaMount: {
|
|
required: true,
|
|
containerPath: "/data",
|
|
label: "Media Library",
|
|
description: "Folder containing your movies, TV shows, music, etc.",
|
|
defaultPath: "/media"
|
|
},
|
|
claimToken: {
|
|
envVar: "PLEX_CLAIM",
|
|
label: "Plex Claim Token",
|
|
description: "Get from https://plex.tv/claim - expires in 4 minutes!",
|
|
placeholder: "claim-xxxxxxxxxxxxxxxxxxxx",
|
|
helpUrl: "https://plex.tv/claim"
|
|
},
|
|
setupInstructions: [
|
|
"Get your claim token from https://plex.tv/claim",
|
|
"Add your media libraries in the web interface",
|
|
"Configure remote access settings"
|
|
],
|
|
requiredVolumes: ["config", "media"],
|
|
optionalVolumes: ["transcode"]
|
|
},
|
|
|
|
"jellyfin": {
|
|
name: "Jellyfin",
|
|
description: "Free software media system - alternative to Plex",
|
|
icon: "🍿",
|
|
logo: "/assets/jellyfin.png",
|
|
category: "Media",
|
|
popularity: 88,
|
|
difficulty: "Easy",
|
|
docker: {
|
|
image: "jellyfin/jellyfin:latest",
|
|
ports: ["{{PORT}}:8096"],
|
|
volumes: [
|
|
"/opt/jellyfin/config:/config",
|
|
"/opt/jellyfin/cache:/cache",
|
|
"{{MEDIA_PATH}}:/media"
|
|
],
|
|
environment: {
|
|
"JELLYFIN_PublishedServerUrl": "https://{{SUBDOMAIN}}.sami"
|
|
}
|
|
},
|
|
subdomain: "jellyfin",
|
|
defaultPort: 8096,
|
|
healthCheck: "/health",
|
|
subpathSupport: 'native',
|
|
urlBaseEnv: 'JELLYFIN_BaseUrl',
|
|
mediaMount: {
|
|
required: true,
|
|
containerPath: "/media",
|
|
label: "Media Library",
|
|
description: "Folder containing your movies, TV shows, music, etc.",
|
|
defaultPath: "/media"
|
|
},
|
|
setupInstructions: [
|
|
"Complete the initial setup wizard",
|
|
"Add your media libraries",
|
|
"Configure user accounts and permissions"
|
|
]
|
|
},
|
|
|
|
"emby": {
|
|
name: "Emby",
|
|
description: "Personal media server with apps for all devices",
|
|
icon: "🎥",
|
|
logo: "/assets/emby.png",
|
|
category: "Media",
|
|
popularity: 85,
|
|
difficulty: "Easy",
|
|
docker: {
|
|
image: "emby/embyserver:latest",
|
|
ports: ["{{PORT}}:8096"],
|
|
volumes: [
|
|
"/opt/emby/config:/config",
|
|
"/opt/emby/cache:/cache",
|
|
"{{MEDIA_PATH}}:/media"
|
|
],
|
|
environment: {
|
|
"UID": "1000",
|
|
"GID": "1000"
|
|
}
|
|
},
|
|
subdomain: "emby",
|
|
defaultPort: 8096,
|
|
healthCheck: "/emby/web/",
|
|
subpathSupport: 'none',
|
|
mediaMount: {
|
|
required: true,
|
|
containerPath: "/media",
|
|
label: "Media Library",
|
|
description: "Folder containing your movies, TV shows, music, etc.",
|
|
defaultPath: "/media"
|
|
},
|
|
setupInstructions: [
|
|
"Complete the initial setup wizard at the web interface",
|
|
"Add your media libraries (Movies, TV Shows, Music)",
|
|
"Configure user accounts and permissions",
|
|
"Install Emby apps on your devices for remote access"
|
|
]
|
|
},
|
|
|
|
"sonarr": {
|
|
name: "Sonarr",
|
|
description: "Smart PVR for newsgroup and bittorrent users",
|
|
icon: "📺",
|
|
category: "Media Management",
|
|
popularity: 82,
|
|
difficulty: "Intermediate",
|
|
docker: {
|
|
image: "linuxserver/sonarr:latest",
|
|
ports: ["{{PORT}}:8989"],
|
|
volumes: [
|
|
"/opt/sonarr/config:/config",
|
|
"/downloads:/downloads",
|
|
"/tv:/tv"
|
|
],
|
|
environment: {
|
|
"PUID": "1000",
|
|
"PGID": "1000",
|
|
"TZ": "{{TIMEZONE}}"
|
|
}
|
|
},
|
|
subdomain: "sonarr",
|
|
defaultPort: 8989,
|
|
healthCheck: "/api/v3/system/status",
|
|
subpathSupport: 'native',
|
|
urlBaseEnv: 'URL_BASE',
|
|
setupInstructions: [
|
|
"Configure download clients (qBittorrent, etc.)",
|
|
"Add indexers for content discovery",
|
|
"Set up root folders for TV shows"
|
|
]
|
|
},
|
|
|
|
"radarr": {
|
|
name: "Radarr",
|
|
description: "Movie collection manager for Usenet and BitTorrent",
|
|
icon: "🎭",
|
|
category: "Media Management",
|
|
popularity: 80,
|
|
difficulty: "Intermediate",
|
|
docker: {
|
|
image: "linuxserver/radarr:latest",
|
|
ports: ["{{PORT}}:7878"],
|
|
volumes: [
|
|
"/opt/radarr/config:/config",
|
|
"/downloads:/downloads",
|
|
"/movies:/movies"
|
|
],
|
|
environment: {
|
|
"PUID": "1000",
|
|
"PGID": "1000",
|
|
"TZ": "{{TIMEZONE}}"
|
|
}
|
|
},
|
|
subdomain: "radarr",
|
|
defaultPort: 7878,
|
|
healthCheck: "/api/v3/system/status",
|
|
subpathSupport: 'native',
|
|
urlBaseEnv: 'URL_BASE'
|
|
},
|
|
|
|
"prowlarr": {
|
|
name: "Prowlarr",
|
|
description: "Indexer manager/proxy for *arr applications",
|
|
icon: "🔍",
|
|
category: "Media Management",
|
|
popularity: 75,
|
|
difficulty: "Advanced",
|
|
docker: {
|
|
image: "linuxserver/prowlarr:latest",
|
|
ports: ["{{PORT}}:9696"],
|
|
volumes: ["/opt/prowlarr/config:/config"],
|
|
environment: {
|
|
"PUID": "1000",
|
|
"PGID": "1000",
|
|
"TZ": "{{TIMEZONE}}"
|
|
}
|
|
},
|
|
subdomain: "prowlarr",
|
|
defaultPort: 9696,
|
|
healthCheck: "/api/v1/system/status",
|
|
subpathSupport: 'native',
|
|
urlBaseEnv: 'URL_BASE'
|
|
},
|
|
|
|
"qbittorrent": {
|
|
name: "qBittorrent",
|
|
description: "Lightweight BitTorrent client with web UI",
|
|
icon: "⬇️",
|
|
category: "Downloads",
|
|
popularity: 90,
|
|
difficulty: "Easy",
|
|
docker: {
|
|
image: "linuxserver/qbittorrent:latest",
|
|
ports: ["{{PORT}}:8080", "6881:6881", "6881:6881/udp"],
|
|
volumes: [
|
|
"/opt/qbittorrent/config:/config",
|
|
"/downloads:/downloads"
|
|
],
|
|
environment: {
|
|
"PUID": "1000",
|
|
"PGID": "1000",
|
|
"TZ": "{{TIMEZONE}}",
|
|
"WEBUI_PORT": "8080"
|
|
}
|
|
},
|
|
subdomain: "torrent",
|
|
defaultPort: 8080,
|
|
healthCheck: "/",
|
|
subpathSupport: 'native',
|
|
urlBaseEnv: 'WEBUI_BASE_PATH',
|
|
setupInstructions: [
|
|
"Default login: admin/adminadmin",
|
|
"Change default password immediately",
|
|
"Configure download paths"
|
|
]
|
|
},
|
|
|
|
// === PRODUCTIVITY & TOOLS ===
|
|
"nextcloud": {
|
|
name: "Nextcloud",
|
|
description: "Self-hosted productivity platform and file sync",
|
|
icon: "☁️",
|
|
category: "Productivity",
|
|
popularity: 92,
|
|
difficulty: "Intermediate",
|
|
docker: {
|
|
image: "nextcloud:latest",
|
|
ports: ["{{PORT}}:80"],
|
|
volumes: [
|
|
"/opt/nextcloud/html:/var/www/html",
|
|
"/opt/nextcloud/data:/var/www/html/data"
|
|
],
|
|
environment: {
|
|
"NEXTCLOUD_ADMIN_USER": "admin",
|
|
"NEXTCLOUD_ADMIN_PASSWORD": "{{NEXTCLOUD_ADMIN_PASSWORD}}",
|
|
"NEXTCLOUD_TRUSTED_DOMAINS": "{{SUBDOMAIN}}.sami"
|
|
}
|
|
},
|
|
subdomain: "cloud",
|
|
defaultPort: 8080,
|
|
healthCheck: "/status.php",
|
|
subpathSupport: 'none',
|
|
setupInstructions: [
|
|
"Change the default admin password",
|
|
"Configure trusted domains",
|
|
"Install recommended apps"
|
|
],
|
|
secrets: [
|
|
{
|
|
envVar: "NEXTCLOUD_ADMIN_PASSWORD",
|
|
label: "Admin Password",
|
|
description: "Secure password for Nextcloud admin account",
|
|
type: "password",
|
|
required: true,
|
|
generate: "alphanumeric",
|
|
length: 32
|
|
}
|
|
]
|
|
},
|
|
|
|
"vscode-server": {
|
|
name: "VS Code Server",
|
|
description: "Visual Studio Code in your browser",
|
|
icon: "💻",
|
|
category: "Development",
|
|
popularity: 85,
|
|
difficulty: "Easy",
|
|
docker: {
|
|
image: "codercom/code-server:latest",
|
|
ports: ["{{PORT}}:8080"],
|
|
volumes: [
|
|
"/opt/vscode/config:/home/coder/.config",
|
|
"/opt/vscode/projects:/home/coder/projects"
|
|
],
|
|
environment: {
|
|
"PASSWORD": "{{VSCODE_PASSWORD}}"
|
|
}
|
|
},
|
|
subdomain: "code",
|
|
defaultPort: 8443,
|
|
healthCheck: "/healthz",
|
|
subpathSupport: 'strip',
|
|
secrets: [
|
|
{
|
|
envVar: "VSCODE_PASSWORD",
|
|
label: "Access Password",
|
|
description: "Password to access VS Code Server web interface",
|
|
type: "password",
|
|
required: true,
|
|
generate: "alphanumeric",
|
|
length: 24
|
|
}
|
|
]
|
|
},
|
|
|
|
// === MONITORING & ADMIN ===
|
|
"portainer": {
|
|
name: "Portainer",
|
|
description: "Docker container management UI",
|
|
icon: "🐳",
|
|
category: "Management",
|
|
popularity: 88,
|
|
difficulty: "Easy",
|
|
docker: {
|
|
image: "portainer/portainer-ce:latest",
|
|
ports: ["{{PORT}}:9000"],
|
|
volumes: [
|
|
"/var/run/docker.sock:/var/run/docker.sock",
|
|
"/opt/portainer/data:/data"
|
|
]
|
|
},
|
|
subdomain: "portainer",
|
|
defaultPort: 9000,
|
|
healthCheck: "/api/status",
|
|
subpathSupport: 'strip'
|
|
},
|
|
|
|
"grafana": {
|
|
name: "Grafana",
|
|
description: "Analytics and interactive visualization platform",
|
|
icon: "📊",
|
|
category: "Monitoring",
|
|
popularity: 78,
|
|
difficulty: "Advanced",
|
|
docker: {
|
|
image: "grafana/grafana:latest",
|
|
ports: ["{{PORT}}:3000"],
|
|
volumes: ["/opt/grafana/data:/var/lib/grafana"],
|
|
environment: {
|
|
"GF_SECURITY_ADMIN_PASSWORD": "{{GRAFANA_ADMIN_PASSWORD}}"
|
|
}
|
|
},
|
|
subdomain: "grafana",
|
|
defaultPort: 3000,
|
|
healthCheck: "/api/health",
|
|
subpathSupport: 'native',
|
|
urlBaseEnv: 'GF_SERVER_ROOT_URL',
|
|
secrets: [
|
|
{
|
|
envVar: "GRAFANA_ADMIN_PASSWORD",
|
|
label: "Admin Password",
|
|
description: "Password for Grafana admin user",
|
|
type: "password",
|
|
required: true,
|
|
generate: "alphanumeric",
|
|
length: 32
|
|
}
|
|
]
|
|
},
|
|
|
|
"uptime-kuma": {
|
|
name: "Uptime Kuma",
|
|
description: "Self-hosted monitoring tool like Uptime Robot",
|
|
icon: "📈",
|
|
category: "Monitoring",
|
|
popularity: 82,
|
|
difficulty: "Easy",
|
|
docker: {
|
|
image: "louislam/uptime-kuma:latest",
|
|
ports: ["{{PORT}}:3001"],
|
|
volumes: ["/opt/uptime-kuma:/app/data"]
|
|
},
|
|
subdomain: "uptime",
|
|
defaultPort: 3002,
|
|
healthCheck: "/",
|
|
subpathSupport: 'strip'
|
|
},
|
|
|
|
// === NETWORKING & SECURITY ===
|
|
"pihole": {
|
|
name: "Pi-hole",
|
|
description: "Network-wide ad blocker and DNS sinkhole",
|
|
icon: "🛡️",
|
|
category: "Networking",
|
|
popularity: 90,
|
|
difficulty: "Intermediate",
|
|
docker: {
|
|
image: "pihole/pihole:latest",
|
|
ports: ["{{PORT}}:80", "53:53", "53:53/udp"],
|
|
volumes: [
|
|
"/opt/pihole/etc:/etc/pihole",
|
|
"/opt/pihole/dnsmasq:/etc/dnsmasq.d"
|
|
],
|
|
environment: {
|
|
"WEBPASSWORD": "{{PIHOLE_WEB_PASSWORD}}",
|
|
"TZ": "{{TIMEZONE}}"
|
|
}
|
|
},
|
|
subdomain: "pihole",
|
|
defaultPort: 80,
|
|
healthCheck: "/admin/",
|
|
subpathSupport: 'strip',
|
|
secrets: [
|
|
{
|
|
envVar: "PIHOLE_WEB_PASSWORD",
|
|
label: "Web Interface Password",
|
|
description: "Password for Pi-hole admin web interface",
|
|
type: "password",
|
|
required: true,
|
|
generate: "alphanumeric",
|
|
length: 24
|
|
}
|
|
]
|
|
},
|
|
|
|
"wireguard": {
|
|
name: "WireGuard VPN",
|
|
description: "Fast, modern, secure VPN tunnel",
|
|
icon: "🔒",
|
|
category: "Networking",
|
|
popularity: 75,
|
|
difficulty: "Advanced",
|
|
docker: {
|
|
image: "linuxserver/wireguard:latest",
|
|
ports: ["{{PORT}}:51820/udp"],
|
|
volumes: ["/opt/wireguard/config:/config"],
|
|
environment: {
|
|
"PUID": "1000",
|
|
"PGID": "1000",
|
|
"TZ": "{{TIMEZONE}}",
|
|
"SERVERURL": "{{HOST_IP}}",
|
|
"SERVERPORT": "{{PORT}}",
|
|
"PEERS": "1"
|
|
},
|
|
capabilities: ["NET_ADMIN", "SYS_MODULE"]
|
|
},
|
|
subdomain: "vpn",
|
|
defaultPort: 51820,
|
|
healthCheck: "/",
|
|
subpathSupport: 'strip',
|
|
setupInstructions: [
|
|
"Configure your external IP/domain",
|
|
"Set up port forwarding on router",
|
|
"Download client configs from /config/peer1/"
|
|
]
|
|
},
|
|
|
|
// === DNS SERVERS ===
|
|
"technitium": {
|
|
name: "Technitium DNS Server",
|
|
description: "Modern DNS server with web UI for managing private zones",
|
|
icon: "🌐",
|
|
category: "DNS",
|
|
popularity: 85,
|
|
difficulty: "Easy",
|
|
features: [
|
|
"Web-based management interface",
|
|
"Private zone management for .sami domain",
|
|
"DHCP server integration",
|
|
"DNS-over-HTTPS and DNS-over-TLS support",
|
|
"Built-in DNSSEC support"
|
|
],
|
|
docker: {
|
|
image: "technitium/dns-server:latest",
|
|
ports: ["{{PORT}}:5380", "53:53", "53:53/udp"],
|
|
volumes: ["/opt/technitium/config:/etc/dns"],
|
|
environment: {
|
|
"DNS_SERVER_DOMAIN": "dns1.sami",
|
|
"DNS_SERVER_ADMIN_PASSWORD": "{{DNS_ADMIN_PASSWORD}}"
|
|
}
|
|
},
|
|
subdomain: "dns1",
|
|
defaultPort: 5380,
|
|
healthCheck: "/",
|
|
subpathSupport: 'strip',
|
|
setupInstructions: [
|
|
"Access web interface at https://dns1.sami",
|
|
"Login with admin credentials",
|
|
"Create a primary zone for 'sami' domain",
|
|
"Add A records for your services (e.g., plex.sami -> 192.168.1.100)",
|
|
"Configure your devices to use this DNS server"
|
|
],
|
|
requiredVolumes: ["config"],
|
|
optionalVolumes: [],
|
|
secrets: [
|
|
{
|
|
envVar: "DNS_ADMIN_PASSWORD",
|
|
label: "Admin Password",
|
|
description: "Password for Technitium DNS admin account",
|
|
type: "password",
|
|
required: true,
|
|
generate: "alphanumeric",
|
|
length: 32
|
|
}
|
|
]
|
|
},
|
|
|
|
"bind9": {
|
|
name: "BIND9 DNS Server",
|
|
description: "Industry-standard DNS server - powerful and flexible",
|
|
icon: "🔧",
|
|
category: "DNS",
|
|
popularity: 80,
|
|
difficulty: "Advanced",
|
|
features: [
|
|
"Industry standard DNS server",
|
|
"Full RFC compliance",
|
|
"Advanced zone management",
|
|
"DNSSEC support",
|
|
"High performance and reliability"
|
|
],
|
|
docker: {
|
|
image: "ubuntu/bind9:latest",
|
|
ports: ["53:53", "53:53/udp", "{{PORT}}:953"],
|
|
volumes: [
|
|
"/opt/bind9/config:/etc/bind",
|
|
"/opt/bind9/cache:/var/cache/bind",
|
|
"/opt/bind9/records:/var/lib/bind"
|
|
],
|
|
environment: {
|
|
"BIND9_USER": "root",
|
|
"TZ": "{{TIMEZONE}}"
|
|
}
|
|
},
|
|
subdomain: "dns2",
|
|
defaultPort: 953,
|
|
healthCheck: null,
|
|
subpathSupport: 'strip',
|
|
setupInstructions: [
|
|
"Configure zone files in /opt/bind9/config/",
|
|
"Create named.conf.local for your .sami zone",
|
|
"Add zone file: /opt/bind9/records/db.sami",
|
|
"Restart container to apply changes",
|
|
"Test with: dig @localhost sami"
|
|
],
|
|
requiredVolumes: ["config", "records"],
|
|
optionalVolumes: ["cache"]
|
|
},
|
|
|
|
"powerdns": {
|
|
name: "PowerDNS",
|
|
description: "High-performance DNS server with SQL backend",
|
|
icon: "⚡",
|
|
category: "DNS",
|
|
popularity: 75,
|
|
difficulty: "Intermediate",
|
|
features: [
|
|
"SQL database backend (MySQL/PostgreSQL)",
|
|
"RESTful API for automation",
|
|
"PowerDNS Admin web interface available",
|
|
"Geographic load balancing",
|
|
"DNSSEC support"
|
|
],
|
|
docker: {
|
|
image: "pschiffe/pdns-mysql:latest",
|
|
ports: ["53:53", "53:53/udp", "{{PORT}}:8081"],
|
|
volumes: ["/opt/powerdns/data:/var/lib/mysql"],
|
|
environment: {
|
|
"PDNS_api": "yes",
|
|
"PDNS_api_key": "{{POWERDNS_API_KEY}}",
|
|
"PDNS_webserver": "yes",
|
|
"PDNS_webserver_address": "0.0.0.0",
|
|
"PDNS_webserver_allow_from": "0.0.0.0/0",
|
|
"MYSQL_ROOT_PASSWORD": "{{MYSQL_ROOT_PASSWORD}}"
|
|
}
|
|
},
|
|
subdomain: "dns3",
|
|
defaultPort: 8081,
|
|
healthCheck: "/api/v1/servers",
|
|
subpathSupport: 'strip',
|
|
setupInstructions: [
|
|
"Access API at https://dns3.sami:8081",
|
|
"Use API key for authentication",
|
|
"Create zone via API or PowerDNS Admin",
|
|
"Add records for your .sami domain",
|
|
"Configure devices to use DNS server"
|
|
],
|
|
requiredVolumes: ["data"],
|
|
optionalVolumes: [],
|
|
secrets: [
|
|
{
|
|
envVar: "POWERDNS_API_KEY",
|
|
label: "API Key",
|
|
description: "API key for PowerDNS webserver authentication",
|
|
type: "password",
|
|
required: true,
|
|
generate: "alphanumeric",
|
|
length: 32
|
|
},
|
|
{
|
|
envVar: "MYSQL_ROOT_PASSWORD",
|
|
label: "MySQL Root Password",
|
|
description: "Root password for embedded MySQL database",
|
|
type: "password",
|
|
required: true,
|
|
generate: "alphanumeric",
|
|
length: 32
|
|
}
|
|
]
|
|
},
|
|
|
|
"coredns": {
|
|
name: "CoreDNS",
|
|
description: "Cloud-native DNS server - lightweight and flexible",
|
|
icon: "☁️",
|
|
category: "DNS",
|
|
popularity: 70,
|
|
difficulty: "Intermediate",
|
|
features: [
|
|
"Plugin-based architecture",
|
|
"Kubernetes-native (used in K8s)",
|
|
"Lightweight and fast",
|
|
"Prometheus metrics",
|
|
"Easy configuration via Corefile"
|
|
],
|
|
docker: {
|
|
image: "coredns/coredns:latest",
|
|
ports: ["53:53", "53:53/udp"],
|
|
volumes: ["/opt/coredns/config:/etc/coredns"],
|
|
environment: {},
|
|
command: ["-conf", "/etc/coredns/Corefile"]
|
|
},
|
|
subdomain: "dns4",
|
|
defaultPort: 53,
|
|
healthCheck: null,
|
|
subpathSupport: 'strip',
|
|
setupInstructions: [
|
|
"Create Corefile in /opt/coredns/config/",
|
|
"Define .sami zone with file plugin",
|
|
"Create zone file with your records",
|
|
"Restart container to load config",
|
|
"Test with: dig @localhost test.sami"
|
|
],
|
|
requiredVolumes: ["config"],
|
|
optionalVolumes: []
|
|
},
|
|
|
|
// === FILE MANAGEMENT ===
|
|
"filebrowser": {
|
|
name: "FileBrowser",
|
|
description: "Web-based file manager with sharing capabilities",
|
|
icon: "📁",
|
|
category: "Files",
|
|
popularity: 88,
|
|
difficulty: "Easy",
|
|
docker: {
|
|
image: "filebrowser/filebrowser:latest",
|
|
ports: ["{{PORT}}:80"],
|
|
volumes: [
|
|
"E:/docker-progs/filebrowser/data:/srv",
|
|
"E:/docker-progs/filebrowser/database:/database"
|
|
],
|
|
environment: {}
|
|
},
|
|
subdomain: "files",
|
|
defaultPort: 8085,
|
|
healthCheck: "/",
|
|
subpathSupport: 'strip',
|
|
setupInstructions: [
|
|
"Default login: admin/admin",
|
|
"Change default password immediately",
|
|
"Configure user permissions and shares"
|
|
]
|
|
},
|
|
|
|
"syncthing": {
|
|
name: "Syncthing",
|
|
description: "Continuous file synchronization between devices",
|
|
icon: "🔄",
|
|
category: "Files",
|
|
popularity: 85,
|
|
difficulty: "Easy",
|
|
docker: {
|
|
image: "linuxserver/syncthing:latest",
|
|
ports: ["{{PORT}}:8384", "22000:22000", "21027:21027/udp"],
|
|
volumes: [
|
|
"/opt/syncthing/config:/config",
|
|
"/opt/syncthing/data:/data"
|
|
],
|
|
environment: {
|
|
"PUID": "1000",
|
|
"PGID": "1000",
|
|
"TZ": "{{TIMEZONE}}"
|
|
}
|
|
},
|
|
subdomain: "sync",
|
|
defaultPort: 8384,
|
|
healthCheck: "/",
|
|
subpathSupport: 'strip',
|
|
setupInstructions: [
|
|
"Add devices using their Device IDs",
|
|
"Configure shared folders",
|
|
"Set up folder synchronization"
|
|
]
|
|
},
|
|
|
|
// === COMMUNICATION & EMAIL ===
|
|
"mailserver": {
|
|
name: "Docker Mailserver",
|
|
description: "Full-featured email server with SMTP, IMAP, spam filtering",
|
|
icon: "📧",
|
|
category: "Communication",
|
|
popularity: 70,
|
|
difficulty: "Advanced",
|
|
docker: {
|
|
image: "mailserver/docker-mailserver:latest",
|
|
ports: ["{{PORT}}:25", "143:143", "587:587", "993:993"],
|
|
volumes: [
|
|
"/opt/mailserver/data:/var/mail",
|
|
"/opt/mailserver/state:/var/mail-state",
|
|
"/opt/mailserver/logs:/var/log/mail",
|
|
"/opt/mailserver/config:/tmp/docker-mailserver"
|
|
],
|
|
environment: {
|
|
"ENABLE_SPAMASSASSIN": "1",
|
|
"ENABLE_CLAMAV": "1",
|
|
"ENABLE_FAIL2BAN": "1",
|
|
"ONE_DIR": "1",
|
|
"TZ": "{{TIMEZONE}}"
|
|
}
|
|
},
|
|
subdomain: "mail",
|
|
defaultPort: 25,
|
|
healthCheck: "/",
|
|
subpathSupport: 'strip',
|
|
setupInstructions: [
|
|
"Configure DNS records (MX, SPF, DKIM, DMARC)",
|
|
"Create email accounts using setup.sh",
|
|
"Set up SSL certificates for secure connections"
|
|
]
|
|
},
|
|
|
|
"roundcube": {
|
|
name: "Roundcube",
|
|
description: "Modern webmail client with rich features",
|
|
icon: "💌",
|
|
category: "Communication",
|
|
popularity: 72,
|
|
difficulty: "Intermediate",
|
|
docker: {
|
|
image: "roundcube/roundcubemail:latest",
|
|
ports: ["{{PORT}}:80"],
|
|
volumes: [
|
|
"/opt/roundcube/config:/var/roundcube/config",
|
|
"/opt/roundcube/db:/var/roundcube/db"
|
|
],
|
|
environment: {
|
|
"ROUNDCUBEMAIL_DEFAULT_HOST": "mail.{{SUBDOMAIN}}.sami",
|
|
"ROUNDCUBEMAIL_SMTP_SERVER": "mail.{{SUBDOMAIN}}.sami"
|
|
}
|
|
},
|
|
subdomain: "webmail",
|
|
defaultPort: 8086,
|
|
healthCheck: "/",
|
|
subpathSupport: 'strip',
|
|
setupInstructions: [
|
|
"Configure IMAP/SMTP server settings",
|
|
"Set up database connection",
|
|
"Customize appearance and plugins"
|
|
]
|
|
},
|
|
|
|
"matrix": {
|
|
name: "Matrix Synapse",
|
|
description: "Decentralized, secure messaging and collaboration",
|
|
icon: "💬",
|
|
category: "Communication",
|
|
popularity: 75,
|
|
difficulty: "Advanced",
|
|
docker: {
|
|
image: "matrixdotorg/synapse:latest",
|
|
ports: ["{{PORT}}:8008"],
|
|
volumes: ["/opt/matrix/data:/data"],
|
|
environment: {
|
|
"SYNAPSE_SERVER_NAME": "{{SUBDOMAIN}}.sami",
|
|
"SYNAPSE_REPORT_STATS": "no"
|
|
}
|
|
},
|
|
subdomain: "matrix",
|
|
defaultPort: 8008,
|
|
healthCheck: "/_matrix/client/versions",
|
|
subpathSupport: 'none',
|
|
setupInstructions: [
|
|
"Generate initial config with --generate",
|
|
"Configure homeserver.yaml",
|
|
"Set up federation if needed"
|
|
]
|
|
},
|
|
|
|
"rocketchat": {
|
|
name: "Rocket.Chat",
|
|
description: "Team collaboration platform like Slack",
|
|
icon: "🚀",
|
|
category: "Communication",
|
|
popularity: 78,
|
|
difficulty: "Intermediate",
|
|
docker: {
|
|
image: "rocket.chat:latest",
|
|
ports: ["{{PORT}}:3000"],
|
|
volumes: ["/opt/rocketchat/uploads:/app/uploads"],
|
|
environment: {
|
|
"ROOT_URL": "https://{{SUBDOMAIN}}.sami",
|
|
"MONGO_URL": "mongodb://mongo:27017/rocketchat"
|
|
}
|
|
},
|
|
subdomain: "chat",
|
|
defaultPort: 3004,
|
|
healthCheck: "/api/info",
|
|
subpathSupport: 'strip',
|
|
setupInstructions: [
|
|
"Requires MongoDB - deploy mongo container first",
|
|
"Complete admin setup wizard",
|
|
"Configure OAuth and integrations"
|
|
]
|
|
},
|
|
|
|
// === HOME AUTOMATION ===
|
|
"homeassistant": {
|
|
name: "Home Assistant",
|
|
description: "Open source home automation platform",
|
|
icon: "🏠",
|
|
category: "Home Automation",
|
|
popularity: 92,
|
|
difficulty: "Intermediate",
|
|
docker: {
|
|
image: "homeassistant/home-assistant:stable",
|
|
ports: ["{{PORT}}:8123"],
|
|
volumes: [
|
|
"/opt/homeassistant/config:/config",
|
|
"/etc/localtime:/etc/localtime:ro"
|
|
],
|
|
environment: {
|
|
"TZ": "{{TIMEZONE}}"
|
|
}
|
|
},
|
|
subdomain: "home",
|
|
defaultPort: 8123,
|
|
healthCheck: "/api/",
|
|
subpathSupport: 'strip',
|
|
setupInstructions: [
|
|
"Complete onboarding wizard",
|
|
"Add integrations for your smart devices",
|
|
"Create automations and dashboards"
|
|
]
|
|
},
|
|
|
|
"nodered": {
|
|
name: "Node-RED",
|
|
description: "Flow-based programming for IoT and automation",
|
|
icon: "🔴",
|
|
category: "Home Automation",
|
|
popularity: 80,
|
|
difficulty: "Intermediate",
|
|
docker: {
|
|
image: "nodered/node-red:latest",
|
|
ports: ["{{PORT}}:1880"],
|
|
volumes: ["/opt/nodered/data:/data"],
|
|
environment: {
|
|
"TZ": "{{TIMEZONE}}"
|
|
}
|
|
},
|
|
subdomain: "nodered",
|
|
defaultPort: 1880,
|
|
healthCheck: "/",
|
|
subpathSupport: 'strip',
|
|
setupInstructions: [
|
|
"Install additional nodes from palette",
|
|
"Create flows for automation",
|
|
"Connect to Home Assistant or MQTT"
|
|
]
|
|
},
|
|
|
|
// === DATABASES ===
|
|
"postgres": {
|
|
name: "PostgreSQL",
|
|
description: "Advanced open-source relational database",
|
|
icon: "🐘",
|
|
category: "Database",
|
|
popularity: 85,
|
|
difficulty: "Intermediate",
|
|
docker: {
|
|
image: "postgres:16-alpine",
|
|
ports: ["{{PORT}}:5432"],
|
|
volumes: ["/opt/postgres/data:/var/lib/postgresql/data"],
|
|
environment: {
|
|
"POSTGRES_USER": "admin",
|
|
"POSTGRES_PASSWORD": "{{POSTGRES_PASSWORD}}",
|
|
"POSTGRES_DB": "default"
|
|
}
|
|
},
|
|
subdomain: "postgres",
|
|
defaultPort: 5432,
|
|
healthCheck: "/",
|
|
subpathSupport: 'strip',
|
|
setupInstructions: [
|
|
"Change default password immediately",
|
|
"Create databases and users as needed",
|
|
"Configure pg_hba.conf for remote access"
|
|
],
|
|
secrets: [
|
|
{
|
|
envVar: "POSTGRES_PASSWORD",
|
|
label: "Admin Password",
|
|
description: "Password for PostgreSQL admin user",
|
|
type: "password",
|
|
required: true,
|
|
generate: "alphanumeric",
|
|
length: 32
|
|
}
|
|
]
|
|
},
|
|
|
|
"redis": {
|
|
name: "Redis",
|
|
description: "In-memory data structure store and cache",
|
|
icon: "🔴",
|
|
category: "Database",
|
|
popularity: 82,
|
|
difficulty: "Easy",
|
|
docker: {
|
|
image: "redis:alpine",
|
|
ports: ["{{PORT}}:6379"],
|
|
volumes: ["/opt/redis/data:/data"],
|
|
environment: {}
|
|
},
|
|
subdomain: "redis",
|
|
defaultPort: 6379,
|
|
healthCheck: "/",
|
|
subpathSupport: 'strip',
|
|
setupInstructions: [
|
|
"Configure redis.conf for persistence",
|
|
"Set up authentication if needed",
|
|
"Configure maxmemory policy"
|
|
]
|
|
},
|
|
|
|
"mongodb": {
|
|
name: "MongoDB",
|
|
description: "Document-oriented NoSQL database",
|
|
icon: "🍃",
|
|
category: "Database",
|
|
popularity: 80,
|
|
difficulty: "Intermediate",
|
|
docker: {
|
|
image: "mongo:latest",
|
|
ports: ["{{PORT}}:27017"],
|
|
volumes: ["/opt/mongodb/data:/data/db"],
|
|
environment: {
|
|
"MONGO_INITDB_ROOT_USERNAME": "admin",
|
|
"MONGO_INITDB_ROOT_PASSWORD": "{{MONGO_ROOT_PASSWORD}}"
|
|
}
|
|
},
|
|
subdomain: "mongo",
|
|
defaultPort: 27017,
|
|
healthCheck: "/",
|
|
subpathSupport: 'strip',
|
|
setupInstructions: [
|
|
"Change default admin password",
|
|
"Create application databases and users",
|
|
"Configure replica set if needed"
|
|
],
|
|
secrets: [
|
|
{
|
|
envVar: "MONGO_ROOT_PASSWORD",
|
|
label: "Root Password",
|
|
description: "Root password for MongoDB admin user",
|
|
type: "password",
|
|
required: true,
|
|
generate: "alphanumeric",
|
|
length: 32
|
|
}
|
|
]
|
|
},
|
|
|
|
"adminer": {
|
|
name: "Adminer",
|
|
description: "Lightweight database management in single PHP file",
|
|
icon: "🗄️",
|
|
category: "Database",
|
|
popularity: 75,
|
|
difficulty: "Easy",
|
|
docker: {
|
|
image: "adminer:latest",
|
|
ports: ["{{PORT}}:8080"],
|
|
volumes: [],
|
|
environment: {
|
|
"ADMINER_DEFAULT_SERVER": "postgres"
|
|
}
|
|
},
|
|
subdomain: "adminer",
|
|
defaultPort: 8087,
|
|
healthCheck: "/",
|
|
subpathSupport: 'strip',
|
|
setupInstructions: [
|
|
"Connect to your database servers",
|
|
"Supports MySQL, PostgreSQL, SQLite, etc."
|
|
]
|
|
},
|
|
|
|
// === SECURITY & AUTH ===
|
|
"vaultwarden": {
|
|
name: "Vaultwarden",
|
|
description: "Lightweight Bitwarden-compatible password manager",
|
|
icon: "🔑",
|
|
category: "Security",
|
|
popularity: 90,
|
|
difficulty: "Easy",
|
|
docker: {
|
|
image: "vaultwarden/server:latest",
|
|
ports: ["{{PORT}}:80"],
|
|
volumes: ["/opt/vaultwarden/data:/data"],
|
|
environment: {
|
|
"DOMAIN": "https://{{SUBDOMAIN}}.sami",
|
|
"ADMIN_TOKEN": "{{VAULTWARDEN_ADMIN_TOKEN}}"
|
|
}
|
|
},
|
|
subdomain: "vault",
|
|
defaultPort: 8088,
|
|
healthCheck: "/",
|
|
subpathSupport: 'strip',
|
|
setupInstructions: [
|
|
"Change admin token immediately",
|
|
"Create your account",
|
|
"Install browser extensions and mobile apps"
|
|
],
|
|
secrets: [
|
|
{
|
|
envVar: "VAULTWARDEN_ADMIN_TOKEN",
|
|
label: "Admin Token",
|
|
description: "Admin panel access token for Vaultwarden",
|
|
type: "password",
|
|
required: true,
|
|
generate: "alphanumeric",
|
|
length: 48
|
|
}
|
|
]
|
|
},
|
|
|
|
"dashca": {
|
|
name: "DashCA",
|
|
description: "One-click root CA certificate installer for your network",
|
|
icon: "🔐",
|
|
logo: "/assets/certificate-icon.png",
|
|
category: "Security",
|
|
popularity: 95,
|
|
difficulty: "Easy",
|
|
isStaticSite: true, // Special flag for non-Docker deployments
|
|
subdomain: "ca",
|
|
defaultPort: null, // Static site, no port needed
|
|
healthCheck: null,
|
|
subpathSupport: 'strip',
|
|
features: [
|
|
"Automatic OS detection",
|
|
"One-click installation",
|
|
"Supports Windows, macOS, Linux, iOS, Android",
|
|
"Apple mobileconfig for easy iOS/macOS setup",
|
|
"QR code for mobile access",
|
|
"Certificate expiration monitoring"
|
|
],
|
|
setupInstructions: [
|
|
"New devices: visit http://ca.sami (HTTP, no certificate needed)",
|
|
"Click the 'Install Certificate' button for your platform",
|
|
"Follow platform-specific instructions",
|
|
"Verify all *.sami domains now show secure connections"
|
|
],
|
|
tags: ["security", "certificates", "ssl", "tls", "infrastructure"]
|
|
},
|
|
|
|
"weather": {
|
|
name: "Weather",
|
|
description: "Live weather widget with temperature, conditions, and wind",
|
|
icon: "🌤️",
|
|
category: "Utilities",
|
|
popularity: 85,
|
|
difficulty: "Easy",
|
|
isDashboardWidget: true,
|
|
widgetSelector: ".weather-widget-container",
|
|
subdomain: null,
|
|
defaultPort: null,
|
|
healthCheck: null,
|
|
subpathSupport: 'strip',
|
|
features: [
|
|
"Current temperature and conditions",
|
|
"Wind speed and direction",
|
|
"Weather icon with emoji fallback",
|
|
"Configurable ZIP code",
|
|
"Auto-refreshes periodically"
|
|
],
|
|
setupInstructions: [
|
|
"Click the gear icon on the widget to set your ZIP code",
|
|
"Weather appears in the top bar next to the logo"
|
|
],
|
|
tags: ["weather", "widget", "dashboard", "utility"]
|
|
},
|
|
|
|
"digital-clock": {
|
|
name: "Digital Clock",
|
|
description: "Live digital clock with time, date, and day of week",
|
|
icon: "🕐",
|
|
category: "Utilities",
|
|
popularity: 80,
|
|
difficulty: "Easy",
|
|
isDashboardWidget: true,
|
|
widgetSelector: ".clock-widget-container",
|
|
subdomain: null,
|
|
defaultPort: null,
|
|
healthCheck: null,
|
|
subpathSupport: 'strip',
|
|
features: [
|
|
"12-hour format with AM/PM",
|
|
"Live seconds display",
|
|
"Full date with day of week",
|
|
"Responsive sizing across all devices",
|
|
"Matches dashboard theme automatically"
|
|
],
|
|
setupInstructions: [
|
|
"Clock appears in the top bar to the right of the weather widget",
|
|
"No configuration needed — runs automatically"
|
|
],
|
|
tags: ["clock", "time", "widget", "dashboard", "utility"]
|
|
},
|
|
|
|
// === MEDIA MANAGEMENT (Additional) ===
|
|
"lidarr": {
|
|
name: "Lidarr",
|
|
description: "Music collection manager for Usenet and BitTorrent",
|
|
icon: "🎵",
|
|
category: "Media Management",
|
|
popularity: 70,
|
|
difficulty: "Intermediate",
|
|
docker: {
|
|
image: "linuxserver/lidarr:latest",
|
|
ports: ["{{PORT}}:8686"],
|
|
volumes: [
|
|
"/opt/lidarr/config:/config",
|
|
"/downloads:/downloads",
|
|
"/music:/music"
|
|
],
|
|
environment: {
|
|
"PUID": "1000",
|
|
"PGID": "1000",
|
|
"TZ": "{{TIMEZONE}}"
|
|
}
|
|
},
|
|
subdomain: "lidarr",
|
|
defaultPort: 8686,
|
|
healthCheck: "/api/v1/system/status",
|
|
subpathSupport: 'native',
|
|
urlBaseEnv: 'URL_BASE',
|
|
setupInstructions: [
|
|
"Configure download clients",
|
|
"Add indexers",
|
|
"Set up root folders for music"
|
|
]
|
|
},
|
|
|
|
"readarr": {
|
|
name: "Readarr",
|
|
description: "Book and audiobook collection manager",
|
|
icon: "📚",
|
|
category: "Media Management",
|
|
popularity: 65,
|
|
difficulty: "Intermediate",
|
|
docker: {
|
|
image: "linuxserver/readarr:develop",
|
|
ports: ["{{PORT}}:8787"],
|
|
volumes: [
|
|
"/opt/readarr/config:/config",
|
|
"/downloads:/downloads",
|
|
"/books:/books"
|
|
],
|
|
environment: {
|
|
"PUID": "1000",
|
|
"PGID": "1000",
|
|
"TZ": "{{TIMEZONE}}"
|
|
}
|
|
},
|
|
subdomain: "readarr",
|
|
defaultPort: 8787,
|
|
healthCheck: "/api/v1/system/status",
|
|
subpathSupport: 'native',
|
|
urlBaseEnv: 'URL_BASE',
|
|
setupInstructions: [
|
|
"Configure download clients",
|
|
"Add indexers for books",
|
|
"Set up root folders"
|
|
]
|
|
},
|
|
|
|
"bazarr": {
|
|
name: "Bazarr",
|
|
description: "Automatic subtitle downloader for Sonarr and Radarr",
|
|
icon: "💬",
|
|
category: "Media Management",
|
|
popularity: 72,
|
|
difficulty: "Easy",
|
|
docker: {
|
|
image: "linuxserver/bazarr:latest",
|
|
ports: ["{{PORT}}:6767"],
|
|
volumes: [
|
|
"/opt/bazarr/config:/config",
|
|
"/movies:/movies",
|
|
"/tv:/tv"
|
|
],
|
|
environment: {
|
|
"PUID": "1000",
|
|
"PGID": "1000",
|
|
"TZ": "{{TIMEZONE}}"
|
|
}
|
|
},
|
|
subdomain: "bazarr",
|
|
defaultPort: 6767,
|
|
healthCheck: "/",
|
|
subpathSupport: 'native',
|
|
urlBaseEnv: 'BASE_URL',
|
|
setupInstructions: [
|
|
"Connect to Sonarr and Radarr",
|
|
"Configure subtitle providers",
|
|
"Set language preferences"
|
|
]
|
|
},
|
|
|
|
"seerr": {
|
|
name: "Seerr",
|
|
description: "Media request and discovery manager for Plex, Jellyfin, and Emby",
|
|
icon: "🎫",
|
|
category: "Media Management",
|
|
popularity: 82,
|
|
difficulty: "Easy",
|
|
docker: {
|
|
image: "ghcr.io/seerr-team/seerr:latest",
|
|
ports: ["{{PORT}}:5055"],
|
|
volumes: ["/opt/seerr/config:/app/config"],
|
|
environment: {
|
|
"TZ": "{{TIMEZONE}}"
|
|
},
|
|
init: true
|
|
},
|
|
subdomain: "requests",
|
|
defaultPort: 5055,
|
|
healthCheck: "/api/v1/status",
|
|
subpathSupport: 'native',
|
|
urlBaseEnv: 'BASE_PATH',
|
|
setupInstructions: [
|
|
"Connect to Plex, Jellyfin, or Emby server",
|
|
"Link Sonarr and Radarr",
|
|
"Configure user permissions"
|
|
]
|
|
},
|
|
|
|
"tautulli": {
|
|
name: "Tautulli",
|
|
description: "Plex media server monitoring and statistics",
|
|
icon: "📊",
|
|
category: "Media Management",
|
|
popularity: 78,
|
|
difficulty: "Easy",
|
|
docker: {
|
|
image: "linuxserver/tautulli:latest",
|
|
ports: ["{{PORT}}:8181"],
|
|
volumes: ["/opt/tautulli/config:/config"],
|
|
environment: {
|
|
"PUID": "1000",
|
|
"PGID": "1000",
|
|
"TZ": "{{TIMEZONE}}"
|
|
}
|
|
},
|
|
subdomain: "tautulli",
|
|
defaultPort: 8181,
|
|
healthCheck: "/",
|
|
subpathSupport: 'native',
|
|
urlBaseEnv: 'TAUTULLI_HTTP_ROOT',
|
|
setupInstructions: [
|
|
"Connect to Plex server",
|
|
"Configure notifications",
|
|
"Set up newsletters"
|
|
]
|
|
},
|
|
|
|
// === DEVELOPMENT TOOLS ===
|
|
"gitea": {
|
|
name: "Gitea",
|
|
description: "Lightweight self-hosted Git service",
|
|
icon: "🦊",
|
|
category: "Development",
|
|
popularity: 85,
|
|
difficulty: "Easy",
|
|
docker: {
|
|
image: "gitea/gitea:latest",
|
|
ports: ["{{PORT}}:3000", "2222:22"],
|
|
volumes: [
|
|
"/opt/gitea/data:/data",
|
|
"/etc/timezone:/etc/timezone:ro",
|
|
"/etc/localtime:/etc/localtime:ro"
|
|
],
|
|
environment: {
|
|
"USER_UID": "1000",
|
|
"USER_GID": "1000"
|
|
}
|
|
},
|
|
subdomain: "gitea",
|
|
defaultPort: 3005,
|
|
healthCheck: "/",
|
|
subpathSupport: 'native',
|
|
urlBaseEnv: 'GITEA__server__ROOT_URL',
|
|
setupInstructions: [
|
|
"Complete initial setup wizard",
|
|
"Create admin account",
|
|
"Configure SSH access"
|
|
]
|
|
},
|
|
|
|
"jenkins": {
|
|
name: "Jenkins",
|
|
description: "Automation server for CI/CD pipelines",
|
|
icon: "🔧",
|
|
category: "Development",
|
|
popularity: 75,
|
|
difficulty: "Advanced",
|
|
docker: {
|
|
image: "jenkins/jenkins:lts",
|
|
ports: ["{{PORT}}:8080", "50000:50000"],
|
|
volumes: ["/opt/jenkins/data:/var/jenkins_home"],
|
|
environment: {}
|
|
},
|
|
subdomain: "jenkins",
|
|
defaultPort: 8089,
|
|
healthCheck: "/login",
|
|
subpathSupport: 'strip',
|
|
setupInstructions: [
|
|
"Get initial admin password from logs",
|
|
"Install suggested plugins",
|
|
"Create admin user"
|
|
]
|
|
},
|
|
|
|
"drone": {
|
|
name: "Drone CI",
|
|
description: "Container-native continuous delivery platform",
|
|
icon: "🐝",
|
|
category: "Development",
|
|
popularity: 70,
|
|
difficulty: "Intermediate",
|
|
docker: {
|
|
image: "drone/drone:latest",
|
|
ports: ["{{PORT}}:80"],
|
|
volumes: ["/opt/drone/data:/data"],
|
|
environment: {
|
|
"DRONE_GITEA_SERVER": "https://git.sami",
|
|
"DRONE_RPC_SECRET": "{{DRONE_RPC_SECRET}}",
|
|
"DRONE_SERVER_HOST": "{{SUBDOMAIN}}.sami",
|
|
"DRONE_SERVER_PROTO": "https"
|
|
}
|
|
},
|
|
subdomain: "drone",
|
|
defaultPort: 8090,
|
|
healthCheck: "/",
|
|
subpathSupport: 'strip',
|
|
setupInstructions: [
|
|
"Configure Git provider integration",
|
|
"Set up shared secret",
|
|
"Deploy Drone runners"
|
|
],
|
|
secrets: [
|
|
{
|
|
envVar: "DRONE_RPC_SECRET",
|
|
label: "RPC Secret",
|
|
description: "Shared secret for Drone server and runner communication",
|
|
type: "password",
|
|
required: true,
|
|
generate: "alphanumeric",
|
|
length: 64
|
|
}
|
|
]
|
|
},
|
|
|
|
// === NOTES & WIKI ===
|
|
"bookstack": {
|
|
name: "BookStack",
|
|
description: "Simple wiki and documentation platform",
|
|
icon: "📖",
|
|
category: "Productivity",
|
|
popularity: 80,
|
|
difficulty: "Intermediate",
|
|
docker: {
|
|
image: "linuxserver/bookstack:latest",
|
|
ports: ["{{PORT}}:80"],
|
|
volumes: ["/opt/bookstack/config:/config"],
|
|
environment: {
|
|
"PUID": "1000",
|
|
"PGID": "1000",
|
|
"APP_URL": "https://{{SUBDOMAIN}}.sami",
|
|
"DB_HOST": "mariadb",
|
|
"DB_DATABASE": "bookstack",
|
|
"DB_USERNAME": "bookstack",
|
|
"DB_PASSWORD": "{{BOOKSTACK_DB_PASSWORD}}"
|
|
}
|
|
},
|
|
subdomain: "wiki",
|
|
defaultPort: 8091,
|
|
healthCheck: "/",
|
|
subpathSupport: 'strip',
|
|
setupInstructions: [
|
|
"Requires MariaDB/MySQL database",
|
|
"Default login: admin@admin.com / password",
|
|
"Change default credentials"
|
|
],
|
|
secrets: [
|
|
{
|
|
envVar: "BOOKSTACK_DB_PASSWORD",
|
|
label: "Database Password",
|
|
description: "Password for BookStack database user",
|
|
type: "password",
|
|
required: true,
|
|
generate: "alphanumeric",
|
|
length: 32
|
|
}
|
|
]
|
|
},
|
|
|
|
"outline": {
|
|
name: "Outline",
|
|
description: "Modern team knowledge base and wiki",
|
|
icon: "📝",
|
|
category: "Productivity",
|
|
popularity: 75,
|
|
difficulty: "Advanced",
|
|
docker: {
|
|
image: "outlinewiki/outline:latest",
|
|
ports: ["{{PORT}}:3000"],
|
|
volumes: ["/opt/outline/data:/var/lib/outline/data"],
|
|
environment: {
|
|
"URL": "https://{{SUBDOMAIN}}.sami",
|
|
"SECRET_KEY": "{{OUTLINE_SECRET_KEY}}",
|
|
"DATABASE_URL": "postgres://outline:{{OUTLINE_DB_PASSWORD}}@postgres:5432/outline"
|
|
}
|
|
},
|
|
subdomain: "outline",
|
|
defaultPort: 3006,
|
|
healthCheck: "/",
|
|
subpathSupport: 'strip',
|
|
setupInstructions: [
|
|
"Requires PostgreSQL and Redis",
|
|
"Configure OAuth provider",
|
|
"Set up S3-compatible storage"
|
|
],
|
|
secrets: [
|
|
{
|
|
envVar: "OUTLINE_SECRET_KEY",
|
|
label: "Secret Key",
|
|
description: "Secret key for encrypting session data",
|
|
type: "password",
|
|
required: true,
|
|
generate: "alphanumeric",
|
|
length: 64
|
|
},
|
|
{
|
|
envVar: "OUTLINE_DB_PASSWORD",
|
|
label: "Database Password",
|
|
description: "Password for Outline PostgreSQL database user",
|
|
type: "password",
|
|
required: true,
|
|
generate: "alphanumeric",
|
|
length: 32
|
|
}
|
|
]
|
|
},
|
|
|
|
"standardnotes": {
|
|
name: "Standard Notes",
|
|
description: "End-to-end encrypted notes app",
|
|
icon: "🔒",
|
|
category: "Productivity",
|
|
popularity: 72,
|
|
difficulty: "Intermediate",
|
|
docker: {
|
|
image: "standardnotes/server:latest",
|
|
ports: ["{{PORT}}:3000"],
|
|
volumes: ["/opt/standardnotes/data:/var/lib/server"],
|
|
environment: {
|
|
"RAILS_ENV": "production"
|
|
}
|
|
},
|
|
subdomain: "notes",
|
|
defaultPort: 3007,
|
|
healthCheck: "/",
|
|
subpathSupport: 'strip',
|
|
setupInstructions: [
|
|
"Configure environment variables",
|
|
"Set up database connection",
|
|
"Install Standard Notes apps"
|
|
]
|
|
},
|
|
|
|
// === PHOTOS & GALLERIES ===
|
|
"immich": {
|
|
name: "Immich",
|
|
description: "Self-hosted Google Photos alternative",
|
|
icon: "📸",
|
|
category: "Photos",
|
|
popularity: 90,
|
|
difficulty: "Intermediate",
|
|
docker: {
|
|
image: "ghcr.io/immich-app/immich-server:latest",
|
|
ports: ["{{PORT}}:2283"],
|
|
volumes: [
|
|
"/opt/immich/upload:/usr/src/app/upload",
|
|
"/opt/immich/library:/usr/src/app/library"
|
|
],
|
|
environment: {
|
|
"DB_HOSTNAME": "postgres",
|
|
"DB_USERNAME": "immich",
|
|
"DB_PASSWORD": "{{IMMICH_DB_PASSWORD}}",
|
|
"DB_DATABASE_NAME": "immich",
|
|
"REDIS_HOSTNAME": "redis"
|
|
}
|
|
},
|
|
subdomain: "photos",
|
|
defaultPort: 2283,
|
|
healthCheck: "/api/server-info/ping",
|
|
subpathSupport: 'strip',
|
|
setupInstructions: [
|
|
"Requires PostgreSQL and Redis",
|
|
"Install mobile apps for backup",
|
|
"Configure machine learning for face detection"
|
|
],
|
|
secrets: [
|
|
{
|
|
envVar: "IMMICH_DB_PASSWORD",
|
|
label: "Database Password",
|
|
description: "Password for Immich PostgreSQL database user",
|
|
type: "password",
|
|
required: true,
|
|
generate: "alphanumeric",
|
|
length: 32
|
|
}
|
|
]
|
|
},
|
|
|
|
"photoprism": {
|
|
name: "PhotoPrism",
|
|
description: "AI-powered photo management",
|
|
icon: "🖼️",
|
|
category: "Photos",
|
|
popularity: 85,
|
|
difficulty: "Intermediate",
|
|
docker: {
|
|
image: "photoprism/photoprism:latest",
|
|
ports: ["{{PORT}}:2342"],
|
|
volumes: [
|
|
"/opt/photoprism/storage:/photoprism/storage",
|
|
"/opt/photoprism/originals:/photoprism/originals"
|
|
],
|
|
environment: {
|
|
"PHOTOPRISM_ADMIN_PASSWORD": "{{PHOTOPRISM_ADMIN_PASSWORD}}",
|
|
"PHOTOPRISM_SITE_URL": "https://{{SUBDOMAIN}}.sami/",
|
|
"PHOTOPRISM_DATABASE_DRIVER": "sqlite"
|
|
}
|
|
},
|
|
subdomain: "gallery",
|
|
defaultPort: 2342,
|
|
healthCheck: "/api/v1/status",
|
|
subpathSupport: 'strip',
|
|
setupInstructions: [
|
|
"Change admin password",
|
|
"Import your photos",
|
|
"Run indexing for AI features"
|
|
],
|
|
secrets: [
|
|
{
|
|
envVar: "PHOTOPRISM_ADMIN_PASSWORD",
|
|
label: "Admin Password",
|
|
description: "Password for PhotoPrism admin account",
|
|
type: "password",
|
|
required: true,
|
|
generate: "alphanumeric",
|
|
length: 32
|
|
}
|
|
]
|
|
},
|
|
|
|
// === DOWNLOAD MANAGERS ===
|
|
"sabnzbd": {
|
|
name: "SABnzbd",
|
|
description: "Binary newsreader for Usenet downloads",
|
|
icon: "📰",
|
|
category: "Downloads",
|
|
popularity: 75,
|
|
difficulty: "Intermediate",
|
|
docker: {
|
|
image: "linuxserver/sabnzbd:latest",
|
|
ports: ["{{PORT}}:8080"],
|
|
volumes: [
|
|
"/opt/sabnzbd/config:/config",
|
|
"/downloads:/downloads"
|
|
],
|
|
environment: {
|
|
"PUID": "1000",
|
|
"PGID": "1000",
|
|
"TZ": "{{TIMEZONE}}"
|
|
}
|
|
},
|
|
subdomain: "sabnzbd",
|
|
defaultPort: 8092,
|
|
healthCheck: "/",
|
|
subpathSupport: 'native',
|
|
urlBaseEnv: 'SABNZBD_URL_BASE',
|
|
setupInstructions: [
|
|
"Configure Usenet server credentials",
|
|
"Set up download categories",
|
|
"Configure post-processing scripts"
|
|
]
|
|
},
|
|
|
|
"nzbget": {
|
|
name: "NZBGet",
|
|
description: "Efficient Usenet downloader",
|
|
icon: "📥",
|
|
category: "Downloads",
|
|
popularity: 70,
|
|
difficulty: "Intermediate",
|
|
docker: {
|
|
image: "linuxserver/nzbget:latest",
|
|
ports: ["{{PORT}}:6789"],
|
|
volumes: [
|
|
"/opt/nzbget/config:/config",
|
|
"/downloads:/downloads"
|
|
],
|
|
environment: {
|
|
"PUID": "1000",
|
|
"PGID": "1000",
|
|
"TZ": "{{TIMEZONE}}"
|
|
}
|
|
},
|
|
subdomain: "nzbget",
|
|
defaultPort: 6789,
|
|
healthCheck: "/",
|
|
subpathSupport: 'strip',
|
|
setupInstructions: [
|
|
"Default login: nzbget/tegbzn6789",
|
|
"Configure news servers",
|
|
"Set up categories and paths"
|
|
]
|
|
},
|
|
|
|
"transmission": {
|
|
name: "Transmission",
|
|
description: "Lightweight BitTorrent client",
|
|
icon: "🌊",
|
|
category: "Downloads",
|
|
popularity: 80,
|
|
difficulty: "Easy",
|
|
docker: {
|
|
image: "linuxserver/transmission:latest",
|
|
ports: ["{{PORT}}:9091", "51413:51413", "51413:51413/udp"],
|
|
volumes: [
|
|
"/opt/transmission/config:/config",
|
|
"/downloads:/downloads"
|
|
],
|
|
environment: {
|
|
"PUID": "1000",
|
|
"PGID": "1000",
|
|
"TZ": "{{TIMEZONE}}"
|
|
}
|
|
},
|
|
subdomain: "transmission",
|
|
defaultPort: 9092,
|
|
healthCheck: "/transmission/web/",
|
|
subpathSupport: 'native',
|
|
urlBaseEnv: 'TRANSMISSION_WEB_HOME',
|
|
setupInstructions: [
|
|
"Configure download paths",
|
|
"Set bandwidth limits",
|
|
"Configure blocklists if needed"
|
|
]
|
|
},
|
|
|
|
"jdownloader": {
|
|
name: "JDownloader 2",
|
|
description: "Download manager for file hosting sites",
|
|
icon: "⬇️",
|
|
category: "Downloads",
|
|
popularity: 72,
|
|
difficulty: "Easy",
|
|
docker: {
|
|
image: "jlesage/jdownloader-2:latest",
|
|
ports: ["{{PORT}}:5800"],
|
|
volumes: [
|
|
"/opt/jdownloader/config:/config",
|
|
"/downloads:/output"
|
|
],
|
|
environment: {}
|
|
},
|
|
subdomain: "jdownloader",
|
|
defaultPort: 5800,
|
|
healthCheck: "/",
|
|
subpathSupport: 'strip',
|
|
setupInstructions: [
|
|
"Access web interface to configure",
|
|
"Link to MyJDownloader account",
|
|
"Configure download paths"
|
|
]
|
|
},
|
|
|
|
// === STREAMING & MEDIA ===
|
|
"navidrome": {
|
|
name: "Navidrome",
|
|
description: "Modern music server and streamer",
|
|
icon: "🎶",
|
|
category: "Media",
|
|
popularity: 80,
|
|
difficulty: "Easy",
|
|
docker: {
|
|
image: "deluan/navidrome:latest",
|
|
ports: ["{{PORT}}:4533"],
|
|
volumes: [
|
|
"/opt/navidrome/data:/data",
|
|
"/music:/music:ro"
|
|
],
|
|
environment: {
|
|
"ND_SCANSCHEDULE": "1h",
|
|
"ND_LOGLEVEL": "info"
|
|
}
|
|
},
|
|
subdomain: "music",
|
|
defaultPort: 4533,
|
|
healthCheck: "/",
|
|
subpathSupport: 'strip',
|
|
setupInstructions: [
|
|
"Point to your music library",
|
|
"Create user accounts",
|
|
"Install Subsonic-compatible apps"
|
|
]
|
|
},
|
|
|
|
"airsonic": {
|
|
name: "Airsonic Advanced",
|
|
description: "Free web-based media streamer",
|
|
icon: "🎧",
|
|
category: "Media",
|
|
popularity: 68,
|
|
difficulty: "Easy",
|
|
docker: {
|
|
image: "linuxserver/airsonic-advanced:latest",
|
|
ports: ["{{PORT}}:4040"],
|
|
volumes: [
|
|
"/opt/airsonic/config:/config",
|
|
"/music:/music",
|
|
"/podcasts:/podcasts"
|
|
],
|
|
environment: {
|
|
"PUID": "1000",
|
|
"PGID": "1000",
|
|
"TZ": "{{TIMEZONE}}"
|
|
}
|
|
},
|
|
subdomain: "airsonic",
|
|
defaultPort: 4040,
|
|
healthCheck: "/",
|
|
subpathSupport: 'strip',
|
|
setupInstructions: [
|
|
"Default login: admin/admin",
|
|
"Configure media folders",
|
|
"Set up transcoding"
|
|
]
|
|
},
|
|
|
|
// === MISC UTILITIES ===
|
|
"homepage": {
|
|
name: "Homepage",
|
|
description: "Highly customizable application dashboard",
|
|
icon: "🏡",
|
|
category: "Utilities",
|
|
popularity: 85,
|
|
difficulty: "Easy",
|
|
docker: {
|
|
image: "ghcr.io/gethomepage/homepage:latest",
|
|
ports: ["{{PORT}}:3000"],
|
|
volumes: [
|
|
"/opt/homepage/config:/app/config",
|
|
"/var/run/docker.sock:/var/run/docker.sock:ro"
|
|
],
|
|
environment: {}
|
|
},
|
|
subdomain: "dashboard",
|
|
defaultPort: 3008,
|
|
healthCheck: "/",
|
|
subpathSupport: 'strip',
|
|
setupInstructions: [
|
|
"Edit config files to add services",
|
|
"Configure widgets",
|
|
"Customize appearance"
|
|
]
|
|
},
|
|
|
|
"homarr": {
|
|
name: "Homarr",
|
|
description: "Sleek dashboard for all your services",
|
|
icon: "🎯",
|
|
category: "Utilities",
|
|
popularity: 82,
|
|
difficulty: "Easy",
|
|
docker: {
|
|
image: "ghcr.io/ajnart/homarr:latest",
|
|
ports: ["{{PORT}}:7575"],
|
|
volumes: [
|
|
"/opt/homarr/configs:/app/data/configs",
|
|
"/opt/homarr/icons:/app/public/icons",
|
|
"/var/run/docker.sock:/var/run/docker.sock:ro"
|
|
],
|
|
environment: {}
|
|
},
|
|
subdomain: "homarr",
|
|
defaultPort: 7575,
|
|
healthCheck: "/",
|
|
subpathSupport: 'strip',
|
|
setupInstructions: [
|
|
"Add your services via UI",
|
|
"Configure integrations",
|
|
"Customize layout and appearance"
|
|
]
|
|
},
|
|
|
|
"changedetection": {
|
|
name: "Change Detection",
|
|
description: "Monitor websites for changes",
|
|
icon: "👁️",
|
|
category: "Utilities",
|
|
popularity: 70,
|
|
difficulty: "Easy",
|
|
docker: {
|
|
image: "ghcr.io/dgtlmoon/changedetection.io:latest",
|
|
ports: ["{{PORT}}:5000"],
|
|
volumes: ["/opt/changedetection/data:/datastore"],
|
|
environment: {}
|
|
},
|
|
subdomain: "watch",
|
|
defaultPort: 5001,
|
|
healthCheck: "/",
|
|
subpathSupport: 'strip',
|
|
setupInstructions: [
|
|
"Add URLs to monitor",
|
|
"Configure check frequency",
|
|
"Set up notifications"
|
|
]
|
|
},
|
|
|
|
"speedtest": {
|
|
name: "Speedtest Tracker",
|
|
description: "Internet speed monitoring over time",
|
|
icon: "⚡",
|
|
category: "Monitoring",
|
|
popularity: 75,
|
|
difficulty: "Easy",
|
|
docker: {
|
|
image: "ghcr.io/alexjustesen/speedtest-tracker:latest",
|
|
ports: ["{{PORT}}:80"],
|
|
volumes: ["/opt/speedtest/config:/config"],
|
|
environment: {
|
|
"PUID": "1000",
|
|
"PGID": "1000",
|
|
"DB_CONNECTION": "sqlite"
|
|
}
|
|
},
|
|
subdomain: "speedtest",
|
|
defaultPort: 8093,
|
|
healthCheck: "/",
|
|
subpathSupport: 'strip',
|
|
setupInstructions: [
|
|
"Configure test schedule",
|
|
"View historical data",
|
|
"Set up notifications for slow speeds"
|
|
]
|
|
},
|
|
|
|
"whoami": {
|
|
name: "Whoami",
|
|
description: "Simple HTTP request debugging service",
|
|
icon: "🔍",
|
|
category: "Utilities",
|
|
popularity: 60,
|
|
difficulty: "Easy",
|
|
docker: {
|
|
image: "traefik/whoami:latest",
|
|
ports: ["{{PORT}}:80"],
|
|
volumes: [],
|
|
environment: {}
|
|
},
|
|
subdomain: "whoami",
|
|
defaultPort: 8094,
|
|
healthCheck: "/",
|
|
subpathSupport: 'strip',
|
|
setupInstructions: [
|
|
"Useful for testing reverse proxy setup",
|
|
"Shows request headers and info"
|
|
]
|
|
},
|
|
|
|
// === NEW APPS ===
|
|
|
|
"stirling-pdf": {
|
|
name: "Stirling PDF",
|
|
description: "Self-hosted PDF manipulation tool - merge, split, convert, and more",
|
|
icon: "\uD83D\uDCC4",
|
|
logo: "/assets/stirling-pdf.png",
|
|
category: "Utilities",
|
|
popularity: 85,
|
|
difficulty: "Easy",
|
|
docker: {
|
|
image: "frooodle/s-pdf:latest",
|
|
ports: ["{{PORT}}:8080"],
|
|
volumes: [
|
|
"/opt/stirling-pdf/data:/usr/share/tessdata",
|
|
"/opt/stirling-pdf/config:/configs"
|
|
],
|
|
environment: {
|
|
"DOCKER_ENABLE_SECURITY": "false"
|
|
}
|
|
},
|
|
subdomain: "pdf",
|
|
defaultPort: 8084,
|
|
healthCheck: "/",
|
|
subpathSupport: 'strip',
|
|
setupInstructions: [
|
|
"Access the web interface to start manipulating PDFs",
|
|
"Supports merge, split, rotate, convert, compress, and more",
|
|
"Optional OCR support via Tesseract"
|
|
]
|
|
},
|
|
|
|
"actual-budget": {
|
|
name: "Actual Budget",
|
|
description: "Privacy-focused budgeting app with envelope budgeting",
|
|
icon: "\uD83D\uDCB0",
|
|
logo: "/assets/actual-budget.png",
|
|
category: "Productivity",
|
|
popularity: 78,
|
|
difficulty: "Easy",
|
|
docker: {
|
|
image: "actualbudget/actual-server:latest",
|
|
ports: ["{{PORT}}:5006"],
|
|
volumes: [
|
|
"/opt/actual-budget/data:/data"
|
|
],
|
|
environment: {}
|
|
},
|
|
subdomain: "budget",
|
|
defaultPort: 5006,
|
|
healthCheck: "/",
|
|
subpathSupport: 'strip',
|
|
setupInstructions: [
|
|
"Create your first budget in the web interface",
|
|
"Import transactions from your bank (OFX, QFX, CSV)",
|
|
"Set up envelope categories for spending control"
|
|
]
|
|
},
|
|
|
|
"mealie": {
|
|
name: "Mealie",
|
|
description: "Recipe manager and meal planner with grocery lists",
|
|
icon: "\uD83C\uDF73",
|
|
logo: "/assets/mealie.png",
|
|
category: "Productivity",
|
|
popularity: 76,
|
|
difficulty: "Easy",
|
|
docker: {
|
|
image: "ghcr.io/mealie-recipes/mealie:latest",
|
|
ports: ["{{PORT}}:9000"],
|
|
volumes: [
|
|
"/opt/mealie/data:/app/data"
|
|
],
|
|
environment: {
|
|
"ALLOW_SIGNUP": "true",
|
|
"MAX_WORKERS": "1",
|
|
"WEB_CONCURRENCY": "1",
|
|
"BASE_URL": "https://{{SUBDOMAIN}}.sami"
|
|
}
|
|
},
|
|
subdomain: "mealie",
|
|
defaultPort: 9925,
|
|
healthCheck: "/",
|
|
subpathSupport: 'strip',
|
|
setupInstructions: [
|
|
"Default login: changeme@example.com / MyPassword",
|
|
"Import recipes from URLs or add them manually",
|
|
"Create meal plans and generate shopping lists"
|
|
]
|
|
},
|
|
|
|
"paperless-ngx": {
|
|
name: "Paperless-ngx",
|
|
description: "Document management system - scan, organize, and search documents",
|
|
icon: "\uD83D\uDCDA",
|
|
logo: "/assets/paperless-ngx.png",
|
|
category: "Productivity",
|
|
popularity: 82,
|
|
difficulty: "Intermediate",
|
|
docker: {
|
|
image: "ghcr.io/paperless-ngx/paperless-ngx:latest",
|
|
ports: ["{{PORT}}:8000"],
|
|
volumes: [
|
|
"/opt/paperless/data:/usr/src/paperless/data",
|
|
"/opt/paperless/media:/usr/src/paperless/media",
|
|
"/opt/paperless/consume:/usr/src/paperless/consume"
|
|
],
|
|
environment: {
|
|
"PAPERLESS_URL": "https://{{SUBDOMAIN}}.sami",
|
|
"USERMAP_UID": "1000",
|
|
"USERMAP_GID": "1000",
|
|
"PAPERLESS_TIME_ZONE": "{{TIMEZONE}}",
|
|
"PAPERLESS_OCR_LANGUAGE": "eng",
|
|
"PAPERLESS_SECRET_KEY": "{{GENERATED_SECRET}}"
|
|
}
|
|
},
|
|
subdomain: "paperless",
|
|
defaultPort: 8095,
|
|
healthCheck: "/",
|
|
subpathSupport: 'strip',
|
|
setupInstructions: [
|
|
"Create admin account via: docker exec -it <container> python3 manage.py createsuperuser",
|
|
"Drop documents into the consume folder for automatic import",
|
|
"Configure tags and correspondents for organization"
|
|
]
|
|
},
|
|
|
|
"audiobookshelf": {
|
|
name: "Audiobookshelf",
|
|
description: "Self-hosted audiobook and podcast server",
|
|
icon: "\uD83C\uDFA7",
|
|
logo: "/assets/audiobookshelf.png",
|
|
category: "Media",
|
|
popularity: 80,
|
|
difficulty: "Easy",
|
|
docker: {
|
|
image: "ghcr.io/advplyr/audiobookshelf:latest",
|
|
ports: ["{{PORT}}:80"],
|
|
volumes: [
|
|
"/opt/audiobookshelf/config:/config",
|
|
"/opt/audiobookshelf/metadata:/metadata",
|
|
"{{MEDIA_PATH}}:/audiobooks"
|
|
],
|
|
environment: {}
|
|
},
|
|
subdomain: "audiobooks",
|
|
defaultPort: 13378,
|
|
healthCheck: "/",
|
|
subpathSupport: 'strip',
|
|
mediaMount: {
|
|
required: true,
|
|
containerPath: "/audiobooks",
|
|
label: "Audiobook Library",
|
|
description: "Folder containing your audiobooks and podcasts",
|
|
defaultPath: "/media/audiobooks"
|
|
},
|
|
setupInstructions: [
|
|
"Create your account on first access",
|
|
"Add your audiobook library folders",
|
|
"Download the mobile app for offline listening"
|
|
]
|
|
},
|
|
|
|
"calibre-web": {
|
|
name: "Calibre-Web",
|
|
description: "Web-based ebook manager and reader",
|
|
icon: "\uD83D\uDCD6",
|
|
logo: "/assets/calibre-web.png",
|
|
category: "Media",
|
|
popularity: 74,
|
|
difficulty: "Intermediate",
|
|
docker: {
|
|
image: "lscr.io/linuxserver/calibre-web:latest",
|
|
ports: ["{{PORT}}:8083"],
|
|
volumes: [
|
|
"/opt/calibre-web/config:/config",
|
|
"{{MEDIA_PATH}}:/books"
|
|
],
|
|
environment: {
|
|
"PUID": "1000",
|
|
"PGID": "1000",
|
|
"TZ": "{{TIMEZONE}}"
|
|
}
|
|
},
|
|
subdomain: "books",
|
|
defaultPort: 8083,
|
|
healthCheck: "/",
|
|
subpathSupport: 'strip',
|
|
mediaMount: {
|
|
required: true,
|
|
containerPath: "/books",
|
|
label: "Ebook Library",
|
|
description: "Folder containing your Calibre library (with metadata.db)",
|
|
defaultPath: "/media/books"
|
|
},
|
|
setupInstructions: [
|
|
"Default login: admin / admin123",
|
|
"Point to your Calibre database location on first setup",
|
|
"Supports EPUB, PDF, MOBI, and more formats"
|
|
]
|
|
},
|
|
|
|
"komga": {
|
|
name: "Komga",
|
|
description: "Comic and manga media server with web reader",
|
|
icon: "\uD83D\uDCDA",
|
|
logo: "/assets/komga.png",
|
|
category: "Media",
|
|
popularity: 70,
|
|
difficulty: "Easy",
|
|
docker: {
|
|
image: "gotson/komga:latest",
|
|
ports: ["{{PORT}}:25600"],
|
|
volumes: [
|
|
"/opt/komga/config:/config",
|
|
"{{MEDIA_PATH}}:/data"
|
|
],
|
|
environment: {
|
|
"TZ": "{{TIMEZONE}}"
|
|
}
|
|
},
|
|
subdomain: "komga",
|
|
defaultPort: 25600,
|
|
healthCheck: "/",
|
|
subpathSupport: 'strip',
|
|
mediaMount: {
|
|
required: true,
|
|
containerPath: "/data",
|
|
label: "Comics Library",
|
|
description: "Folder containing your comics and manga",
|
|
defaultPath: "/media/comics"
|
|
},
|
|
setupInstructions: [
|
|
"Create admin account on first access",
|
|
"Add your comic libraries (CBZ, CBR, PDF supported)",
|
|
"Use OPDS for third-party reader apps"
|
|
]
|
|
},
|
|
|
|
"kavita": {
|
|
name: "Kavita",
|
|
description: "Digital reading platform for manga, comics, and books",
|
|
icon: "\uD83D\uDCD6",
|
|
logo: "/assets/kavita.png",
|
|
category: "Media",
|
|
popularity: 72,
|
|
difficulty: "Easy",
|
|
docker: {
|
|
image: "jvmilazz0/kavita:latest",
|
|
ports: ["{{PORT}}:5000"],
|
|
volumes: [
|
|
"/opt/kavita/config:/kavita/config",
|
|
"{{MEDIA_PATH}}:/data"
|
|
],
|
|
environment: {}
|
|
},
|
|
subdomain: "kavita",
|
|
defaultPort: 5004,
|
|
healthCheck: "/",
|
|
subpathSupport: 'strip',
|
|
mediaMount: {
|
|
required: true,
|
|
containerPath: "/data",
|
|
label: "Reading Library",
|
|
description: "Folder containing your manga, comics, and ebooks",
|
|
defaultPath: "/media/reading"
|
|
},
|
|
setupInstructions: [
|
|
"Create admin account on first access",
|
|
"Add library folders for manga, comics, or books",
|
|
"Supports EPUB, PDF, CBZ, CBR formats"
|
|
]
|
|
},
|
|
|
|
"trilium": {
|
|
name: "Trilium Notes",
|
|
description: "Hierarchical knowledge base and note-taking app",
|
|
icon: "\uD83D\uDDD2\uFE0F",
|
|
logo: "/assets/trilium.png",
|
|
category: "Productivity",
|
|
popularity: 75,
|
|
difficulty: "Easy",
|
|
docker: {
|
|
image: "zadam/trilium:latest",
|
|
ports: ["{{PORT}}:8080"],
|
|
volumes: [
|
|
"/opt/trilium/data:/home/node/trilium-data"
|
|
],
|
|
environment: {}
|
|
},
|
|
subdomain: "notes",
|
|
defaultPort: 8085,
|
|
healthCheck: "/",
|
|
subpathSupport: 'strip',
|
|
setupInstructions: [
|
|
"Set your password on first access",
|
|
"Organize notes in a tree hierarchy",
|
|
"Supports rich text, code blocks, math equations, and diagrams"
|
|
]
|
|
},
|
|
|
|
"excalidraw": {
|
|
name: "Excalidraw",
|
|
description: "Collaborative virtual whiteboard for sketching and diagrams",
|
|
icon: "\uD83C\uDFA8",
|
|
logo: "/assets/excalidraw.png",
|
|
category: "Productivity",
|
|
popularity: 73,
|
|
difficulty: "Easy",
|
|
docker: {
|
|
image: "excalidraw/excalidraw:latest",
|
|
ports: ["{{PORT}}:80"],
|
|
volumes: [],
|
|
environment: {}
|
|
},
|
|
subdomain: "draw",
|
|
defaultPort: 8086,
|
|
healthCheck: "/",
|
|
subpathSupport: 'strip',
|
|
setupInstructions: [
|
|
"Start drawing immediately - no account needed",
|
|
"Share drawings via link for real-time collaboration",
|
|
"Export as PNG, SVG, or Excalidraw file"
|
|
]
|
|
},
|
|
|
|
"it-tools": {
|
|
name: "IT Tools",
|
|
description: "Collection of handy developer and IT tools in one place",
|
|
icon: "\uD83E\uDDF0",
|
|
logo: "/assets/it-tools.png",
|
|
category: "Utilities",
|
|
popularity: 79,
|
|
difficulty: "Easy",
|
|
docker: {
|
|
image: "corentinth/it-tools:latest",
|
|
ports: ["{{PORT}}:80"],
|
|
volumes: [],
|
|
environment: {}
|
|
},
|
|
subdomain: "tools",
|
|
defaultPort: 8087,
|
|
healthCheck: "/",
|
|
subpathSupport: 'strip',
|
|
setupInstructions: [
|
|
"Access the web interface for instant tools access",
|
|
"Includes: hash generators, UUID, JWT decoder, base64, regex tester, and 70+ more",
|
|
"No configuration needed"
|
|
]
|
|
},
|
|
|
|
"dozzle": {
|
|
name: "Dozzle",
|
|
description: "Real-time Docker container log viewer",
|
|
icon: "\uD83D\uDCDC",
|
|
logo: "/assets/dozzle.png",
|
|
category: "Monitoring",
|
|
popularity: 77,
|
|
difficulty: "Easy",
|
|
docker: {
|
|
image: "amir20/dozzle:latest",
|
|
ports: ["{{PORT}}:8080"],
|
|
volumes: [
|
|
"/var/run/docker.sock:/var/run/docker.sock:ro"
|
|
],
|
|
environment: {}
|
|
},
|
|
subdomain: "logs",
|
|
defaultPort: 8088,
|
|
healthCheck: "/",
|
|
subpathSupport: 'strip',
|
|
setupInstructions: [
|
|
"View real-time logs from all running containers",
|
|
"Filter and search across container logs",
|
|
"No configuration needed - auto-discovers containers"
|
|
]
|
|
},
|
|
|
|
"watchtower": {
|
|
name: "Watchtower",
|
|
description: "Automatic Docker container image updates",
|
|
icon: "\uD83D\uDC53",
|
|
logo: "/assets/watchtower.png",
|
|
category: "Management",
|
|
popularity: 81,
|
|
difficulty: "Easy",
|
|
docker: {
|
|
image: "containrrr/watchtower:latest",
|
|
ports: ["{{PORT}}:8080"],
|
|
volumes: [
|
|
"/var/run/docker.sock:/var/run/docker.sock"
|
|
],
|
|
environment: {
|
|
"WATCHTOWER_CLEANUP": "true",
|
|
"WATCHTOWER_SCHEDULE": "0 0 4 * * *",
|
|
"WATCHTOWER_HTTP_API_METRICS": "true",
|
|
"WATCHTOWER_HTTP_API_TOKEN": "{{GENERATED_SECRET}}"
|
|
}
|
|
},
|
|
subdomain: "watchtower",
|
|
defaultPort: 8089,
|
|
healthCheck: "/v1/update",
|
|
subpathSupport: 'strip',
|
|
setupInstructions: [
|
|
"Watchtower checks for image updates daily at 4 AM by default",
|
|
"Customize schedule via WATCHTOWER_SCHEDULE (cron format)",
|
|
"Add labels to exclude specific containers from updates"
|
|
]
|
|
},
|
|
|
|
"authentik": {
|
|
name: "Authentik",
|
|
description: "Identity provider and single sign-on platform",
|
|
icon: "\uD83D\uDD10",
|
|
logo: "/assets/authentik.png",
|
|
category: "Security",
|
|
popularity: 80,
|
|
difficulty: "Advanced",
|
|
docker: {
|
|
image: "ghcr.io/goauthentik/server:latest",
|
|
ports: ["{{PORT}}:9000"],
|
|
volumes: [
|
|
"/opt/authentik/media:/media",
|
|
"/opt/authentik/templates:/templates"
|
|
],
|
|
environment: {
|
|
"AUTHENTIK_SECRET_KEY": "{{GENERATED_SECRET}}",
|
|
"AUTHENTIK_ERROR_REPORTING__ENABLED": "false"
|
|
}
|
|
},
|
|
subdomain: "auth",
|
|
defaultPort: 9010,
|
|
healthCheck: "/-/health/live/",
|
|
subpathSupport: 'strip',
|
|
setupInstructions: [
|
|
"Requires a PostgreSQL database and Redis instance",
|
|
"Consider deploying via the Dev Environment recipe for full stack",
|
|
"Set up flows for authentication, enrollment, and recovery",
|
|
"Configure OAuth2/OIDC providers for SSO with other apps"
|
|
]
|
|
},
|
|
|
|
"crowdsec": {
|
|
name: "CrowdSec",
|
|
description: "Collaborative intrusion prevention system",
|
|
icon: "\uD83D\uDEE1\uFE0F",
|
|
logo: "/assets/crowdsec.png",
|
|
category: "Security",
|
|
popularity: 74,
|
|
difficulty: "Intermediate",
|
|
docker: {
|
|
image: "crowdsecurity/crowdsec:latest",
|
|
ports: ["{{PORT}}:8080"],
|
|
volumes: [
|
|
"/opt/crowdsec/config:/etc/crowdsec",
|
|
"/opt/crowdsec/data:/var/lib/crowdsec/data",
|
|
"/var/log:/var/log:ro"
|
|
],
|
|
environment: {}
|
|
},
|
|
subdomain: "crowdsec",
|
|
defaultPort: 8091,
|
|
healthCheck: "/health",
|
|
subpathSupport: 'strip',
|
|
setupInstructions: [
|
|
"Register at app.crowdsec.net for community threat intelligence",
|
|
"Install bouncers on your reverse proxy for active blocking",
|
|
"CrowdSec analyzes logs and shares threat data with the community"
|
|
]
|
|
},
|
|
|
|
"minecraft": {
|
|
name: "Minecraft Server",
|
|
description: "Minecraft Java Edition dedicated server",
|
|
icon: "\u26CF\uFE0F",
|
|
logo: "/assets/minecraft.png",
|
|
category: "Gaming",
|
|
popularity: 85,
|
|
difficulty: "Easy",
|
|
docker: {
|
|
image: "itzg/minecraft-server:latest",
|
|
ports: ["{{PORT}}:25565"],
|
|
volumes: [
|
|
"/opt/minecraft/data:/data"
|
|
],
|
|
environment: {
|
|
"EULA": "TRUE",
|
|
"TYPE": "VANILLA",
|
|
"VERSION": "LATEST",
|
|
"MEMORY": "2G",
|
|
"MAX_PLAYERS": "20",
|
|
"MOTD": "DashCaddy Minecraft Server"
|
|
}
|
|
},
|
|
subdomain: "mc",
|
|
defaultPort: 25565,
|
|
healthCheck: null,
|
|
subpathSupport: 'none',
|
|
setupInstructions: [
|
|
"Server accepts the Minecraft EULA automatically",
|
|
"Connect with your Minecraft client to the server IP:port",
|
|
"Configure server.properties in the data volume for customization",
|
|
"Supports Vanilla, Paper, Forge, Fabric via TYPE environment variable"
|
|
]
|
|
},
|
|
|
|
"valheim": {
|
|
name: "Valheim Server",
|
|
description: "Valheim dedicated server for multiplayer Viking adventures",
|
|
icon: "\u2694\uFE0F",
|
|
logo: "/assets/valheim.png",
|
|
category: "Gaming",
|
|
popularity: 72,
|
|
difficulty: "Easy",
|
|
docker: {
|
|
image: "lloesche/valheim-server:latest",
|
|
ports: ["{{PORT}}:2456/udp", "2457:2457/udp", "2458:2458/udp"],
|
|
volumes: [
|
|
"/opt/valheim/config:/config",
|
|
"/opt/valheim/data:/opt/valheim"
|
|
],
|
|
environment: {
|
|
"SERVER_NAME": "DashCaddy Valheim",
|
|
"WORLD_NAME": "DashCaddyWorld",
|
|
"SERVER_PASS": "{{GENERATED_SECRET}}",
|
|
"SERVER_PUBLIC": "false"
|
|
}
|
|
},
|
|
subdomain: "valheim",
|
|
defaultPort: 2456,
|
|
healthCheck: null,
|
|
subpathSupport: 'none',
|
|
setupInstructions: [
|
|
"Connect via Steam: Add Server > IP:2456",
|
|
"Default server password is auto-generated (check environment variables)",
|
|
"World data is persisted in the data volume",
|
|
"Requires at least 4GB RAM for smooth operation"
|
|
]
|
|
}
|
|
};
|
|
|
|
// Template categories for organization
|
|
const TEMPLATE_CATEGORIES = {
|
|
"Media": { icon: "🎬", color: "#e74c3c" },
|
|
"Media Management": { icon: "📋", color: "#3498db" },
|
|
"Downloads": { icon: "⬇️", color: "#2ecc71" },
|
|
"Productivity": { icon: "📝", color: "#f39c12" },
|
|
"Development": { icon: "💻", color: "#9b59b6" },
|
|
"Management": { icon: "⚙️", color: "#34495e" },
|
|
"Monitoring": { icon: "📊", color: "#1abc9c" },
|
|
"Networking": { icon: "🌐", color: "#e67e22" },
|
|
"DNS": { icon: "🌐", color: "#3498db" },
|
|
"Files": { icon: "📁", color: "#3498db" },
|
|
"Communication": { icon: "💬", color: "#9b59b6" },
|
|
"Home Automation": { icon: "🏠", color: "#27ae60" },
|
|
"Database": { icon: "🗄️", color: "#8e44ad" },
|
|
"Security": { icon: "🔐", color: "#c0392b" },
|
|
"Photos": { icon: "📸", color: "#16a085" },
|
|
"Utilities": { icon: "\uD83D\uDEE0\uFE0F", color: "#7f8c8d" },
|
|
"Gaming": { icon: "\uD83C\uDFAE", color: "#e91e63" }
|
|
};
|
|
|
|
// Difficulty levels
|
|
const DIFFICULTY_LEVELS = {
|
|
"Easy": { color: "#2ecc71", description: "Quick setup, minimal configuration" },
|
|
"Intermediate": { color: "#f39c12", description: "Some configuration required" },
|
|
"Advanced": { color: "#e74c3c", description: "Complex setup, technical knowledge needed" }
|
|
};
|
|
|
|
module.exports = {
|
|
APP_TEMPLATES,
|
|
TEMPLATE_CATEGORIES,
|
|
DIFFICULTY_LEVELS
|
|
}; |