Use domain-based URLs for services instead of IP:port

- config.ts: Server uses localhost, client uses domain names (coolify.nuc.lan, etc.)
- Added serviceDomains mapping and getServiceUrl() helper
- services.ts: Updated getCoolifyUrl/getDozzleUrl to use domains
- fallbackServices now uses domain-based URLs where available

Works from anywhere via Tailscale (no subnet conflicts)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Alejandro Gutiérrez
2026-02-06 17:01:11 +01:00
parent 396b2c3ecf
commit f7c57ca4f0
2 changed files with 66 additions and 22 deletions

View File

@@ -1,22 +1,66 @@
// Server-side configuration (only available in API routes / server components)
// Note: Server runs on NUC, so it can use localhost or container names for internal access
export const serverConfig = {
coolifyToken: process.env.COOLIFY_API_TOKEN || '',
coolifyApiUrl: process.env.COOLIFY_API_URL || 'http://192.168.1.3:8000/api/v1',
coolifyApiUrl: process.env.COOLIFY_API_URL || 'http://localhost:8000/api/v1',
coolifyServerUuid: process.env.COOLIFY_SERVER_UUID || 'qk84w0goo4w48g4ggsoo0oss',
coolifyDbUrl: process.env.COOLIFY_DB_URL || '',
prometheusUrl: process.env.PROMETHEUS_URL || 'http://192.168.1.3:9091',
nodeExporterInstance: process.env.NODE_EXPORTER_INSTANCE || '192.168.1.3:9100',
prometheusUrl: process.env.PROMETHEUS_URL || 'http://localhost:9091',
nodeExporterInstance: process.env.NODE_EXPORTER_INSTANCE || 'localhost:9100',
nicDevice: process.env.NIC_DEVICE || 'eno1',
nucHost: process.env.NUC_HOST || '192.168.1.3',
nucHost: process.env.NUC_HOST || 'localhost',
};
// Client-side configuration (available everywhere via NEXT_PUBLIC_ prefix)
// Uses domain names for browser access (works via Tailscale from anywhere)
export const clientConfig = {
nucHost: process.env.NEXT_PUBLIC_NUC_HOST || '192.168.1.3',
coolifyUrl: process.env.NEXT_PUBLIC_COOLIFY_URL || 'http://192.168.1.3:8000',
// Primary domain-based URLs (preferred - work from anywhere)
coolifyUrl: process.env.NEXT_PUBLIC_COOLIFY_URL || 'http://coolify.nuc.lan',
grafanaUrl: process.env.NEXT_PUBLIC_GRAFANA_URL || 'http://grafana.nuc.lan',
dozzleUrl: process.env.NEXT_PUBLIC_DOZZLE_URL || 'http://dozzle.nuc.lan',
// Fallback host for services without domain routes
nucHost: process.env.NEXT_PUBLIC_NUC_HOST || '100.113.153.45',
// Coolify project identifiers
coolifyProjectUuid: process.env.NEXT_PUBLIC_COOLIFY_PROJECT_UUID || 'a8484ggc88c40w4g4k004ow0',
coolifyEnvUuid: process.env.NEXT_PUBLIC_COOLIFY_ENV_UUID || 'dckc0w4ko8s888c4gk84skoo',
grafanaUrl: process.env.NEXT_PUBLIC_GRAFANA_URL || 'http://192.168.1.3:3333',
dozzleUrl: process.env.NEXT_PUBLIC_DOZZLE_URL || 'http://192.168.1.3:9999',
dozzleHostId: process.env.NEXT_PUBLIC_DOZZLE_HOST_ID || '6c1738d9-6f12-4ed7-9293-70a91f407347',
};
// Domain mappings for services (used for generating URLs)
export const serviceDomains: Record<string, string> = {
coolify: 'http://coolify.nuc.lan',
gitea: 'http://gitea.nuc.lan',
outline: 'http://outline.nuc.lan',
files: 'http://files.nuc.lan',
filebrowser: 'http://files.nuc.lan',
mail: 'http://mail.nuc.lan',
snappymail: 'http://mail.nuc.lan',
vault: 'http://vault.nuc.lan',
vaultwarden: 'http://vault.nuc.lan',
homepage: 'http://homepage.nuc.lan',
grafana: 'http://grafana.nuc.lan',
dozzle: 'http://dozzle.nuc.lan',
};
/**
* Get the URL for a service, preferring domain-based URL if available
*/
export function getServiceUrl(serviceName: string, port?: number): string {
const lower = serviceName.toLowerCase();
// Check for domain mapping first
for (const [key, url] of Object.entries(serviceDomains)) {
if (lower.includes(key)) {
return url;
}
}
// Fallback to port-based URL
if (port) {
return `http://${clientConfig.nucHost}:${port}`;
}
return `http://${clientConfig.nucHost}`;
}

View File

