Files
dashcaddy/dashcaddy-api/app-templates.js

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: [
"/opt/filebrowser/data:/srv",
"/opt/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
};