Encryption In Transit: TLS 1.3, Certificate Management & HSTS

When your ChatGPT app handles sensitive customer data—medical records, financial information, or personal conversations—that data travels across the internet between your servers and users. Without proper encryption in transit, malicious actors can intercept, read, or modify this information through man-in-the-middle attacks, packet sniffing, or session hijacking.

Transport Layer Security (TLS) 1.3 represents the gold standard for encrypting data in transit, offering faster handshakes, stronger cipher suites, and mandatory forward secrecy compared to older protocols. For ChatGPT applications built with MakeAIHQ's no-code platform, implementing enterprise-grade TLS encryption ensures that every API call, user authentication, and data exchange remains confidential and tamper-proof.

This guide provides production-ready implementations for TLS 1.3 server configuration, automated certificate management with Let's Encrypt, HTTP Strict Transport Security (HSTS) headers, certificate pinning strategies, and mutual TLS (mTLS) authentication. Whether you're deploying a healthcare ChatGPT assistant or a financial planning bot, these security measures protect your users' data from the moment it leaves their device until it reaches your server—and back again.

Modern browsers and API clients expect TLS encryption by default. Failing to implement proper encryption in transit can result in browser warnings, failed API requests, compliance violations (GDPR, HIPAA, PCI-DSS), and severe reputation damage. By following this comprehensive guide, you'll implement the same encryption standards used by major tech companies to protect billions of users daily.

TLS 1.3 Configuration: Modern Cipher Suites & Protocol Selection

TLS 1.3 eliminates legacy vulnerabilities found in TLS 1.2 by removing support for weak cipher suites (RC4, 3DES, CBC-mode ciphers), deprecated handshake mechanisms, and compression algorithms vulnerable to CRIME attacks. The protocol reduces handshake latency from two round-trips to one (0-RTT in resumption scenarios), making it ideal for real-time ChatGPT applications where every millisecond of response time matters.

For ChatGPT MCP servers handling authentication tokens, user messages, and API keys, TLS 1.3 provides mandatory perfect forward secrecy through ephemeral Diffie-Hellman (DHE) or elliptic-curve Diffie-Hellman (ECDHE) key exchanges. This ensures that even if your server's private key is compromised in the future, past encrypted sessions remain secure—critical for applications subject to data retention regulations.

When configuring TLS 1.3 for production, you must balance security with compatibility. While TLS 1.3-only configurations offer maximum security, supporting TLS 1.2 as a fallback ensures compatibility with older enterprise systems and government networks that may not have upgraded. The configuration below demonstrates a security-first approach suitable for ChatGPT applications processing sensitive data:

// tls-server.ts - Production TLS 1.3 Server Configuration
import https from 'https';
import fs from 'fs';
import express from 'express';
import helmet from 'helmet';

interface TLSConfig {
  minVersion: string;
  maxVersion: string;
  ciphers: string;
  honorCipherOrder: boolean;
  ecdhCurve: string;
}

class SecureTLSServer {
  private app: express.Application;
  private server: https.Server | null = null;

  constructor() {
    this.app = express();
    this.configureMiddleware();
    this.configureRoutes();
  }

  private configureMiddleware(): void {
    // Security headers via Helmet
    this.app.use(helmet({
      hsts: {
        maxAge: 31536000,
        includeSubDomains: true,
        preload: true
      },
      frameguard: { action: 'deny' },
      contentSecurityPolicy: {
        directives: {
          defaultSrc: ["'self'"],
          scriptSrc: ["'self'"],
          styleSrc: ["'self'", "'unsafe-inline'"],
          imgSrc: ["'self'", 'data:', 'https:'],
          connectSrc: ["'self'"],
          fontSrc: ["'self'"],
          objectSrc: ["'none'"],
          upgradeInsecureRequests: []
        }
      }
    }));

    // JSON body parser
    this.app.use(express.json({ limit: '10mb' }));
  }

