Skip to the content.

Architecture

← Back to Home

System Overview

The proxy system consists of three main components working together to provide high-performance reverse proxying with automated SSL management.

┌──────────────────────────────────────────────────────────────┐
│                         Internet                              │
└─────────────────────────┬────────────────────────────────────┘
                          │ HTTPS/HTTP
                          ▼
┌──────────────────────────────────────────────────────────────┐
│                    OpenResty/Nginx                            │
│  ┌────────────────┐  ┌──────────────┐  ┌─────────────────┐  │
│  │ SSL Termination│  │ Host Routing │  │ Request Proxying│  │
│  │ (lua-resty-    │  │ (targetinfo. │  │                 │  │
│  │  auto-ssl)     │  │  lua)        │  │                 │  │
│  └────────────────┘  └──────┬───────┘  └─────────────────┘  │
└────────────┬──────────────────┼───────────────────────────┬──┘
             │                  │                           │
     Let's Encrypt       1. Check Redis FIRST          Backend
       HTTP-01           2. Unix Socket (fallback)    Services
             │                  │                           │
             ▼                  ▼                           ▼
┌──────────────────────┐  ┌──────────────────────────────────┐
│       Redis          │  │      Node.js Application         │
│  (Primary Cache)     │  │  ┌──────────────┐  ┌─────────┐  │
│  - Host configs ◄────┼──┼──┤   Services   │  │ Routes  │  │
│  - User accounts     │  │  │ - host_lookup│  │ - /api/*│  │
│  - SSL certs         │  │  │ - scheduler  │  │         │  │
│  - Auth tokens       │  │  └──────────────┘  └─────────┘  │
└──────────────────────┘  └─────────┬────────────────────────┘
                                    │
                                    ▼
                          ┌──────────────────────┐
                          │    DNS Providers     │
                          │  - CloudFlare        │
                          │  - DigitalOcean      │
                          │  - PorkBun           │
                          │  (DNS-01 challenges) │
                          └──────────────────────┘

Component Details

OpenResty/Nginx (Frontend)

Responsibilities:

Key Features:

Configuration Files:

Node.js Application (Backend)

Responsibilities:

Directory Structure:

nodejs/
├── bin/www              # Application entry point
├── models/              # Data models
│   ├── host.js          # Host configuration and lookup
│   ├── auth.js          # Authentication logic
│   ├── user.js          # User management
│   └── dns_provider/    # DNS provider implementations
├── routes/              # API endpoints
│   ├── host.js          # Host CRUD operations
│   ├── dns.js           # DNS provider management
│   ├── user.js          # User management
│   └── auth.js          # Authentication
├── services/            # Background services
│   ├── host_lookup.js   # Unix socket server
│   └── host_scheduler.js # Cert renewal scheduler
├── middleware/          # Express middleware
│   └── auth.js          # Authentication middleware
└── utils/               # Utility modules
    └── unix_socket_json.js # Unix socket server

Redis (Data Store)

ORM: model-redis - A lightweight Redis ORM for Node.js with schema validation, relationships, and automatic key management.

Stored Data:

Key Prefixes:

proxy_Host_<hostname>           # Host configuration
proxy_User_<username>           # User account
proxy_AuthToken_<token>         # Auth tokens
proxy_DnsProvider_<id>          # DNS provider
proxy_Domain_<domain>           # Domain info
<hostname>:latest               # SSL certificate cache

Request Flow

Standard HTTP/HTTPS Request

  1. Client sends HTTPS request to app.example.com
  2. OpenResty receives request, terminates SSL
  3. Lua script (targetinfo.lua) queries Redis first for host config
  4. If found in Redis, jump to step 7 (Node.js not involved)
  5. If not in Redis, Lua queries Node.js via Unix socket as fallback
  6. Node.js performs host lookup (supports wildcards), caches result in Redis
  7. OpenResty proxies request to backend service using target IP and port
  8. Response proxied back to client

Resilience: If Node.js goes down, all hosts already cached in Redis continue to work. Only new/uncached hosts will fail until Node.js recovers.

Wildcard SSL Certificate Request

  1. User creates wildcard host (*.example.com) via API
  2. Node.js validates domain has DNS provider configured
  3. Let’s Encrypt DNS-01 challenge initiated
  4. DNS provider API creates TXT record (_acme-challenge.example.com)
  5. Let’s Encrypt validates TXT record
  6. Certificate generated and stored in Redis
  7. DNS provider cleans up TXT record
  8. Background scheduler monitors expiration, renews 30 days before expiry

Host Lookup Algorithm

The lookup tree enables sophisticated domain matching:

Input: "api.v1.example.com"

Tree Structure:
{
  "com": {
    "example": {
      "*": {          // Matches api.example.com
        "#record": {...}
      },
      "v1": {
        "api": {      // Matches api.v1.example.com (exact)
          "#record": {...}
        }
      }
    }
  }
}

Priority: Exact > Single wildcard (*) > Double wildcard (**)

Wildcard Types:

Security Architecture

Authentication Flow

  1. User sends credentials to /api/auth/login
  2. Credentials validated against stored hash (bcrypt)
  3. Token generated and stored in Redis with TTL
  4. Token returned to client
  5. Subsequent requests include token in auth-token header
  6. Middleware validates token before processing request

SSL Certificate Security

Unix Socket Communication

Performance Optimizations

Caching Strategy

The system uses a multi-tier caching approach:

  1. Redis (L1 Cache) - OpenResty checks Redis FIRST for every request
    • Primary host configuration storage
    • Survives Node.js restarts/failures
    • Shared across all OpenResty workers
  2. Node.js Lookup Tree (L2 Cache) - In-memory host lookup with wildcard matching
    • Only queried when Redis has no entry
    • Rebuilt automatically when hosts change
    • Supports complex wildcard resolution
  3. Wildcard Parent Caching - Resolved wildcard matches stored back to Redis
    • Subsequent requests to api.example.com hit Redis directly
    • No repeated wildcard resolution needed

Unix Socket vs HTTP API

Unix socket chosen over HTTP for host lookups:

Scalability Considerations

Current Architecture

Future Scaling Options

Monitoring and Observability

Logs

Health Checks

Metrics to Monitor

← Back to Home