6.7 KiB
6.7 KiB
Certificate Management in SmartProxy v19+
Overview
SmartProxy v19+ enhances certificate management with support for both global and route-level ACME configuration. This guide covers the updated certificate management system, which now supports flexible configuration hierarchies.
Key Changes from Previous Versions
v19.0.0 Changes
- Global ACME configuration: Set default ACME settings for all routes with
certificate: 'auto'
- Configuration hierarchy: Top-level ACME settings serve as defaults, route-level settings override
- Better error messages: Clear guidance when ACME configuration is missing
- Improved validation: Configuration validation warns about common issues
v18.0.0 Changes (from v17)
- No backward compatibility: Clean break from the legacy certificate system
- No separate Port80Handler: ACME challenges handled as regular SmartProxy routes
- Unified route-based configuration: Certificates configured directly in route definitions
- Direct integration with @push.rocks/smartacme: Leverages SmartAcme's built-in capabilities
Configuration
Global ACME Configuration (New in v19+)
Set default ACME settings at the top level that apply to all routes with certificate: 'auto'
:
const proxy = new SmartProxy({
// Global ACME defaults
acme: {
email: 'ssl@example.com', // Required for Let's Encrypt
useProduction: false, // Use staging by default
port: 80, // Port for HTTP-01 challenges
renewThresholdDays: 30, // Renew 30 days before expiry
certificateStore: './certs', // Certificate storage directory
autoRenew: true, // Enable automatic renewal
renewCheckIntervalHours: 24 // Check for renewals daily
},
routes: [
// Routes using certificate: 'auto' will inherit global settings
{
name: 'website',
match: { ports: 443, domains: 'example.com' },
action: {
type: 'forward',
target: { host: 'localhost', port: 8080 },
tls: {
mode: 'terminate',
certificate: 'auto' // Uses global ACME configuration
}
}
}
]
});
Route-Level Certificate Configuration
Certificates are now configured at the route level using the tls
property:
const route: IRouteConfig = {
name: 'secure-website',
match: {
ports: 443,
domains: ['example.com', 'www.example.com']
},
action: {
type: 'forward',
target: { host: 'localhost', port: 8080 },
tls: {
mode: 'terminate',
certificate: 'auto', // Use ACME (Let's Encrypt)
acme: {
email: 'admin@example.com',
useProduction: true,
renewBeforeDays: 30
}
}
}
};
Static Certificate Configuration
For manually managed certificates:
const route: IRouteConfig = {
name: 'api-endpoint',
match: {
ports: 443,
domains: 'api.example.com'
},
action: {
type: 'forward',
target: { host: 'localhost', port: 9000 },
tls: {
mode: 'terminate',
certificate: {
certFile: './certs/api.crt',
keyFile: './certs/api.key',
ca: '...' // Optional CA chain
}
}
}
};
TLS Modes
SmartProxy supports three TLS modes:
- terminate: Decrypt TLS at the proxy and forward plain HTTP
- passthrough: Pass encrypted TLS traffic directly to the backend
- terminate-and-reencrypt: Decrypt at proxy, then re-encrypt to backend
Certificate Storage
Certificates are stored in the ./certs
directory by default:
./certs/
├── route-name/
│ ├── cert.pem
│ ├── key.pem
│ ├── ca.pem (if available)
│ └── meta.json
ACME Integration
How It Works
- SmartProxy creates a high-priority route for ACME challenges
- When ACME server makes requests to
/.well-known/acme-challenge/*
, SmartProxy handles them automatically - Certificates are obtained and stored locally
- Automatic renewal checks every 12 hours
Configuration Options
export interface IRouteAcme {
email: string; // Contact email for ACME account
useProduction?: boolean; // Use production servers (default: false)
challengePort?: number; // Port for HTTP-01 challenges (default: 80)
renewBeforeDays?: number; // Days before expiry to renew (default: 30)
}
Advanced Usage
Manual Certificate Operations
// Get certificate status
const status = proxy.getCertificateStatus('route-name');
console.log(status);
// {
// domain: 'example.com',
// status: 'valid',
// source: 'acme',
// expiryDate: Date,
// issueDate: Date
// }
// Force certificate renewal
await proxy.renewCertificate('route-name');
// Manually provision a certificate
await proxy.provisionCertificate('route-name');
Events
SmartProxy emits certificate-related events:
proxy.on('certificate:issued', (event) => {
console.log(`New certificate for ${event.domain}`);
});
proxy.on('certificate:renewed', (event) => {
console.log(`Certificate renewed for ${event.domain}`);
});
proxy.on('certificate:expiring', (event) => {
console.log(`Certificate expiring soon for ${event.domain}`);
});
Migration from Previous Versions
Before (v17 and earlier)
// Old approach with Port80Handler
const smartproxy = new SmartProxy({
port: 443,
acme: {
enabled: true,
accountEmail: 'admin@example.com',
// ... other ACME options
}
});
// Certificate provisioning was automatic or via certProvisionFunction
After (v18+)
// New approach with route-based configuration
const smartproxy = new SmartProxy({
routes: [{
match: { ports: 443, domains: 'example.com' },
action: {
type: 'forward',
target: { host: 'localhost', port: 8080 },
tls: {
mode: 'terminate',
certificate: 'auto',
acme: {
email: 'admin@example.com',
useProduction: true
}
}
}
}]
});
Troubleshooting
Common Issues
- Certificate not provisioning: Ensure port 80 is accessible for ACME challenges
- ACME rate limits: Use staging environment for testing
- Permission errors: Ensure the certificate directory is writable
Debug Mode
Enable detailed logging to troubleshoot certificate issues:
const proxy = new SmartProxy({
enableDetailedLogging: true,
// ... other options
});
Best Practices
- Always test with staging ACME servers first
- Set up monitoring for certificate expiration
- Use meaningful route names for easier certificate management
- Store static certificates securely with appropriate permissions
- Implement certificate status monitoring in production