feat: replace onebox ingress with SmartProxy
This commit is contained in:
+39
-42
@@ -1,8 +1,8 @@
|
||||
/**
|
||||
* Reverse Proxy for Onebox
|
||||
*
|
||||
* Delegates to Caddy (running as Docker service) for production-grade reverse proxy
|
||||
* with native SNI support, HTTP/2, WebSocket proxying, and zero-downtime configuration updates.
|
||||
* Delegates to SmartProxy (running as Docker service) for production-grade reverse proxy
|
||||
* with TLS termination, WebSocket proxying, and zero-downtime configuration updates.
|
||||
*
|
||||
* Routes use Docker service names (e.g., onebox-hello-world:80) for container-to-container
|
||||
* communication within the Docker overlay network.
|
||||
@@ -11,7 +11,7 @@
|
||||
import { logger } from '../logging.ts';
|
||||
import { getErrorMessage } from '../utils/error.ts';
|
||||
import { OneboxDatabase } from './database.ts';
|
||||
import { CaddyManager } from './caddy.ts';
|
||||
import { SmartProxyManager } from './smartproxy.ts';
|
||||
|
||||
interface IProxyRoute {
|
||||
domain: string;
|
||||
@@ -24,7 +24,7 @@ interface IProxyRoute {
|
||||
export class OneboxReverseProxy {
|
||||
private oneboxRef: any;
|
||||
private database: OneboxDatabase;
|
||||
private caddy: CaddyManager;
|
||||
private smartProxy: SmartProxyManager;
|
||||
private routes: Map<string, IProxyRoute> = new Map();
|
||||
private httpPort = 8080; // Default to dev ports (will be overridden if production)
|
||||
private httpsPort = 8443;
|
||||
@@ -32,33 +32,32 @@ export class OneboxReverseProxy {
|
||||
constructor(oneboxRef: any) {
|
||||
this.oneboxRef = oneboxRef;
|
||||
this.database = oneboxRef.database;
|
||||
this.caddy = new CaddyManager({
|
||||
this.smartProxy = new SmartProxyManager({
|
||||
httpPort: this.httpPort,
|
||||
httpsPort: this.httpsPort,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize reverse proxy - Caddy runs as Docker service, no setup needed
|
||||
* Initialize reverse proxy - SmartProxy runs as Docker service, no setup needed
|
||||
*/
|
||||
async init(): Promise<void> {
|
||||
logger.info('Reverse proxy initialized (Caddy Docker service)');
|
||||
logger.info('Reverse proxy initialized (SmartProxy Docker service)');
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the HTTP/HTTPS reverse proxy server
|
||||
* Caddy handles both HTTP and HTTPS on the configured ports
|
||||
* SmartProxy handles both HTTP and HTTPS on the configured ports
|
||||
*/
|
||||
async startHttp(port?: number): Promise<void> {
|
||||
if (port) {
|
||||
this.httpPort = port;
|
||||
this.caddy.setPorts(this.httpPort, this.httpsPort);
|
||||
this.smartProxy.setPorts(this.httpPort, this.httpsPort);
|
||||
}
|
||||
|
||||
try {
|
||||
// Start Caddy (handles both HTTP and HTTPS)
|
||||
await this.caddy.start();
|
||||
logger.success(`Reverse proxy started on port ${this.httpPort} (Caddy Docker service)`);
|
||||
await this.smartProxy.start();
|
||||
logger.success(`Reverse proxy started on port ${this.httpPort} (SmartProxy Docker service)`);
|
||||
} catch (error) {
|
||||
logger.error(`Failed to start reverse proxy: ${getErrorMessage(error)}`);
|
||||
throw error;
|
||||
@@ -66,21 +65,19 @@ export class OneboxReverseProxy {
|
||||
}
|
||||
|
||||
/**
|
||||
* Start HTTPS - Caddy already handles HTTPS when started
|
||||
* Start HTTPS - SmartProxy already handles HTTPS when started
|
||||
* This method exists for interface compatibility
|
||||
*/
|
||||
async startHttps(port?: number): Promise<void> {
|
||||
if (port) {
|
||||
this.httpsPort = port;
|
||||
this.caddy.setPorts(this.httpPort, this.httpsPort);
|
||||
this.smartProxy.setPorts(this.httpPort, this.httpsPort);
|
||||
}
|
||||
// Caddy handles both HTTP and HTTPS together
|
||||
// If already running, just log and optionally reload with new port
|
||||
const status = this.caddy.getStatus();
|
||||
const status = this.smartProxy.getStatus();
|
||||
if (status.running) {
|
||||
logger.info(`HTTPS already running on port ${this.httpsPort} via Caddy`);
|
||||
logger.info(`HTTPS already running on port ${this.httpsPort} via SmartProxy`);
|
||||
} else {
|
||||
await this.caddy.start();
|
||||
await this.smartProxy.start();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,13 +85,13 @@ export class OneboxReverseProxy {
|
||||
* Stop the reverse proxy
|
||||
*/
|
||||
async stop(): Promise<void> {
|
||||
await this.caddy.stop();
|
||||
await this.smartProxy.stop();
|
||||
logger.info('Reverse proxy stopped');
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a route for a service
|
||||
* Uses Docker service name for upstream (Caddy runs in same Docker network)
|
||||
* Uses Docker service name for upstream (SmartProxy runs in same Docker network)
|
||||
*/
|
||||
async addRoute(serviceId: number, domain: string, targetPort: number): Promise<void> {
|
||||
try {
|
||||
@@ -105,7 +102,7 @@ export class OneboxReverseProxy {
|
||||
}
|
||||
|
||||
// Use Docker service name as upstream target
|
||||
// Caddy runs on the same Docker network, so it can resolve service names directly
|
||||
// SmartProxy runs on the same Docker network, so it can resolve service names directly
|
||||
const serviceName = `onebox-${service.name}`;
|
||||
const targetHost = serviceName;
|
||||
|
||||
@@ -119,9 +116,9 @@ export class OneboxReverseProxy {
|
||||
|
||||
this.routes.set(domain, route);
|
||||
|
||||
// Add route to Caddy using Docker service name
|
||||
// Add route to SmartProxy using Docker service name
|
||||
const upstream = `${targetHost}:${targetPort}`;
|
||||
await this.caddy.addRoute(domain, upstream);
|
||||
await this.smartProxy.addRoute(domain, upstream);
|
||||
|
||||
logger.success(`Added proxy route: ${domain} -> ${upstream}`);
|
||||
} catch (error) {
|
||||
@@ -135,9 +132,9 @@ export class OneboxReverseProxy {
|
||||
*/
|
||||
removeRoute(domain: string): void {
|
||||
if (this.routes.delete(domain)) {
|
||||
// Remove from Caddy (async but we don't wait)
|
||||
this.caddy.removeRoute(domain).catch((error) => {
|
||||
logger.error(`Failed to remove Caddy route for ${domain}: ${getErrorMessage(error)}`);
|
||||
// Remove from SmartProxy (async but we don't wait)
|
||||
this.smartProxy.removeRoute(domain).catch((error) => {
|
||||
logger.error(`Failed to remove SmartProxy route for ${domain}: ${getErrorMessage(error)}`);
|
||||
});
|
||||
logger.success(`Removed proxy route: ${domain}`);
|
||||
} else {
|
||||
@@ -159,9 +156,9 @@ export class OneboxReverseProxy {
|
||||
try {
|
||||
logger.info('Reloading proxy routes...');
|
||||
|
||||
// Clear local and Caddy routes
|
||||
// Clear local and SmartProxy routes
|
||||
this.routes.clear();
|
||||
this.caddy.clear();
|
||||
this.smartProxy.clear();
|
||||
|
||||
const services = this.database.getAllServices();
|
||||
|
||||
@@ -181,7 +178,7 @@ export class OneboxReverseProxy {
|
||||
|
||||
/**
|
||||
* Add TLS certificate for a domain
|
||||
* Sends PEM content to Caddy via Admin API
|
||||
* Sends PEM content to SmartProxy via Admin API
|
||||
*/
|
||||
async addCertificate(domain: string, certPem: string, keyPem: string): Promise<void> {
|
||||
if (!certPem || !keyPem) {
|
||||
@@ -189,14 +186,14 @@ export class OneboxReverseProxy {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.caddy.addCertificate(domain, certPem, keyPem);
|
||||
await this.smartProxy.addCertificate(domain, certPem, keyPem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove TLS certificate for a domain
|
||||
*/
|
||||
removeCertificate(domain: string): void {
|
||||
this.caddy.removeCertificate(domain).catch((error) => {
|
||||
this.smartProxy.removeCertificate(domain).catch((error) => {
|
||||
logger.error(`Failed to remove certificate for ${domain}: ${getErrorMessage(error)}`);
|
||||
});
|
||||
}
|
||||
@@ -213,13 +210,13 @@ export class OneboxReverseProxy {
|
||||
for (const cert of certificates) {
|
||||
// Use fullchainPem for the cert (includes intermediates) and keyPem for the key
|
||||
if (cert.domain && cert.fullchainPem && cert.keyPem) {
|
||||
await this.caddy.addCertificate(cert.domain, cert.fullchainPem, cert.keyPem);
|
||||
await this.smartProxy.addCertificate(cert.domain, cert.fullchainPem, cert.keyPem);
|
||||
} else {
|
||||
logger.warn(`Skipping certificate for ${cert.domain}: missing PEM content`);
|
||||
}
|
||||
}
|
||||
|
||||
logger.success(`Loaded ${this.caddy.getCertificates().length} TLS certificates`);
|
||||
logger.success(`Loaded ${this.smartProxy.getCertificates().length} TLS certificates`);
|
||||
} catch (error) {
|
||||
logger.error(`Failed to reload certificates: ${getErrorMessage(error)}`);
|
||||
throw error;
|
||||
@@ -230,19 +227,19 @@ export class OneboxReverseProxy {
|
||||
* Get status of reverse proxy
|
||||
*/
|
||||
getStatus() {
|
||||
const caddyStatus = this.caddy.getStatus();
|
||||
const smartProxyStatus = this.smartProxy.getStatus();
|
||||
return {
|
||||
http: {
|
||||
running: caddyStatus.running,
|
||||
port: caddyStatus.httpPort,
|
||||
running: smartProxyStatus.running,
|
||||
port: smartProxyStatus.httpPort,
|
||||
},
|
||||
https: {
|
||||
running: caddyStatus.running,
|
||||
port: caddyStatus.httpsPort,
|
||||
certificates: caddyStatus.certificates,
|
||||
running: smartProxyStatus.running,
|
||||
port: smartProxyStatus.httpsPort,
|
||||
certificates: smartProxyStatus.certificates,
|
||||
},
|
||||
routes: caddyStatus.routes,
|
||||
backend: 'caddy-docker',
|
||||
routes: smartProxyStatus.routes,
|
||||
backend: 'smartproxy-docker',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user