  private configureRoutes(): void {
    // Health check endpoint
    this.app.get('/health', (req, res) => {
      const tlsVersion = (req.socket as any).getProtocol();
      const cipherSuite = (req.socket as any).getCipher();

      res.json({
        status: 'healthy',
        timestamp: new Date().toISOString(),
        tls: {
          version: tlsVersion,
          cipher: cipherSuite?.name,
          bits: cipherSuite?.bits
        }
      });
    });

    // ChatGPT MCP endpoint
    this.app.post('/mcp', (req, res) => {
      // Validate TLS connection
      if (!this.isSecureConnection(req)) {
        return res.status(400).json({
          error: 'Insecure connection rejected'
        });
      }

      // Process MCP request
      res.json({
        message: 'Secure MCP endpoint',
        encrypted: true
      });
    });
  }

  private isSecureConnection(req: express.Request): boolean {
    const tlsVersion = (req.socket as any).getProtocol();
    return tlsVersion === 'TLSv1.3' || tlsVersion === 'TLSv1.2';
  }

  public async start(port: number = 443): Promise<void> {
    const tlsConfig: TLSConfig = {
      minVersion: 'TLSv1.2', // Fallback for compatibility
      maxVersion: 'TLSv1.3', // Enforce latest
      // TLS 1.3 cipher suites (auto-selected by Node.js)
      // TLS 1.2 fallback ciphers (ECDHE + AES-GCM only)
      ciphers: [
        'TLS_AES_256_GCM_SHA384',
        'TLS_CHACHA20_POLY1305_SHA256',
        'TLS_AES_128_GCM_SHA256',
        'ECDHE-RSA-AES256-GCM-SHA384',
        'ECDHE-RSA-AES128-GCM-SHA256'
      ].join(':'),
      honorCipherOrder: true,
      ecdhCurve: 'auto' // Prefer X25519, fallback to P-256
    };

    const httpsOptions = {
      key: fs.readFileSync('/etc/letsencrypt/live/yourdomain.com/privkey.pem'),
      cert: fs.readFileSync('/etc/letsencrypt/live/yourdomain.com/fullchain.pem'),
      ...tlsConfig
    };

    this.server = https.createServer(httpsOptions, this.app);

    return new Promise((resolve, reject) => {
      this.server!.listen(port, () => {
        console.log(`✅ TLS 1.3 server running on port ${port}`);
        resolve();
      });

      this.server!.on('error', (error) => {
        console.error('❌ Server error:', error);
        reject(error);
      });
    });
  }

  public async stop(): Promise<void> {
    if (this.server) {
      return new Promise((resolve) => {
        this.server!.close(() => {
          console.log('✅ Server stopped gracefully');
          resolve();
        });
      });
    }
  }
}

// Usage
const server = new SecureTLSServer();
server.start(443).catch(console.error);

The cipher suite configuration prioritizes AEAD (Authenticated Encryption with Associated Data) modes like AES-GCM and ChaCha20-Poly1305, which provide both confidentiality and integrity protection in a single cryptographic operation. For ChatGPT applications, this prevents tampering attacks where adversaries modify encrypted API requests mid-flight.

Certificate Management: Let's Encrypt Automation & Wildcard Certificates

SSL/TLS certificates authenticate your server's identity and enable encrypted connections. Let's Encrypt provides free, automated certificates with 90-day validity periods, requiring robust renewal automation to prevent service disruptions. For ChatGPT applications hosted on custom domains or subdomains (e.g., chatbot.yourbusiness.com), wildcard certificates eliminate the need to provision individual certificates for each subdomain.

The challenge with Let's Encrypt automation lies in handling certificate renewal without downtime. Certbot's standalone mode requires stopping your web server to bind port 80/443 for validation, while webroot mode requires careful directory permissions. For production ChatGPT MCP servers, the DNS-01 challenge method offers zero-downtime renewals and supports wildcard certificates—essential for multi-tenant platforms where each customer gets a dedicated subdomain.

This automated certificate renewal service uses the DNS-01 challenge with Cloudflare DNS, implements certificate validation checks, and gracefully reloads your TLS server without dropping active connections:

#!/bin/bash
# certificate-renewal-service.sh - Automated Let's Encrypt Renewal with DNS-01

set -euo pipefail

# Configuration
DOMAIN="yourdomain.com"
WILDCARD_DOMAIN="*.yourdomain.com"
EMAIL="security@yourdomain.com"
CERT_DIR="/etc/letsencrypt/live/${DOMAIN}"
CLOUDFLARE_API_TOKEN="your_cloudflare_api_token"
RENEWAL_DAYS=30
LOG_FILE="/var/log/cert-renewal.log"
NOTIFICATION_WEBHOOK="https://hooks.slack.com/services/YOUR/WEBHOOK/URL"

