feat: split into separate files

This commit is contained in:
tonyaellie
2025-04-11 15:25:44 +00:00
parent c980ce679c
commit 1d941b148c
10 changed files with 1347 additions and 754 deletions

View File

@@ -0,0 +1,369 @@
import type { AppConfig, DockerServices } from "./types" // Assuming types are in a separate file
export function generateDockerCompose(config: AppConfig): string {
const services: DockerServices = {
homebox: {
image: config.rootless
? "ghcr.io/sysadminsmedia/homebox:latest-rootless"
: "ghcr.io/sysadminsmedia/homebox:latest",
container_name: "homebox",
restart: "always",
environment: [
`HBOX_LOG_LEVEL=${config.logLevel}`,
`HBOX_LOG_FORMAT=${config.logFormat}`,
`HBOX_WEB_MAX_FILE_UPLOAD=${config.maxFileUpload}`,
`HBOX_OPTIONS_ALLOW_ANALYTICS=${config.allowAnalytics}`,
`HBOX_OPTIONS_ALLOW_REGISTRATION=${config.allowRegistration}`,
`HBOX_OPTIONS_AUTO_INCREMENT_ASSET_ID=${config.autoIncrementAssetId}`,
`HBOX_OPTIONS_CHECK_GITHUB_RELEASE=${config.checkGithubRelease}`,
],
volumes: [],
},
}
// Configure homebox volumes based on storage type
if (config.storageConfig.homeboxStorage.type === "volume") {
services.homebox.volumes.push(
`${config.storageConfig.homeboxStorage.volumeName}:/data/`,
)
} else {
services.homebox.volumes.push(
`${config.storageConfig.homeboxStorage.directory}:/data/`,
)
}
// Configure ports based on HTTPS option
if (config.httpsOption === "none") {
services.homebox.ports = [`${config.port}:7745`]
} else {
// For HTTPS options, the proxy will handle the ports
services.homebox.expose = ["7745"]
}
// Add database configuration if PostgreSQL is selected
if (config.databaseType === "postgres") {
// Ensure environment array exists before pushing
if (!services.homebox.environment) {
services.homebox.environment = []
}
services.homebox.environment.push(
"HBOX_DATABASE_DRIVER=postgres",
`HBOX_DATABASE_HOST=${config.postgresConfig.host}`,
`HBOX_DATABASE_PORT=${config.postgresConfig.port}`,
`HBOX_DATABASE_USERNAME=${config.postgresConfig.username}`,
`HBOX_DATABASE_PASSWORD=${config.postgresConfig.password}`,
`HBOX_DATABASE_DATABASE=${config.postgresConfig.database}`,
)
// Add PostgreSQL service
services["postgres"] = {
image: "postgres:14",
container_name: "homebox-postgres",
restart: "always",
environment: [
`POSTGRES_USER=${config.postgresConfig.username}`,
`POSTGRES_PASSWORD=${config.postgresConfig.password}`,
`POSTGRES_DB=${config.postgresConfig.database}`,
],
volumes: [],
}
// Configure postgres volumes based on storage type
if (config.storageConfig.postgresStorage.type === "volume") {
services.postgres.volumes.push(
`${config.storageConfig.postgresStorage.volumeName}:/var/lib/postgresql/data`,
)
} else {
services.postgres.volumes.push(
`${config.storageConfig.postgresStorage.directory}:/var/lib/postgresql/data`,
)
}
}
// Add HTTPS configuration based on selected option
switch (config.httpsOption) {
case "traefik":
addTraefikConfig(services, config)
break
case "nginx":
addNginxConfig(services, config)
break
case "caddy":
addCaddyConfig(services, config)
break
case "cloudflared":
addCloudflaredConfig(services, config)
break
}
// Format the Docker Compose YAML
let dockerCompose = "# generated by homebox config generator v0.0.1\n\nservices:\n"
// Add services
Object.entries(services).forEach(([serviceName, serviceConfig]) => {
dockerCompose += ` ${serviceName}:\n`
Object.entries(serviceConfig).forEach(([key, value]) => {
if (Array.isArray(value)) {
dockerCompose += ` ${key}:\n`
value.forEach((item: string) => {
// Added type assertion for item
dockerCompose += ` - ${item}\n`
})
} else if (value !== undefined) {
// Check for undefined before adding
dockerCompose += ` ${key}: ${value}\n`
}
})
})
// Add volumes section if needed
const volumeNames: string[] = []
// Only add volumes that are configured as Docker volumes, not directories
if (config.storageConfig.homeboxStorage.type === "volume") {
volumeNames.push(config.storageConfig.homeboxStorage.volumeName)
}
if (
config.databaseType === "postgres" &&
config.storageConfig.postgresStorage.type === "volume"
) {
volumeNames.push(config.storageConfig.postgresStorage.volumeName)
}
// Add HTTPS-related volumes
if (
config.httpsOption === "traefik" &&
config.storageConfig.traefikStorage.type === "volume"
) {
volumeNames.push(config.storageConfig.traefikStorage.volumeName)
}
if (
config.httpsOption === "nginx" &&
config.storageConfig.nginxStorage.type === "volume"
) {
volumeNames.push(config.storageConfig.nginxStorage.volumeName)
}
if (
config.httpsOption === "caddy" &&
config.storageConfig.caddyStorage.type === "volume"
) {
volumeNames.push(config.storageConfig.caddyStorage.volumeName)
}
if (
config.httpsOption === "cloudflared" &&
config.storageConfig.cloudflaredStorage.type === "volume"
) {
volumeNames.push(config.storageConfig.cloudflaredStorage.volumeName)
}
if (volumeNames.length > 0) {
dockerCompose += "\nvolumes:\n"
volumeNames.forEach((volumeName: string) => {
dockerCompose += ` ${volumeName}:\n driver: local\n`
})
}
return dockerCompose
}
function addTraefikConfig(services: DockerServices, config: AppConfig): void {
// Add Traefik labels to Homebox
services.homebox.labels = [
"traefik.enable=true",
`traefik.http.routers.homebox.rule=Host(\`${config.traefikConfig.domain}\`)`,
"traefik.http.routers.homebox.entrypoints=websecure",
"traefik.http.routers.homebox.tls.certresolver=letsencrypt",
"traefik.http.services.homebox.loadbalancer.server.port=7745",
]
// Add Traefik service
services["traefik"] = {
image: "traefik:v2.10",
container_name: "homebox-traefik",
restart: "always",
ports: ["80:80", "443:443"],
command: [
"--api.insecure=false",
"--providers.docker=true",
"--providers.docker.exposedbydefault=false",
"--entrypoints.web.address=:80",
"--entrypoints.web.http.redirections.entrypoint.to=websecure",
"--entrypoints.web.http.redirections.entrypoint.scheme=https",
"--entrypoints.websecure.address=:443",
"--certificatesresolvers.letsencrypt.acme.tlschallenge=true",
`--certificatesresolvers.letsencrypt.acme.email=${config.traefikConfig.email}`,
"--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json",
],
volumes: ["/var/run/docker.sock:/var/run/docker.sock:ro"],
}
// Configure traefik volumes based on storage type
if (config.storageConfig.traefikStorage.type === "volume") {
services.traefik.volumes.push(
`${config.storageConfig.traefikStorage.volumeName}:/letsencrypt`,
)
} else {
services.traefik.volumes.push(
`${config.storageConfig.traefikStorage.directory}:/letsencrypt`,
)
}
}
function addNginxConfig(services: DockerServices, config: AppConfig): void {
// Add Nginx service
services["nginx"] = {
image: "nginx:latest",
container_name: "homebox-nginx",
restart: "always",
ports: [`${config.nginxConfig.port}:443`, "80:80"],
volumes: [],
depends_on: ["homebox"],
}
// Configure nginx volumes based on storage type
if (config.storageConfig.nginxStorage.type === "volume") {
services.nginx.volumes.push(
`${config.storageConfig.nginxStorage.volumeName}/conf.d:/etc/nginx/conf.d`,
)
services.nginx.volumes.push(
`${config.storageConfig.nginxStorage.volumeName}/ssl:/etc/nginx/ssl`,
)
} else {
services.nginx.volumes.push(
`${config.storageConfig.nginxStorage.directory}/conf.d:/etc/nginx/conf.d`,
)
services.nginx.volumes.push(
`${config.storageConfig.nginxStorage.directory}/ssl:/etc/nginx/ssl`,
)
}
// Add default Nginx configuration path (assuming the file exists)
const nginxConfVolume =
config.storageConfig.nginxStorage.type === "volume"
? `${config.storageConfig.nginxStorage.volumeName}/conf.d/default.conf:/etc/nginx/conf.d/default.conf`
: `${config.storageConfig.nginxStorage.directory}/conf.d/default.conf:/etc/nginx/conf.d/default.conf`
services.nginx.volumes.push(nginxConfVolume)
// Add comments via environment variables (Docker Compose doesn't support comments directly in YAML this way)
services.nginx.environment = [
"# You need to create SSL certificates and place them in the SSL directory",
`# Certificate path: ${config.nginxConfig.sslCertPath}`,
`# Key path: ${config.nginxConfig.sslKeyPath}`,
"# Then create a default.conf file in the conf.d directory with the following content:",
"# server {",
"# listen 80;",
`# server_name ${config.nginxConfig.domain};`,
"# return 301 https://$host$request_uri;",
"# }",
"# server {",
"# listen 443 ssl;",
`# server_name ${config.nginxConfig.domain};`,
`# ssl_certificate ${config.nginxConfig.sslCertPath};`,
`# ssl_certificate_key ${config.nginxConfig.sslKeyPath};`,
"# location / {",
"# proxy_pass http://homebox:7745;",
"# proxy_set_header Host $host;",
"# proxy_set_header X-Real-IP $remote_addr;",
"# }",
"# }",
]
}
function addCaddyConfig(services: DockerServices, config: AppConfig): void {
// Add Caddy service
services["caddy"] = {
image: "caddy:latest",
container_name: "homebox-caddy",
restart: "always",
ports: ["80:80", "443:443"],
volumes: [],
depends_on: ["homebox"],
}
// Configure caddy volumes based on storage type
if (config.storageConfig.caddyStorage.type === "volume") {
services.caddy.volumes.push(
`${config.storageConfig.caddyStorage.volumeName}/data:/data`,
)
services.caddy.volumes.push(
`${config.storageConfig.caddyStorage.volumeName}/config:/config`,
)
services.caddy.volumes.push(
`${config.storageConfig.caddyStorage.volumeName}/Caddyfile:/etc/caddy/Caddyfile`,
)
} else {
services.caddy.volumes.push(
`${config.storageConfig.caddyStorage.directory}/data:/data`,
)
services.caddy.volumes.push(
`${config.storageConfig.caddyStorage.directory}/config:/config`,
)
services.caddy.volumes.push(
`${config.storageConfig.caddyStorage.directory}/Caddyfile:/etc/caddy/Caddyfile`,
)
}
// Add environment variables for Caddy comments and potential ACME config
services.caddy.environment = [
`# Create a Caddyfile in ${config.storageConfig.caddyStorage.type === "volume" ? config.storageConfig.caddyStorage.volumeName : config.storageConfig.caddyStorage.directory} with the following content:`,
`# ${config.caddyConfig.domain} {`,
"# reverse_proxy homebox:7745",
"# }",
]
// Add email if provided for ACME
if (config.caddyConfig.email) {
// Ensure environment array exists
if (!services.caddy.environment) {
services.caddy.environment = []
}
services.caddy.environment.push(`ACME_AGREE=true`) // Note: Caddy v2 doesn't use ACME_AGREE env var, email is set in Caddyfile
services.caddy.environment.push(`EMAIL=${config.caddyConfig.email}`) // This might be useful for scripting but Caddy reads email from Caddyfile
services.caddy.environment.push(
`# Add 'email ${config.caddyConfig.email}' to your Caddyfile for automatic HTTPS`,
)
}
}
function addCloudflaredConfig(
services: DockerServices,
config: AppConfig,
): void {
// Add Cloudflared service
services["cloudflared"] = {
image: "cloudflare/cloudflared:latest",
container_name: "homebox-cloudflared",
restart: "always",
command: ["tunnel", "--no-autoupdate", "run"],
volumes: [],
environment: [`TUNNEL_TOKEN=${config.cloudflaredConfig.token}`],
depends_on: ["homebox"],
}
// Configure cloudflared volumes based on storage type
if (config.storageConfig.cloudflaredStorage.type === "volume") {
services.cloudflared.volumes.push(
`${config.storageConfig.cloudflaredStorage.volumeName}:/etc/cloudflared`,
)
} else {
services.cloudflared.volumes.push(
`${config.storageConfig.cloudflaredStorage.directory}:/etc/cloudflared`,
)
}
// Add comments via environment variables
// Ensure environment array exists
if (!services.cloudflared.environment) {
services.cloudflared.environment = []
}
services.cloudflared.environment.push(
"# Create a tunnel in the Cloudflare Zero Trust dashboard",
`# Configure DNS for ${config.cloudflaredConfig.domain} to point to your tunnel`,
"# Add a public hostname in the tunnel configuration pointing to http://homebox:7745",
)
}