smartproxy/docs/certificate-management.md

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:

  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

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

  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:

const proxy = new SmartProxy({
  enableDetailedLogging: true,
  // ... other options
});

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