# Logging function
log() {
  echo "[$(date +'%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE"
}

# Send notification
notify() {
  local message="$1"
  local color="${2:-#36a64f}"

  curl -X POST "$NOTIFICATION_WEBHOOK" \
    -H 'Content-Type: application/json' \
    -d "{
      \"attachments\": [{
        \"color\": \"$color\",
        \"text\": \"$message\",
        \"footer\": \"Certificate Renewal Service\",
        \"ts\": $(date +%s)
      }]
    }" || log "Failed to send notification"
}

# Check certificate expiration
check_expiration() {
  local cert_file="${CERT_DIR}/cert.pem"

  if [[ ! -f "$cert_file" ]]; then
    log "Certificate not found at $cert_file"
    return 1
  fi

  local expiry_date
  expiry_date=$(openssl x509 -enddate -noout -in "$cert_file" | cut -d= -f2)

  local expiry_epoch
  expiry_epoch=$(date -d "$expiry_date" +%s)

  local current_epoch
  current_epoch=$(date +%s)

  local days_until_expiry
  days_until_expiry=$(( (expiry_epoch - current_epoch) / 86400 ))

  log "Certificate expires in $days_until_expiry days"

  if [[ $days_until_expiry -le $RENEWAL_DAYS ]]; then
    log "Certificate renewal required (threshold: $RENEWAL_DAYS days)"
    return 0
  else
    log "Certificate renewal not needed yet"
    return 1
  fi
}

# Renew certificate with DNS-01 challenge
renew_certificate() {
  log "Starting certificate renewal for $DOMAIN and $WILDCARD_DOMAIN"

  # Export Cloudflare credentials
  export CLOUDFLARE_API_TOKEN="$CLOUDFLARE_API_TOKEN"

  # Run certbot with DNS-01 challenge
  if certbot certonly \
    --dns-cloudflare \
    --dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
    --dns-cloudflare-propagation-seconds 60 \
    -d "$DOMAIN" \
    -d "$WILDCARD_DOMAIN" \
    --email "$EMAIL" \
    --agree-tos \
    --non-interactive \
    --keep-until-expiring \
    --quiet; then

    log "✅ Certificate renewed successfully"
    return 0
  else
    log "❌ Certificate renewal failed"
    return 1
  fi
}

# Validate renewed certificate
validate_certificate() {
  local cert_file="${CERT_DIR}/cert.pem"
  local key_file="${CERT_DIR}/privkey.pem"

  # Check certificate validity
  if ! openssl x509 -in "$cert_file" -noout -checkend 0; then
    log "❌ Certificate is expired or invalid"
    return 1
  fi

  # Verify private key matches certificate
  local cert_modulus
  cert_modulus=$(openssl x509 -noout -modulus -in "$cert_file" | openssl md5)

  local key_modulus
  key_modulus=$(openssl rsa -noout -modulus -in "$key_file" | openssl md5)

  if [[ "$cert_modulus" != "$key_modulus" ]]; then
    log "❌ Certificate and private key mismatch"
    return 1
  fi

  # Check certificate chain
  if ! openssl verify -CAfile "${CERT_DIR}/chain.pem" "$cert_file" > /dev/null 2>&1; then
    log "❌ Certificate chain validation failed"
    return 1
  fi

  log "✅ Certificate validation passed"
  return 0
}

# Reload TLS server gracefully
reload_server() {
  log "Reloading TLS server with new certificate"

  # Send USR2 signal for graceful reload (Node.js cluster mode)
  if pkill -USR2 -f "node.*tls-server.js"; then
    log "✅ Server reload signal sent"
    sleep 5

    # Verify server is responding
    if curl -s -o /dev/null -w "%{http_code}" https://"$DOMAIN"/health | grep -q "200"; then
      log "✅ Server responding correctly with new certificate"
      return 0
    else
      log "❌ Server health check failed after reload"
      return 1
    fi
  else
    log "❌ Failed to send reload signal to server"
    return 1
  fi
}

