# 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'`: ```typescript 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: ```typescript 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: ```typescript 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: 1. **terminate**: Decrypt TLS at the proxy and forward plain HTTP 2. **passthrough**: Pass encrypted TLS traffic directly to the backend 3. **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 1. SmartProxy creates a high-priority route for ACME challenges 2. When ACME server makes requests to `/.well-known/acme-challenge/*`, SmartProxy handles them automatically 3. Certificates are obtained and stored locally 4. Automatic renewal checks every 12 hours ### Configuration Options ```typescript 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 ```typescript // 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: ```typescript 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) ```typescript // 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+) ```typescript // 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 1. **Certificate not provisioning**: Ensure port 80 is accessible for ACME challenges 2. **ACME rate limits**: Use staging environment for testing 3. **Permission errors**: Ensure the certificate directory is writable ### Debug Mode Enable detailed logging to troubleshoot certificate issues: ```typescript const proxy = new SmartProxy({ enableDetailedLogging: true, // ... other options }); ``` ## Dynamic Route Updates When routes are updated dynamically using `updateRoutes()`, SmartProxy maintains certificate management continuity: ```typescript // Update routes with new domains await proxy.updateRoutes([ { name: 'new-domain', match: { ports: 443, domains: 'newsite.example.com' }, action: { type: 'forward', target: { host: 'localhost', port: 8080 }, tls: { mode: 'terminate', certificate: 'auto' // Will use global ACME config } } } ]); ``` ### Important Notes on Route Updates 1. **Certificate Manager Recreation**: When routes are updated, the certificate manager is recreated to reflect the new configuration 2. **ACME Callbacks Preserved**: The ACME route update callback is automatically preserved during route updates 3. **Existing Certificates**: Certificates already provisioned are retained in the certificate store 4. **New Route Certificates**: New routes with `certificate: 'auto'` will trigger certificate provisioning ### Route Update Best Practices 1. **Batch Updates**: Update multiple routes in a single `updateRoutes()` call for efficiency 2. **Monitor Certificate Status**: Check certificate status after route updates 3. **Handle ACME Errors**: Implement error handling for certificate provisioning failures 4. **Test Updates**: Test route updates in staging environment first ## Best Practices 1. **Always test with staging ACME servers first** 2. **Set up monitoring for certificate expiration** 3. **Use meaningful route names for easier certificate management** 4. **Store static certificates securely with appropriate permissions** 5. **Implement certificate status monitoring in production** 6. **Batch route updates when possible to minimize disruption** 7. **Monitor certificate provisioning after route updates**