126 lines
3.6 KiB
Markdown
126 lines
3.6 KiB
Markdown
# Port 80 ACME Management in SmartProxy
|
|
|
|
## Overview
|
|
|
|
SmartProxy correctly handles port management when both user routes and ACME challenges need to use the same port (typically port 80). This document explains how the system prevents port conflicts and EADDRINUSE errors.
|
|
|
|
## Port Deduplication
|
|
|
|
SmartProxy's PortManager implements automatic port deduplication:
|
|
|
|
```typescript
|
|
public async addPort(port: number): Promise<void> {
|
|
// Check if we're already listening on this port
|
|
if (this.servers.has(port)) {
|
|
console.log(`PortManager: Already listening on port ${port}`);
|
|
return;
|
|
}
|
|
|
|
// Create server for this port...
|
|
}
|
|
```
|
|
|
|
This means that when both a user route and ACME challenges are configured to use port 80, the port is only opened once and shared between both use cases.
|
|
|
|
## ACME Challenge Route Flow
|
|
|
|
1. **Initialization**: When SmartProxy starts and detects routes with `certificate: 'auto'`, it initializes the certificate manager
|
|
2. **Challenge Route Creation**: The certificate manager creates a special challenge route on the configured ACME port (default 80)
|
|
3. **Route Update**: The challenge route is added via `updateRoutes()`, which triggers port allocation
|
|
4. **Deduplication**: If port 80 is already in use by a user route, the PortManager's deduplication prevents double allocation
|
|
5. **Shared Access**: Both user routes and ACME challenges share the same port listener
|
|
|
|
## Configuration Examples
|
|
|
|
### Shared Port (Recommended)
|
|
|
|
```typescript
|
|
const settings = {
|
|
routes: [
|
|
{
|
|
name: 'web-traffic',
|
|
match: {
|
|
ports: [80]
|
|
},
|
|
action: {
|
|
type: 'forward',
|
|
targetUrl: 'http://localhost:3000'
|
|
}
|
|
},
|
|
{
|
|
name: 'secure-traffic',
|
|
match: {
|
|
ports: [443]
|
|
},
|
|
action: {
|
|
type: 'forward',
|
|
targetUrl: 'https://localhost:3001',
|
|
tls: {
|
|
mode: 'terminate',
|
|
certificate: 'auto'
|
|
}
|
|
}
|
|
}
|
|
],
|
|
acme: {
|
|
email: 'your-email@example.com',
|
|
port: 80 // Same as user route - this is safe!
|
|
}
|
|
};
|
|
```
|
|
|
|
### Separate ACME Port
|
|
|
|
```typescript
|
|
const settings = {
|
|
routes: [
|
|
{
|
|
name: 'web-traffic',
|
|
match: {
|
|
ports: [80]
|
|
},
|
|
action: {
|
|
type: 'forward',
|
|
targetUrl: 'http://localhost:3000'
|
|
}
|
|
}
|
|
],
|
|
acme: {
|
|
email: 'your-email@example.com',
|
|
port: 8080 // Different port for ACME challenges
|
|
}
|
|
};
|
|
```
|
|
|
|
## Best Practices
|
|
|
|
1. **Use Default Port 80**: Let ACME use port 80 (the default) even if you have user routes on that port
|
|
2. **Priority Routing**: ACME challenge routes have high priority (1000) to ensure they take precedence
|
|
3. **Path-Based Routing**: ACME routes only match `/.well-known/acme-challenge/*` paths, avoiding conflicts
|
|
4. **Automatic Cleanup**: Challenge routes are automatically removed when not needed
|
|
|
|
## Troubleshooting
|
|
|
|
### EADDRINUSE Errors
|
|
|
|
If you see EADDRINUSE errors, check:
|
|
|
|
1. Is another process using the port?
|
|
2. Are you running multiple SmartProxy instances?
|
|
3. Is the previous instance still shutting down?
|
|
|
|
### Certificate Provisioning Issues
|
|
|
|
1. Ensure the ACME port is accessible from the internet
|
|
2. Check that DNS is properly configured for your domains
|
|
3. Verify email configuration in ACME settings
|
|
|
|
## Technical Details
|
|
|
|
The port deduplication is handled at multiple levels:
|
|
|
|
1. **PortManager Level**: Checks if port is already active before creating new listener
|
|
2. **RouteManager Level**: Tracks which ports are needed and updates accordingly
|
|
3. **Certificate Manager Level**: Adds challenge route only when needed
|
|
|
|
This multi-level approach ensures robust port management without conflicts. |