# Main renewal workflow
main() {
  log "=== Certificate Renewal Service Started ==="

  # Check if renewal is needed
  if ! check_expiration; then
    log "No action needed"
    exit 0
  fi

  # Renew certificate
  if ! renew_certificate; then
    notify "❌ Certificate renewal failed for $DOMAIN" "#ff0000"
    exit 1
  fi

  # Validate new certificate
  if ! validate_certificate; then
    notify "❌ Certificate validation failed for $DOMAIN" "#ff0000"
    exit 1
  fi

  # Reload server
  if ! reload_server; then
    notify "⚠️ Certificate renewed but server reload failed for $DOMAIN" "#ffcc00"
    exit 1
  fi

  notify "✅ Certificate renewed and deployed successfully for $DOMAIN"
  log "=== Certificate Renewal Service Completed ==="
}

# Run main function
main

Deploy this script as a systemd timer (runs daily) or cron job. For ChatGPT applications with high availability requirements, implement certificate renewal monitoring that alerts your team 7 days before expiration—well before the 30-day renewal threshold.

HSTS Headers: Strict-Transport-Security & Browser Preloading

HTTP Strict Transport Security (HSTS) headers instruct browsers to always use HTTPS connections for your domain, preventing protocol downgrade attacks where adversaries force users onto unencrypted HTTP connections. For ChatGPT applications handling authentication, HSTS headers prevent session hijacking attacks that exploit mixed-content vulnerabilities or insecure redirects.

The Strict-Transport-Security header includes three critical directives: max-age (how long browsers should remember the HTTPS-only policy), includeSubDomains (apply policy to all subdomains), and preload (opt-in to browser preload lists). Setting max-age to 31536000 seconds (1 year) balances security with operational flexibility—you can still migrate domains or change hosting providers without permanent HSTS lockout.

Including your domain in the HSTS preload list (hstspreload.org) provides protection from the very first visit, eliminating the trust-on-first-use vulnerability where attackers can intercept the initial HTTP connection before HSTS activates. For production ChatGPT MCP servers, HSTS preloading is mandatory for compliance with PCI-DSS and recommended by OWASP:

// hsts-middleware.ts - Production HSTS Implementation
import { Request, Response, NextFunction } from 'express';

interface HSTSOptions {
  maxAge: number;
  includeSubDomains: boolean;
  preload: boolean;
  reportUri?: string;
}

class HSTSMiddleware {
  private options: HSTSOptions;

  constructor(options?: Partial<HSTSOptions>) {
    this.options = {
      maxAge: 31536000, // 1 year
      includeSubDomains: true,
      preload: true,
      ...options
    };
  }

  public middleware() {
    return (req: Request, res: Response, next: NextFunction): void => {
      // Only apply HSTS on HTTPS connections
      if (req.secure || req.headers['x-forwarded-proto'] === 'https') {
        const directives: string[] = [
          `max-age=${this.options.maxAge}`
        ];

        if (this.options.includeSubDomains) {
          directives.push('includeSubDomains');
        }

        if (this.options.preload) {
          directives.push('preload');
        }

        res.setHeader('Strict-Transport-Security', directives.join('; '));
      }

      next();
    };
  }

  public enforceHTTPS() {
    return (req: Request, res: Response, next: NextFunction): void => {
      // Redirect HTTP to HTTPS
      if (!req.secure && req.headers['x-forwarded-proto'] !== 'https') {
        const httpsUrl = `https://${req.hostname}${req.originalUrl}`;
        res.redirect(301, httpsUrl);
        return;
      }

      next();
    };
  }

  public reportViolations() {
    return (req: Request, res: Response, next: NextFunction): void => {
      // Set Expect-CT header for certificate transparency
      res.setHeader('Expect-CT', 'max-age=86400, enforce');

      // Set Content-Security-Policy with upgrade-insecure-requests
      const existingCSP = res.getHeader('Content-Security-Policy') as string || '';
      if (!existingCSP.includes('upgrade-insecure-requests')) {
        res.setHeader('Content-Security-Policy',
          `${existingCSP}; upgrade-insecure-requests`
        );
      }

      next();
    };
  }
}

// Usage in Express app
import express from 'express';

const app = express();
const hsts = new HSTSMiddleware();

// Enforce HTTPS redirects
app.use(hsts.enforceHTTPS());

// Apply HSTS headers
app.use(hsts.middleware());

// Report violations
app.use(hsts.reportViolations());