@@ -20,14 +20,14 @@ export interface DiscoveredService extends Service {
}
export function getCoolifyUrl(service: DiscoveredService): string {
const base = process.env.NEXT_PUBLIC_COOLIFY_URL || 'http://192.168.1.3:8000';
const base = process.env.NEXT_PUBLIC_COOLIFY_URL || 'http://coolify.nuc.lan';
const project = process.env.NEXT_PUBLIC_COOLIFY_PROJECT_UUID || 'a8484ggc88c40w4g4k004ow0';
const env = process.env.NEXT_PUBLIC_COOLIFY_ENV_UUID || 'dckc0w4ko8s888c4gk84skoo';
return `${base}/project/${project}/environment/${env}/${service.resourceType}/${service.uuid}`;
}
export function getDozzleUrl(service?: DiscoveredService): string {
const base = process.env.NEXT_PUBLIC_DOZZLE_URL || 'http://192.168.1.3:9999';
const base = process.env.NEXT_PUBLIC_DOZZLE_URL || 'http://dozzle.nuc.lan';
const hostId = process.env.NEXT_PUBLIC_DOZZLE_HOST_ID || '6c1738d9-6f12-4ed7-9293-70a91f407347';
if (service?.container) {
return `${base}/container/${hostId}~${service.container}`;
@@ -43,30 +43,30 @@ export interface Bookmark {
description?: string;
}
import { clientConfig } from './config';
import { clientConfig, getServiceUrl } from './config';
const h = clientConfig.nucHost;
export const fallbackServices: Service[] = [
// Infrastructure
{ name: 'Coolify', url: `http://${h}:8000`, port: 8000, icon: 'server', category: 'infrastructure', description: 'Container deployment & management' },
{ name: 'Dozzle', url: `http://${h}:9999`, port: 9999, icon: 'scroll-text', category: 'infrastructure', description: 'Real-time Docker log viewer' },
// Infrastructure - prefer domain-based URLs
{ name: 'Coolify', url: 'http://coolify.nuc.lan', port: 8000, icon: 'server', category: 'infrastructure', description: 'Container deployment & management' },
{ name: 'Dozzle', url: 'http://dozzle.nuc.lan', port: 9999, icon: 'scroll-text', category: 'infrastructure', description: 'Real-time Docker log viewer' },
{ name: 'Playwriter Browser', url: `http://${h}:6081/vnc.html`, port: 6081, icon: 'monitor', category: 'infrastructure', description: 'Remote browser for automation' },
// Automation
{ name: 'n8n', url: `http://${h}:5678`, port: 5678, icon: 'workflow', category: 'automation', description: 'Workflow automation platform' },
// Development
{ name: 'Gitea', url: `http://${h}:3030`, port: 3030, icon: 'git-branch', category: 'development', description: 'Self-hosted Git service' },
// Development - prefer domain-based URLs
{ name: 'Gitea', url: 'http://gitea.nuc.lan', port: 3030, icon: 'git-branch', category: 'development', description: 'Self-hosted Git service' },
{ name: 'CloudBeaver', url: `http://${h}:8978`, port: 8978, icon: 'database', category: 'development', description: 'Database management UI' },
{ name: 'Adminer', url: `http://${h}:8088`, port: 8088, icon: 'table', category: 'development', description: 'Lightweight database admin' },
// Knowledge
{ name: 'Outline', url: `http://${h}:3080`, port: 3080, icon: 'book-open', category: 'knowledge', description: 'Team wiki & documentation' },
// Knowledge - prefer domain-based URLs
{ name: 'Outline', url: 'http://outline.nuc.lan', port: 3080, icon: 'book-open', category: 'knowledge', description: 'Team wiki & documentation' },
{ name: 'NocoDB', url: `http://${h}:8084`, port: 8084, icon: 'grid-3x3', category: 'knowledge', description: 'Airtable alternative database' },
// Storage
{ name: 'FileBrowser', url: `http://${h}:8085`, port: 8085, icon: 'folder', category: 'storage', description: 'Web file manager' },
// Storage - prefer domain-based URLs
{ name: 'FileBrowser', url: 'http://files.nuc.lan', port: 8085, icon: 'folder', category: 'storage', description: 'Web file manager' },
{ name: 'MinIO', url: `http://${h}:9001`, port: 9001, icon: 'hard-drive', category: 'storage', description: 'S3-compatible object storage' },
{ name: 'Kopia', url: `http://${h}:51515`, port: 51515, icon: 'archive', category: 'storage', description: 'Backup & restore' },
@@ -74,8 +74,8 @@ export const fallbackServices: Service[] = [
{ name: 'Uptime Kuma', url: `http://${h}:3001`, port: 3001, icon: 'activity', category: 'monitoring', description: 'Service status monitoring' },
{ name: 'Ntfy', url: `http://${h}:8333`, port: 8333, icon: 'bell', category: 'monitoring', description: 'Push notifications server' },
// Security
{ name: 'Vaultwarden', url: `http://${h}:8222`, port: 8222, icon: 'lock', category: 'security', description: 'Password manager' },
// Security - prefer domain-based URLs
{ name: 'Vaultwarden', url: 'http://vault.nuc.lan', port: 8222, icon: 'lock', category: 'security', description: 'Password manager' },
{ name: 'Authentik', url: `http://${h}:9090`, port: 9090, icon: 'shield', category: 'security', description: 'Identity provider & SSO' },
];