vasyansk ad51829aed
Build Admin / Build image (push) Successful in 31s
Update locations.conf
2026-07-09 14:59:24 +07:00
2026-03-21 10:45:42 +07:00
2026-03-21 10:55:55 +07:00
2026-07-09 14:59:24 +07:00
2026-03-21 10:47:11 +07:00
2026-07-09 14:41:17 +07:00
2026-07-09 14:41:17 +07:00
2026-07-09 14:41:17 +07:00
2026-07-09 14:41:17 +07:00
2026-07-09 14:41:17 +07:00
2026-07-09 14:41:17 +07:00
2026-07-09 14:41:17 +07:00
2026-03-21 10:45:42 +07:00

API Proxy — HTTPS Reverse Proxy

Production-ready nginx reverse proxy in Docker for forwarding requests from an internal Kubernetes cluster to external APIs (ElevenLabs, OpenAI, Telegram Bot API).

Quick Start

Prerequisites

  • Ubuntu 24.04 VM
  • Port 8080 (HTTP) and optionally 8443 (HTTPS) open only to k8s cluster CIDR

Installation

sudo bash scripts/install.sh

Configuration

vi .env

# Set your secret and cluster CIDR:
PROXY_SECRET=<generated-token>
ALLOWED_CIDR=10.0.0.0/8,172.16.0.0/12

docker compose up -d --build

Verify

# Health check (no auth):
curl http://localhost:8080/health

# Test with auth:
curl -H "X-Proxy-Token: YOUR_SECRET" http://localhost:8080/elevenlabs/v1/voices

Available Endpoints

Prefix Upstream
/elevenlabs/ https://api.elevenlabs.io
/openai/ https://api.openai.com
/telegram/ https://api.telegram.org
/health local health check (no auth)

TLS / HTTPS

To enable HTTPS on port 8443, place your certificate and key in the ssl/ directory:

mkdir -p ssl

# Option A: self-signed cert
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout ssl/tls.key \
  -out ssl/tls.crt \
  -subj "/CN=api-proxy"

# Option B: copy existing certs
cp /path/to/your/cert.pem ssl/tls.crt
cp /path/to/your/key.pem  ssl/tls.key

docker compose up -d --build

The entrypoint auto-detects ssl/tls.crt and ssl/tls.key. If present — HTTPS is enabled on port 8443. If absent — only HTTP on 8080.


How to Add a New Upstream

Example: adding api.anthropic.com/anthropic/*

Add this block to nginx/locations.conf:

location /anthropic/ {
    if ($allowed_ip = 0) {
        return 403 '{"error":"ip_not_allowed"}';
    }
    if ($auth_ok = 0) {
        return 403 '{"error":"invalid_token"}';
    }

    set $anthropic_upstream https://api.anthropic.com;
    rewrite ^/anthropic/(.*) /$1 break;

    proxy_pass $anthropic_upstream;
    proxy_ssl_server_name on;
    proxy_ssl_name api.anthropic.com;
    proxy_ssl_protocols TLSv1.2 TLSv1.3;

    proxy_set_header Host api.anthropic.com;
    proxy_set_header Connection "";

    proxy_set_header X-Forwarded-For "";
    proxy_set_header X-Real-IP "";
    proxy_set_header True-Client-IP "";
    proxy_set_header CF-Connecting-IP "";
    proxy_set_header X-Client-IP "";
    proxy_set_header Forwarded "";
    proxy_set_header Via "";

    proxy_set_header X-Proxy-Token "";

    proxy_http_version 1.1;
    proxy_buffering off;
    proxy_request_buffering off;
    proxy_read_timeout 120s;
    proxy_send_timeout 120s;
}

Then rebuild: docker compose up -d --build


K8s Side: How to Call the Proxy

Environment Variables

env:
  - name: PROXY_BASE_URL
    value: "http://10.0.1.50:8080"  # or https://10.0.1.50:8443
  - name: PROXY_SECRET
    valueFrom:
      secretKeyRef:
        name: api-proxy
        key: token

TypeScript Examples

// ElevenLabs TTS
const response = await fetch(
  `${process.env.PROXY_BASE_URL}/elevenlabs/v1/text-to-speech/${voiceId}`,
  {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'xi-api-key': process.env.ELEVENLABS_API_KEY,
      'X-Proxy-Token': process.env.PROXY_SECRET,
    },
    body: JSON.stringify(payload),
  }
);
const buffer = Buffer.from(await response.arrayBuffer());

// Telegram Bot API
const tgResponse = await fetch(
  `${process.env.PROXY_BASE_URL}/telegram/bot${process.env.TELEGRAM_BOT_TOKEN}/sendMessage`,
  {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-Proxy-Token': process.env.PROXY_SECRET,
    },
    body: JSON.stringify({ chat_id: chatId, text: message }),
  }
);

Security Checklist

  • PROXY_SECRET generated via openssl rand -hex 32
  • ALLOWED_CIDR restricted to cluster CIDR only
  • Port 8080/8443 closed to the public (only k8s CIDR in firewall/NSG)
  • VM has no public IP or is behind NAT
  • Logs rotate (Docker logging driver configured: 50m x 5 files)
  • TLS certs have restricted permissions (chmod 600 ssl/tls.key)

Monitoring

# Tail logs
docker compose logs -f proxy | jq .

# Requests per upstream per minute
docker compose logs --since=1m proxy --no-log-prefix \
  | jq -r '.uri' \
  | cut -d'/' -f2 \
  | sort | uniq -c | sort -rn

# Container health
docker inspect --format='{{.State.Health.Status}}' api-proxy

How It Works

  1. A k8s pod sends an HTTP request to http://<proxy-vm>:8080/elevenlabs/v1/text-to-speech/... with the X-Proxy-Token header and the original API key.
  2. Nginx checks the source IP against ALLOWED_CIDR and validates X-Proxy-Token — rejecting with 403 if either fails.
  3. The prefix (/elevenlabs/, /openai/, /telegram/) is stripped via rewrite, and the request is forwarded over HTTPS to the upstream with SNI enabled.
  4. X-Proxy-Token and all IP-leaking headers are removed before forwarding; API keys pass through unchanged.
  5. The response streams back unbuffered to the pod — critical for binary audio data and long-polling (Telegram).
S
Description
No description provided
Readme
60 KiB
Languages
Shell 88.1%
Dockerfile 11.9%