// ChatGPT MCP routes
app.post('/mcp', (req, res) => {
  res.json({ message: 'Secure MCP endpoint' });
});

export default app;

After deploying HSTS headers with preload enabled, submit your domain to the HSTS preload list at hstspreload.org. Chrome, Firefox, Safari, and Edge check this list to enforce HTTPS from the first connection, protecting users even on compromised networks.

Certificate Pinning: Validation & Backup Pin Management

Certificate pinning hardcodes expected certificate properties (public key hashes) into your application, preventing man-in-the-middle attacks that use fraudulent certificates issued by compromised Certificate Authorities. For ChatGPT mobile apps or desktop clients connecting to your MCP server, certificate pinning ensures that only your legitimate certificate is accepted—even if an attacker compromises a CA and issues a valid-looking certificate for your domain.

The challenge with certificate pinning lies in rotation: when you renew or replace your certificate, pinned clients will reject the new certificate and fail to connect. The solution involves pinning to the intermediate CA certificate or maintaining a set of backup pins (including your next certificate's hash) that you rotate before the current certificate expires.

This TypeScript implementation demonstrates public key pinning with backup pin support and graceful degradation for pin validation failures:

// certificate-pinner.ts - Public Key Pinning with Backup Pins
import https from 'https';
import crypto from 'crypto';
import { URL } from 'url';

interface PinConfig {
  hostname: string;
  pins: string[]; // SHA-256 hashes of public keys
  backupPins?: string[];
  reportUri?: string;
  enforceMode: boolean;
}

class CertificatePinner {
  private config: PinConfig;

  constructor(config: PinConfig) {
    this.config = config;
  }

  private extractPublicKeyHash(cert: any): string {
    const publicKey = cert.exportKey({ type: 'spki', format: 'der' });
    return crypto.createHash('sha256').update(publicKey).digest('base64');
  }

  public async validateConnection(url: string): Promise<boolean> {
    const parsedUrl = new URL(url);

    return new Promise((resolve, reject) => {
      const options = {
        hostname: parsedUrl.hostname,
        port: parsedUrl.port || 443,
        method: 'GET',
        path: parsedUrl.pathname
      };

      const req = https.request(options, (res) => {
        const cert = (res.socket as any).getPeerCertificate();

        if (!cert || Object.keys(cert).length === 0) {
          this.reportViolation('No certificate presented');
          resolve(false);
          return;
        }

        const presentedPin = this.extractPublicKeyHash(cert);
        const allPins = [...this.config.pins, ...(this.config.backupPins || [])];

        const pinValid = allPins.includes(presentedPin);

        if (!pinValid) {
          this.reportViolation(`Pin mismatch: ${presentedPin}`);

          if (this.config.enforceMode) {
            resolve(false);
          } else {
            console.warn('⚠️ Pin validation failed but enforceMode=false');
            resolve(true);
          }
        } else {
          resolve(true);
        }
      });

      req.on('error', (error) => {
        this.reportViolation(`Connection error: ${error.message}`);
        reject(error);
      });

      req.end();
    });
  }

  private reportViolation(message: string): void {
    console.error(`❌ Certificate pinning violation: ${message}`);

    if (this.config.reportUri) {
      fetch(this.config.reportUri, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          hostname: this.config.hostname,
          violation: message,
          timestamp: new Date().toISOString()
        })
      }).catch(console.error);
    }
  }

  public async generateBackupPin(certPath: string): Promise<string> {
    const fs = await import('fs');
    const certPem = fs.readFileSync(certPath, 'utf8');

    // Extract public key from certificate
    const cert = crypto.createPublicKey({
      key: certPem,
      format: 'pem'
    });

    const spki = cert.export({ type: 'spki', format: 'der' });
    return crypto.createHash('sha256').update(spki).digest('base64');
  }
}

// Usage example
const pinner = new CertificatePinner({
  hostname: 'api.yourdomain.com',
  pins: [
    'x3xBwzSZx8GYuIv+pXXxQNmXJdqnJQQqEDfCHiuWWUA=', // Current cert
  ],
  backupPins: [
    'k3xBwzSZx8GYuIv+pXXxQNmXJdqnJQQqEDfCHiuWWUB=', // Next cert
  ],
  reportUri: 'https://security.yourdomain.com/pin-report',
  enforceMode: true
});

