3.2 KiB
ACME Certificate Provisioning Timing Fix (v19.3.9)
Problem Description
In SmartProxy v19.3.8 and earlier, ACME certificate provisioning would start immediately during SmartProxy initialization, before the required ports were actually listening. This caused ACME HTTP-01 challenges to fail because the challenge port (typically port 80) was not ready to accept connections when Let's Encrypt tried to validate the challenge.
Root Cause
The certificate manager was initialized and immediately started provisioning certificates as part of the SmartProxy startup sequence:
- SmartProxy.start() called
- Certificate manager initialized
- Certificate provisioning started immediately (including ACME challenges)
- Port listeners started afterwards
- ACME challenges would fail because port 80 wasn't listening yet
This race condition meant that when Let's Encrypt tried to connect to port 80 to validate the HTTP-01 challenge, the connection would be refused.
Solution
The fix defers certificate provisioning until after all ports are listening and ready:
Changes to SmartCertManager
// Modified initialize() to skip automatic provisioning
public async initialize(): Promise<void> {
// ... initialization code ...
// Skip automatic certificate provisioning during initialization
console.log('Certificate manager initialized. Deferring certificate provisioning until after ports are listening.');
// Start renewal timer
this.startRenewalTimer();
}
// Made provisionAllCertificates public to allow direct calling after ports are ready
public async provisionAllCertificates(): Promise<void> {
// ... certificate provisioning code ...
}
Changes to SmartProxy
public async start() {
// ... initialization code ...
// Start port listeners using the PortManager
await this.portManager.addPorts(listeningPorts);
// Now that ports are listening, provision any required certificates
if (this.certManager) {
console.log('Starting certificate provisioning now that ports are ready');
await this.certManager.provisionAllCertificates();
}
// ... rest of startup code ...
}
Timing Sequence
Before (v19.3.8 and earlier)
- Initialize certificate manager
- Start ACME provisioning immediately
- ACME challenge fails (port not ready)
- Start port listeners
- Port 80 now listening (too late)
After (v19.3.9)
- Initialize certificate manager (provisioning deferred)
- Start port listeners
- Port 80 now listening
- Start ACME provisioning
- ACME challenge succeeds
Configuration
No configuration changes are required. The timing fix is automatic and transparent to users.
Testing
The fix is verified by the test in test/test.acme-timing-simple.ts
which ensures:
- Certificate manager is initialized first
- Ports start listening
- Certificate provisioning happens only after ports are ready
Impact
This fix ensures that:
- ACME HTTP-01 challenges succeed on first attempt
- No more "connection refused" errors during certificate provisioning
- Certificate acquisition is more reliable
- No manual retries needed for failed challenges
Migration
Simply update to SmartProxy v19.3.9 or later. The fix is backward compatible and requires no changes to existing code or configuration.