Try   HackMD

Multi-Domain Management System with Caddy and Tailscale

Co-authored with Claude 3.5 Sonet

Requirements

  1. Public-facing Caddy server for certificate management
  2. Multiple internal Caddy servers accessible only via Tailscale
  3. Cloudflare for DNS management
  4. Tailscale network set up on all servers
  5. Bash scripting capabilities on all servers
  6. jq installed on all servers for JSON parsing

System Components

1. Public Caddy Server

  • Exposed to the internet
  • Manages Let's Encrypt certificates for all domains
  • Runs Caddy admin API (accessible only within Tailscale network)

2. Internal Caddy Servers

  • Accessible only via Tailscale
  • Serve actual content/services
  • Fetch certificates from the public Caddy server

3. Certificate Distribution System

  • Script to fetch certificates from public server
  • Runs periodically on internal servers

4. Domain Management System

  • Scripts to add/remove domains from the system

5. DNS Configuration

  • Cloudflare for public DNS
  • Tailscale for internal DNS resolution

Configurations

Public Caddy Server Caddyfile

{
  email your-email@example.com
  acme_dns cloudflare {env.CLOUDFLARE_API_TOKEN}
  admin 127.0.0.1:2019
}

domain1.com, domain2.com, domain3.com {
  tls {
    dns cloudflare {env.CLOUDFLARE_API_TOKEN}
  }
  respond "Certificate management server"
}

Internal Caddy Server Base Caddyfile

{
  # Global options
}

(domain_template) {
  tls /etc/caddy/certificates/{$DOMAIN}.crt /etc/caddy/certificates/{$DOMAIN}.key

  @service1 path /service1/*
  handle @service1 {
    uri strip_prefix /service1
    reverse_proxy {$SERVICE1_IP}:{$SERVICE1_PORT}
  }

  @service2 path /service2/*
  handle @service2 {
    uri strip_prefix /service2
    reverse_proxy {$SERVICE2_IP}:{$SERVICE2_PORT}
  }
}

import /etc/caddy/conf.d/*.conf

Internal Caddy Server Domain-Specific Config

File: /etc/caddy/conf.d/domain1.com.conf

domain1.com {
  import domain_template {
    DOMAIN domain1.com
    SERVICE1_IP 100.a.b.c
    SERVICE1_PORT 8080
    SERVICE2_IP 100.d.e.f
    SERVICE2_PORT 9090
  }
}

Script Outlines

Certificate Distribution Script

#!/bin/bash

PUBLIC_CADDY_IP="100.x.y.z"
DOMAINS=("domain1.com" "domain2.com" "domain3.com")
CERT_DIR="/etc/caddy/certificates"

# Logic to fetch certificates for each domain
# Save certificates and keys to $CERT_DIR
# Reload Caddy

Domain Management Script

#!/bin/bash

function add_domain() {
  # Logic to add domain to:
  # 1. Public Caddy server
  # 2. Certificate distribution script
  # 3. Internal Caddy configuration
  # 4. Tailscale DNS
}

function remove_domain() {
  # Logic to remove domain from:
  # 1. Public Caddy server
  # 2. Certificate distribution script
  # 3. Internal Caddy configuration
  # 4. Tailscale DNS
  # 5. Remove certificates
}

# Main script logic to handle add/remove commands

DNS Configuration

Cloudflare (Public DNS)

  • For each domain, create an A record pointing to the public IP of the certificate management Caddy server

Tailscale (Internal DNS)

  • Set up Split DNS for each domain, pointing to 100.100.100.100
  • Add A records for each domain, pointing to the appropriate internal Caddy server's Tailscale IP

Security Considerations

  1. Secure the Caddy admin API to be accessible only within the Tailscale network
  2. Use Tailscale ACLs to restrict access to the certificate management server
  3. Keep the Cloudflare API token secure
  4. Regularly update and patch all servers
  5. Monitor certificate expiration dates
  6. Implement logging for all scripts and processes

Maintenance Tasks

  1. Regularly test the certificate renewal process
  2. Monitor disk space on all servers, especially where certificates are stored
  3. Review and update Tailscale ACLs as needed
  4. Perform regular backups of configurations and scripts
  5. Keep Caddy and other software components updated

Scalability Considerations

  1. Consider load balancing for internal Caddy servers if traffic increases
  2. Implement monitoring and alerting for all components
  3. Document the process for adding new internal servers to the system
  4. Plan for potential migration to a clustered Caddy setup for high availability