// Validate before making API call
pinner.validateConnection('https://api.yourdomain.com/mcp')
  .then(valid => {
    if (valid) {
      console.log('✅ Certificate pin validated');
      // Proceed with API call
    } else {
      console.error('❌ Certificate pin validation failed');
      // Block API call
    }
  });

For ChatGPT applications, implement certificate pinning in native mobile apps and desktop clients, but avoid pinning in web browsers (which handle certificate validation natively). Use enforceMode: false during initial deployment to monitor pin violations before enforcing strict validation.

Mutual TLS (mTLS) Authentication: Client Certificate Validation

Mutual TLS extends the standard TLS handshake by requiring clients to present valid certificates, enabling cryptographic authentication without passwords or API keys. For ChatGPT MCP servers processing sensitive healthcare or financial data, mTLS ensures that only authorized clients with valid certificates can establish connections—preventing unauthorized access even if API endpoints are discovered.

mTLS authentication requires distributing client certificates to authorized users or services, implementing certificate revocation checking (OCSP or CRL), and handling certificate renewal for long-lived clients. The security benefit comes from eliminating credential theft attacks: since client certificates include private keys that never leave the client device, attackers cannot replay stolen credentials.

This production implementation validates client certificates, checks revocation status, and enforces certificate-based access control:

// mtls-validator.ts - Mutual TLS Authentication
import https from 'https';
import fs from 'fs';
import { Request, Response, NextFunction } from 'express';
import crypto from 'crypto';

interface MTLSConfig {
  ca: Buffer;
  requestCert: boolean;
  rejectUnauthorized: boolean;
  allowedClients?: string[]; // Common Names
}

class MTLSValidator {
  private config: MTLSConfig;

  constructor(config: MTLSConfig) {
    this.config = config;
  }

  public createServer(app: any, port: number = 443): https.Server {
    const options = {
      key: fs.readFileSync('/etc/letsencrypt/live/yourdomain.com/privkey.pem'),
      cert: fs.readFileSync('/etc/letsencrypt/live/yourdomain.com/fullchain.pem'),
      ca: this.config.ca,
      requestCert: this.config.requestCert,
      rejectUnauthorized: this.config.rejectUnauthorized
    };

    const server = https.createServer(options, app);

    server.listen(port, () => {
      console.log(`✅ mTLS server running on port ${port}`);
    });

    return server;
  }

  public validateMiddleware() {
    return (req: Request, res: Response, next: NextFunction): void => {
      const cert = (req.socket as any).getPeerCertificate();

      // Check if client certificate was presented
      if (!cert || Object.keys(cert).length === 0) {
        res.status(401).json({
          error: 'Client certificate required'
        });
        return;
      }

      // Validate certificate properties
      if (!this.validateCertificate(cert)) {
        res.status(403).json({
          error: 'Invalid client certificate'
        });
        return;
      }

      // Store client identity in request
      (req as any).clientCertificate = {
        commonName: cert.subject.CN,
        fingerprint: cert.fingerprint,
        validFrom: cert.valid_from,
        validTo: cert.valid_to
      };

      next();
    };
  }

  private validateCertificate(cert: any): boolean {
    // Check if certificate is within validity period
    const now = new Date();
    const validFrom = new Date(cert.valid_from);
    const validTo = new Date(cert.valid_to);

    if (now < validFrom || now > validTo) {
      console.error('❌ Certificate expired or not yet valid');
      return false;
    }

    // Check if client is in allowed list
    if (this.config.allowedClients && this.config.allowedClients.length > 0) {
      if (!this.config.allowedClients.includes(cert.subject.CN)) {
        console.error(`❌ Client ${cert.subject.CN} not in allowed list`);
        return false;
      }
    }

    return true;
  }
}

// Usage
import express from 'express';

const app = express();

const mtlsValidator = new MTLSValidator({
  ca: fs.readFileSync('/path/to/client-ca.pem'),
  requestCert: true,
  rejectUnauthorized: true,
  allowedClients: [
    'chatgpt-client-1',
    'chatgpt-client-2'
  ]
});

// Apply mTLS validation
app.use(mtlsValidator.validateMiddleware());

// Protected MCP endpoint
app.post('/mcp', (req, res) => {
  const clientId = (req as any).clientCertificate.commonName;
  res.json({
    message: 'Authenticated via mTLS',
    client: clientId
  });
});

// Start mTLS server
mtlsValidator.createServer(app, 443);

For ChatGPT applications requiring mTLS, generate client certificates using your own Certificate Authority (not Let's Encrypt) and distribute private keys securely via encrypted channels or hardware security modules.

SSL/TLS Health Monitoring & Certificate Rotation

Production ChatGPT applications require continuous monitoring of SSL/TLS health: certificate expiration, protocol support, cipher strength, and certificate chain validity. This monitoring service checks all critical TLS parameters and alerts your team before issues impact users:

// ssl-health-checker.ts - Comprehensive TLS Monitoring
import https from 'https';
import tls from 'tls';

interface HealthCheckResult {
  domain: string;
  valid: boolean;
  issues: string[];
  details: {
    protocol?: string;
    cipher?: string;
    daysUntilExpiry?: number;
    chainValid?: boolean;
  };
}

class SSLHealthChecker {
  public async check(domain: string, port: number = 443): Promise<HealthCheckResult> {
    const result: HealthCheckResult = {
      domain,
      valid: true,
      issues: [],
      details: {}
    };

    try {
      await this.performHealthCheck(domain, port, result);
    } catch (error: any) {
      result.valid = false;
      result.issues.push(`Connection failed: ${error.message}`);
    }

    return result;
  }

  private performHealthCheck(
    domain: string,
    port: number,
    result: HealthCheckResult
  ): Promise<void> {
    return new Promise((resolve, reject) => {
      const socket = tls.connect({ host: domain, port, servername: domain }, () => {
        const cert = socket.getPeerCertificate();

        // Check protocol version
        const protocol = socket.getProtocol();
        result.details.protocol = protocol;

        if (!protocol?.startsWith('TLSv1.3') && !protocol?.startsWith('TLSv1.2')) {
          result.valid = false;
          result.issues.push(`Weak protocol: ${protocol}`);
        }

        // Check cipher suite
        const cipher = socket.getCipher();
        result.details.cipher = cipher.name;

        if (!this.isStrongCipher(cipher.name)) {
          result.valid = false;
          result.issues.push(`Weak cipher: ${cipher.name}`);
        }

        // Check certificate expiration
        const validTo = new Date(cert.valid_to);
        const now = new Date();
        const daysUntilExpiry = Math.floor(
          (validTo.getTime() - now.getTime()) / (1000 * 60 * 60 * 24)
        );

        result.details.daysUntilExpiry = daysUntilExpiry;

        if (daysUntilExpiry < 7) {
          result.valid = false;
          result.issues.push(`Certificate expires in ${daysUntilExpiry} days`);
        } else if (daysUntilExpiry < 30) {
          result.issues.push(`Certificate expires in ${daysUntilExpiry} days (warning)`);
        }

        socket.end();
        resolve();
      });

      socket.on('error', (error) => {
        reject(error);
      });
    });
  }

  private isStrongCipher(cipher: string): boolean {
    const strongCiphers = [
      'TLS_AES_256_GCM_SHA384',
      'TLS_CHACHA20_POLY1305_SHA256',
      'TLS_AES_128_GCM_SHA256',
      'ECDHE-RSA-AES256-GCM-SHA384',
      'ECDHE-RSA-AES128-GCM-SHA256'
    ];

    return strongCiphers.some(strong => cipher.includes(strong));
  }
}

// Monitoring service
const checker = new SSLHealthChecker();

setInterval(async () => {
  const result = await checker.check('api.yourdomain.com');

  if (!result.valid) {
    console.error('❌ SSL health check failed:', result.issues);
    // Send alert to monitoring system
  } else {
    console.log('✅ SSL health check passed');
  }
}, 3600000); // Check every hour

Deploy this health checker as a separate monitoring service that runs independently of your main application, ensuring you detect certificate issues even if your primary server fails.

Certificate Rotation Without Downtime

When rotating certificates (either for scheduled renewal or emergency revocation), your ChatGPT MCP server must continue serving requests without interruption. This handler implements zero-downtime certificate rotation using Node.js cluster mode:

// certificate-rotation-handler.ts - Zero-Downtime Rotation
import cluster from 'cluster';
import os from 'os';
import fs from 'fs';
import https from 'https';
import express from 'express';

interface CertificatePaths {
  key: string;
  cert: string;
  ca?: string;
}

class CertificateRotationHandler {
  private app: express.Application;
  private certPaths: CertificatePaths;
  private servers: Map<number, https.Server> = new Map();

  constructor(app: express.Application, certPaths: CertificatePaths) {
    this.app = app;
    this.certPaths = certPaths;
  }

  public startCluster(port: number = 443): void {
    if (cluster.isPrimary) {
      this.setupPrimary();
    } else {
      this.setupWorker(port);
    }
  }

  private setupPrimary(): void {
    const numWorkers = os.cpus().length;

    console.log(`✅ Starting ${numWorkers} workers`);

    for (let i = 0; i < numWorkers; i++) {
      cluster.fork();
    }

    cluster.on('exit', (worker, code, signal) => {
      console.log(`Worker ${worker.process.pid} died, restarting...`);
      cluster.fork();
    });

    // Listen for certificate rotation signal
    process.on('SIGUSR2', () => {
      console.log('🔄 Received certificate rotation signal');
      this.rotateWorkers();
    });
  }

  private setupWorker(port: number): void {
    const server = this.createServer(port);
    this.servers.set(process.pid!, server);

    console.log(`✅ Worker ${process.pid} started on port ${port}`);

    // Graceful shutdown handler
    process.on('SIGTERM', () => {
      console.log(`Worker ${process.pid} shutting down gracefully`);

      server.close(() => {
        console.log(`Worker ${process.pid} closed all connections`);
        process.exit(0);
      });

      // Force shutdown after 30 seconds
      setTimeout(() => {
        console.error(`Worker ${process.pid} forced shutdown`);
        process.exit(1);
      }, 30000);
    });
  }

  private createServer(port: number): https.Server {
    const options = this.loadCertificates();
    const server = https.createServer(options, this.app);

    server.listen(port, () => {
      console.log(`Worker ${process.pid} listening on port ${port}`);
    });

    return server;
  }

  private loadCertificates(): https.ServerOptions {
    return {
      key: fs.readFileSync(this.certPaths.key),
      cert: fs.readFileSync(this.certPaths.cert),
      ca: this.certPaths.ca ? fs.readFileSync(this.certPaths.ca) : undefined
    };
  }

  private rotateWorkers(): void {
    const workers = Object.values(cluster.workers || {});

    workers.forEach((worker, index) => {
      setTimeout(() => {
        console.log(`Rotating worker ${worker?.process.pid}`);

        // Start new worker
        const newWorker = cluster.fork();

        // Wait for new worker to be ready, then kill old one
        newWorker.on('listening', () => {
          worker?.kill('SIGTERM');
        });
      }, index * 2000); // Stagger rotations by 2 seconds
    });
  }
}

// Usage
const app = express();

app.get('/health', (req, res) => {
  res.json({ status: 'healthy' });
});

const handler = new CertificateRotationHandler(app, {
  key: '/etc/letsencrypt/live/yourdomain.com/privkey.pem',
  cert: '/etc/letsencrypt/live/yourdomain.com/fullchain.pem'
});

handler.startCluster(443);

After renewing certificates with Let's Encrypt, send SIGUSR2 to the master process (kill -USR2 <pid>) to trigger graceful rotation. Workers reload with new certificates while old workers finish existing requests.

Secure Your ChatGPT App with Enterprise-Grade Encryption

Encryption in transit protects your ChatGPT application from the most common attack vectors: man-in-the-middle attacks, session hijacking, and credential theft. By implementing TLS 1.3 with strong cipher suites, automating Let's Encrypt certificate renewal, enforcing HSTS headers, and optionally adding certificate pinning or mTLS authentication, you create defense-in-depth security that meets enterprise compliance requirements.

MakeAIHQ's no-code platform provides built-in TLS 1.3 support, automated certificate management, and HSTS configuration out-of-the-box—so you can deploy secure ChatGPT apps without managing complex infrastructure. Whether you're building a healthcare assistant subject to HIPAA, a financial advisor complying with PCI-DSS, or a customer service bot handling personal data under GDPR, proper encryption in transit is non-negotiable.

Ready to build ChatGPT apps with bank-level security? Start your free trial and deploy your first secure MCP server in 48 hours—no DevOps expertise required.

Internal Links:

External Links: