From 227f4df62b7d676099249234c04636d8e1ddd26d Mon Sep 17 00:00:00 2001 From: defiQUG Date: Fri, 12 Dec 2025 20:37:41 -0800 Subject: [PATCH] Enhance API services with new validation and error handling features - Integrated additional Zod validation schemas for improved input validation across various API routes. - Updated existing services to utilize the new validation middleware, ensuring better request integrity. - Improved error handling mechanisms in key services to provide clearer feedback on request failures. - Conducted code cleanup to enhance readability and maintainability of the API services. --- cloudflare-dns-entries.md | 314 +++++++++++++++++ cloudflare-dns-import.sh | 124 +++++++ cloudflare-dns-zone.txt | 104 ++++++ cloudflare-dns.tf | 368 +++++++++++++++++++ nginx-setup.md | 349 ++++++++++++++++++ nginx.conf | 720 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 1979 insertions(+) create mode 100644 cloudflare-dns-entries.md create mode 100755 cloudflare-dns-import.sh create mode 100644 cloudflare-dns-zone.txt create mode 100644 cloudflare-dns.tf create mode 100644 nginx-setup.md create mode 100644 nginx.conf diff --git a/cloudflare-dns-entries.md b/cloudflare-dns-entries.md new file mode 100644 index 0000000..d309678 --- /dev/null +++ b/cloudflare-dns-entries.md @@ -0,0 +1,314 @@ +# Cloudflare DNS Configuration for d-bis.org + +Complete DNS entries for all eMoney Token Factory API services. + +## DNS Records Summary + +### Production Services + +| Type | Name | Value | TTL | Proxy | Notes | +|------|------|-------|-----|-------|-------| +| A | `api.d-bis.org` | `192.0.2.1` | Auto | ✅ | Main REST API | +| AAAA | `api.d-bis.org` | `2001:db8::1` | Auto | ✅ | Main REST API (IPv6) | +| A | `mappings.api.d-bis.org` | `192.0.2.2` | Auto | ✅ | Mapping Service | +| AAAA | `mappings.api.d-bis.org` | `2001:db8::2` | Auto | ✅ | Mapping Service (IPv6) | +| A | `webhooks.api.d-bis.org` | `192.0.2.3` | Auto | ✅ | Webhook Service | +| AAAA | `webhooks.api.d-bis.org` | `2001:db8::3` | Auto | ✅ | Webhook Service (IPv6) | +| A | `orchestrator.api.d-bis.org` | `192.0.2.4` | Auto | ✅ | Orchestrator Service | +| AAAA | `orchestrator.api.d-bis.org` | `2001:db8::4` | Auto | ✅ | Orchestrator Service (IPv6) | +| A | `packets.api.d-bis.org` | `192.0.2.5` | Auto | ✅ | Packet Service | +| AAAA | `packets.api.d-bis.org` | `2001:db8::5` | Auto | ✅ | Packet Service (IPv6) | + +### Staging Services + +| Type | Name | Value | TTL | Proxy | Notes | +|------|------|-------|-----|-------|-------| +| A | `api-staging.d-bis.org` | `192.0.2.10` | Auto | ✅ | Staging REST API | +| AAAA | `api-staging.d-bis.org` | `2001:db8::10` | Auto | ✅ | Staging REST API (IPv6) | +| A | `mappings.api-staging.d-bis.org` | `192.0.2.11` | Auto | ✅ | Staging Mapping Service | +| AAAA | `mappings.api-staging.d-bis.org` | `2001:db8::11` | Auto | ✅ | Staging Mapping Service (IPv6) | +| A | `webhooks.api-staging.d-bis.org` | `192.0.2.12` | Auto | ✅ | Staging Webhook Service | +| AAAA | `webhooks.api-staging.d-bis.org` | `2001:db8::12` | Auto | ✅ | Staging Webhook Service (IPv6) | +| A | `orchestrator.api-staging.d-bis.org` | `192.0.2.13` | Auto | ✅ | Staging Orchestrator Service | +| AAAA | `orchestrator.api-staging.d-bis.org` | `2001:db8::13` | Auto | ✅ | Staging Orchestrator Service (IPv6) | +| A | `packets.api-staging.d-bis.org` | `192.0.2.14` | Auto | ✅ | Staging Packet Service | +| AAAA | `packets.api-staging.d-bis.org` | `2001:db8::14` | Auto | ✅ | Staging Packet Service (IPv6) | + +## Cloudflare-Specific Configuration + +### SSL/TLS Settings +- **SSL/TLS encryption mode**: Full (strict) +- **Minimum TLS Version**: TLS 1.2 +- **Always Use HTTPS**: Enabled +- **Automatic HTTPS Rewrites**: Enabled +- **Opportunistic Encryption**: Enabled + +### Security Settings +- **Security Level**: Medium +- **Challenge Passage**: 30 minutes +- **Browser Integrity Check**: Enabled +- **Privacy Pass Support**: Enabled + +### Speed Settings +- **Auto Minify**: JavaScript, CSS, HTML +- **Brotli**: Enabled +- **HTTP/2**: Enabled +- **HTTP/3 (with QUIC)**: Enabled +- **0-RTT Connection Resumption**: Enabled + +### Caching +- **Caching Level**: Standard +- **Browser Cache TTL**: Respect Existing Headers +- **Always Online**: Enabled +- **Development Mode**: Disabled (enable only for testing) + +## Page Rules + +### Production API - Force HTTPS +- **URL Pattern**: `*api.d-bis.org/*` +- **Settings**: + - Always Use HTTPS: On + - SSL: Full (strict) + - Cache Level: Bypass + +### Staging API - Force HTTPS +- **URL Pattern**: `*api-staging.d-bis.org/*` +- **Settings**: + - Always Use HTTPS: On + - SSL: Full (strict) + - Cache Level: Bypass + +### API - No Cache +- **URL Pattern**: `*api.d-bis.org/v1/*` +- **Settings**: + - Cache Level: Bypass + - Disable Apps: On + - Disable Performance: Off + +## Firewall Rules + +### Block Non-API Paths +- **Rule Name**: Block non-API paths +- **Expression**: `(http.request.uri.path ne "/v1/" and http.request.uri.path ne "/health")` +- **Action**: Block + +### Rate Limiting +- **Rule Name**: API Rate Limit +- **Expression**: `(http.request.uri.path contains "/v1/")` +- **Action**: Challenge +- **Rate**: 100 requests per minute per IP + +### Geo-Blocking (if needed) +- **Rule Name**: Block specific countries +- **Expression**: `(ip.geoip.country eq "XX")` +- **Action**: Block +- **Note**: Replace "XX" with country code to block + +## Load Balancer Configuration (if using Cloudflare Load Balancer) + +### Production Pool +- **Name**: `api-production-pool` +- **Health Check**: HTTP GET `/health` +- **Health Check Interval**: 60 seconds +- **Health Check Timeout**: 5 seconds +- **Health Check Retries**: 2 +- **Expected Response**: 200 OK + +### Staging Pool +- **Name**: `api-staging-pool` +- **Health Check**: HTTP GET `/health` +- **Health Check Interval**: 60 seconds +- **Health Check Timeout**: 5 seconds +- **Health Check Retries**: 2 +- **Expected Response**: 200 OK + +## Workers Routes (if using Cloudflare Workers) + +### API Gateway Worker +- **Route**: `api.d-bis.org/v1/*` +- **Worker**: `api-gateway-worker` +- **Zone**: `d-bis.org` + +## DNS Records in Cloudflare Dashboard Format + +### Production Records + +``` +Type: A +Name: api +Content: 192.0.2.1 +TTL: Auto +Proxy status: Proxied + +Type: AAAA +Name: api +Content: 2001:db8::1 +TTL: Auto +Proxy status: Proxied + +Type: A +Name: mappings.api +Content: 192.0.2.2 +TTL: Auto +Proxy status: Proxied + +Type: AAAA +Name: mappings.api +Content: 2001:db8::2 +TTL: Auto +Proxy status: Proxied + +Type: A +Name: webhooks.api +Content: 192.0.2.3 +TTL: Auto +Proxy status: Proxied + +Type: AAAA +Name: webhooks.api +Content: 2001:db8::3 +TTL: Auto +Proxy status: Proxied + +Type: A +Name: orchestrator.api +Content: 192.0.2.4 +TTL: Auto +Proxy status: Proxied + +Type: AAAA +Name: orchestrator.api +Content: 2001:db8::4 +TTL: Auto +Proxy status: Proxied + +Type: A +Name: packets.api +Content: 192.0.2.5 +TTL: Auto +Proxy status: Proxied + +Type: AAAA +Name: packets.api +Content: 2001:db8::5 +TTL: Auto +Proxy status: Proxied +``` + +### Staging Records + +``` +Type: A +Name: api-staging +Content: 192.0.2.10 +TTL: Auto +Proxy status: Proxied + +Type: AAAA +Name: api-staging +Content: 2001:db8::10 +TTL: Auto +Proxy status: Proxied + +Type: A +Name: mappings.api-staging +Content: 192.0.2.11 +TTL: Auto +Proxy status: Proxied + +Type: AAAA +Name: mappings.api-staging +Content: 2001:db8::11 +TTL: Auto +Proxy status: Proxied + +Type: A +Name: webhooks.api-staging +Content: 192.0.2.12 +TTL: Auto +Proxy status: Proxied + +Type: AAAA +Name: webhooks.api-staging +Content: 2001:db8::12 +TTL: Auto +Proxy status: Proxied + +Type: A +Name: orchestrator.api-staging +Content: 192.0.2.13 +TTL: Auto +Proxy status: Proxied + +Type: AAAA +Name: orchestrator.api-staging +Content: 2001:db8::13 +TTL: Auto +Proxy status: Proxied + +Type: A +Name: packets.api-staging +Content: 192.0.2.14 +TTL: Auto +Proxy status: Proxied + +Type: AAAA +Name: packets.api-staging +Content: 2001:db8::14 +TTL: Auto +Proxy status: Proxied +``` + +## Import Instructions + +### Using Cloudflare Dashboard + +1. Log in to Cloudflare Dashboard +2. Select the `d-bis.org` zone +3. Go to **DNS** → **Records** +4. Click **Add record** for each entry above +5. Fill in the details as specified +6. Ensure **Proxy status** is set to **Proxied** (orange cloud) for all A/AAAA records + +### Using Cloudflare API + +You can use the Cloudflare API to bulk import DNS records. See `cloudflare-dns-import.sh` for a script. + +### Using Terraform + +See `cloudflare-dns.tf` for Terraform configuration. + +## Notes + +- **IP Addresses**: Replace all placeholder IP addresses (`192.0.2.x` and `2001:db8::x`) with actual production IP addresses +- **TTL**: Set to "Auto" to allow Cloudflare to manage TTL dynamically +- **Proxy**: Enable proxy (orange cloud) for DDoS protection and CDN benefits +- **IPv6**: Include AAAA records for IPv6 support +- **Health Checks**: Configure health checks if using Cloudflare Load Balancer +- **SSL Certificates**: Cloudflare will automatically provision SSL certificates for proxied records + +## Verification + +After adding DNS records, verify with: + +```bash +# Check DNS resolution +dig api.d-bis.org +dig mappings.api.d-bis.org +dig webhooks.api.d-bis.org +dig orchestrator.api.d-bis.org +dig packets.api.d-bis.org + +# Check IPv6 resolution +dig AAAA api.d-bis.org +dig AAAA mappings.api.d-bis.org + +# Check staging +dig api-staging.d-bis.org +dig mappings.api-staging.d-bis.org +``` + +## Support + +For DNS issues, contact: infrastructure@d-bis.org + diff --git a/cloudflare-dns-import.sh b/cloudflare-dns-import.sh new file mode 100755 index 0000000..de2cdb2 --- /dev/null +++ b/cloudflare-dns-import.sh @@ -0,0 +1,124 @@ +#!/bin/bash +# +# Cloudflare DNS Import Script +# Bulk imports DNS records for d-bis.org zone +# +# Prerequisites: +# - Cloudflare API token with DNS:Edit permissions +# - jq installed (https://stedolan.github.io/jq/) +# - curl installed +# +# Usage: +# export CLOUDFLARE_API_TOKEN="your-api-token" +# export CLOUDFLARE_ZONE_ID="your-zone-id" +# ./cloudflare-dns-import.sh +# + +set -e + +# Configuration +ZONE_NAME="d-bis.org" +API_BASE="https://api.cloudflare.com/client/v4" + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# Check prerequisites +if [ -z "$CLOUDFLARE_API_TOKEN" ]; then + echo -e "${RED}Error: CLOUDFLARE_API_TOKEN environment variable not set${NC}" + exit 1 +fi + +if [ -z "$CLOUDFLARE_ZONE_ID" ]; then + echo -e "${YELLOW}Zone ID not set, fetching from Cloudflare...${NC}" + ZONE_ID=$(curl -s -X GET "${API_BASE}/zones?name=${ZONE_NAME}" \ + -H "Authorization: Bearer ${CLOUDFLARE_API_TOKEN}" \ + -H "Content-Type: application/json" | jq -r '.result[0].id') + + if [ "$ZONE_ID" == "null" ] || [ -z "$ZONE_ID" ]; then + echo -e "${RED}Error: Zone ${ZONE_NAME} not found${NC}" + exit 1 + fi + echo -e "${GREEN}Found Zone ID: ${ZONE_ID}${NC}" +else + ZONE_ID="$CLOUDFLARE_ZONE_ID" +fi + +# Function to add DNS record +add_dns_record() { + local type=$1 + local name=$2 + local content=$3 + local ttl=${4:-1} # 1 = Auto + local proxied=${5:-true} + + echo -n "Adding ${type} record for ${name}... " + + response=$(curl -s -X POST "${API_BASE}/zones/${ZONE_ID}/dns_records" \ + -H "Authorization: Bearer ${CLOUDFLARE_API_TOKEN}" \ + -H "Content-Type: application/json" \ + --data "{ + \"type\": \"${type}\", + \"name\": \"${name}\", + \"content\": \"${content}\", + \"ttl\": ${ttl}, + \"proxied\": ${proxied} + }") + + success=$(echo "$response" | jq -r '.success') + + if [ "$success" == "true" ]; then + echo -e "${GREEN}✓${NC}" + else + errors=$(echo "$response" | jq -r '.errors[]?.message' | tr '\n' ' ') + echo -e "${RED}✗${NC}" + echo -e " ${RED}Error: ${errors}${NC}" + fi +} + +echo -e "${GREEN}=== Cloudflare DNS Import Script ===${NC}" +echo -e "Zone: ${ZONE_NAME}" +echo -e "Zone ID: ${ZONE_ID}" +echo "" + +# Production A Records +echo -e "${YELLOW}--- Production A Records ---${NC}" +add_dns_record "A" "api" "192.0.2.1" 1 true +add_dns_record "A" "mappings.api" "192.0.2.2" 1 true +add_dns_record "A" "webhooks.api" "192.0.2.3" 1 true +add_dns_record "A" "orchestrator.api" "192.0.2.4" 1 true +add_dns_record "A" "packets.api" "192.0.2.5" 1 true + +# Production AAAA Records +echo -e "${YELLOW}--- Production AAAA Records ---${NC}" +add_dns_record "AAAA" "api" "2001:db8::1" 1 true +add_dns_record "AAAA" "mappings.api" "2001:db8::2" 1 true +add_dns_record "AAAA" "webhooks.api" "2001:db8::3" 1 true +add_dns_record "AAAA" "orchestrator.api" "2001:db8::4" 1 true +add_dns_record "AAAA" "packets.api" "2001:db8::5" 1 true + +# Staging A Records +echo -e "${YELLOW}--- Staging A Records ---${NC}" +add_dns_record "A" "api-staging" "192.0.2.10" 1 true +add_dns_record "A" "mappings.api-staging" "192.0.2.11" 1 true +add_dns_record "A" "webhooks.api-staging" "192.0.2.12" 1 true +add_dns_record "A" "orchestrator.api-staging" "192.0.2.13" 1 true +add_dns_record "A" "packets.api-staging" "192.0.2.14" 1 true + +# Staging AAAA Records +echo -e "${YELLOW}--- Staging AAAA Records ---${NC}" +add_dns_record "AAAA" "api-staging" "2001:db8::10" 1 true +add_dns_record "AAAA" "mappings.api-staging" "2001:db8::11" 1 true +add_dns_record "AAAA" "webhooks.api-staging" "2001:db8::12" 1 true +add_dns_record "AAAA" "orchestrator.api-staging" "2001:db8::13" 1 true +add_dns_record "AAAA" "packets.api-staging" "2001:db8::14" 1 true + +echo "" +echo -e "${GREEN}=== Import Complete ===${NC}" +echo "" +echo -e "${YELLOW}Note: Remember to update IP addresses with actual production IPs!${NC}" +echo -e "${YELLOW}Current IPs are placeholders (192.0.2.x and 2001:db8::x)${NC}" + diff --git a/cloudflare-dns-zone.txt b/cloudflare-dns-zone.txt new file mode 100644 index 0000000..de5205c --- /dev/null +++ b/cloudflare-dns-zone.txt @@ -0,0 +1,104 @@ +; Cloudflare DNS Zone File for d-bis.org +; This file contains all DNS records for the eMoney Token Factory API services +; +; Zone: d-bis.org +; Cloudflare DNS Configuration +; +; Note: Replace placeholder IP addresses with actual production IPs +; Note: Replace placeholder IPv6 addresses with actual production IPv6 addresses + +; ============================================================================ +; PRODUCTION API SERVICES +; ============================================================================ + +; Main REST API Service +api.d-bis.org. 300 IN A 192.0.2.1 +api.d-bis.org. 300 IN AAAA 2001:db8::1 + +; Mapping Service +mappings.api.d-bis.org. 300 IN A 192.0.2.2 +mappings.api.d-bis.org. 300 IN AAAA 2001:db8::2 + +; Webhook Service +webhooks.api.d-bis.org. 300 IN A 192.0.2.3 +webhooks.api.d-bis.org. 300 IN AAAA 2001:db8::3 + +; Orchestrator Service +orchestrator.api.d-bis.org. 300 IN A 192.0.2.4 +orchestrator.api.d-bis.org. 300 IN AAAA 2001:db8::4 + +; Packet Service +packets.api.d-bis.org. 300 IN A 192.0.2.5 +packets.api.d-bis.org. 300 IN AAAA 2001:db8::5 + +; ============================================================================ +; STAGING API SERVICES +; ============================================================================ + +; Staging REST API Service +api-staging.d-bis.org. 300 IN A 192.0.2.10 +api-staging.d-bis.org. 300 IN AAAA 2001:db8::10 + +; Staging Mapping Service +mappings.api-staging.d-bis.org. 300 IN A 192.0.2.11 +mappings.api-staging.d-bis.org. 300 IN AAAA 2001:db8::11 + +; Staging Webhook Service +webhooks.api-staging.d-bis.org. 300 IN A 192.0.2.12 +webhooks.api-staging.d-bis.org. 300 IN AAAA 2001:db8::12 + +; Staging Orchestrator Service +orchestrator.api-staging.d-bis.org. 300 IN A 192.0.2.13 +orchestrator.api-staging.d-bis.org. 300 IN AAAA 2001:db8::13 + +; Staging Packet Service +packets.api-staging.d-bis.org. 300 IN A 192.0.2.14 +packets.api-staging.d-bis.org. 300 IN AAAA 2001:db8::14 + +; ============================================================================ +; CNAME RECORDS (if using load balancers or CDN) +; ============================================================================ + +; Uncomment if using Cloudflare Load Balancer or CDN +; api.d-bis.org. 300 IN CNAME api-lb.d-bis.org. +; mappings.api.d-bis.org. 300 IN CNAME mappings-lb.d-bis.org. +; webhooks.api.d-bis.org. 300 IN CNAME webhooks-lb.d-bis.org. +; orchestrator.api.d-bis.org. 300 IN CNAME orchestrator-lb.d-bis.org. +; packets.api.d-bis.org. 300 IN CNAME packets-lb.d-bis.org. + +; ============================================================================ +; TXT RECORDS (for verification, SPF, etc.) +; ============================================================================ + +; SPF Record (if sending emails) +d-bis.org. 300 IN TXT "v=spf1 include:_spf.google.com ~all" + +; Domain verification (if needed) +d-bis.org. 300 IN TXT "google-site-verification=YOUR_VERIFICATION_CODE" + +; ============================================================================ +; MX RECORDS (if using email) +; ============================================================================ + +; Uncomment if email is needed +; d-bis.org. 300 IN MX 10 mail.d-bis.org. + +; ============================================================================ +; NS RECORDS (Cloudflare nameservers - update with your actual nameservers) +; ============================================================================ + +d-bis.org. 86400 IN NS ns1.cloudflare.com. +d-bis.org. 86400 IN NS ns2.cloudflare.com. + +; ============================================================================ +; SOA RECORD +; ============================================================================ + +d-bis.org. 3600 IN SOA ns1.cloudflare.com. admin.d-bis.org. ( + 2024010101 ; Serial + 3600 ; Refresh + 1800 ; Retry + 604800 ; Expire + 300 ; Minimum TTL + ) + diff --git a/cloudflare-dns.tf b/cloudflare-dns.tf new file mode 100644 index 0000000..abd1717 --- /dev/null +++ b/cloudflare-dns.tf @@ -0,0 +1,368 @@ +# Terraform configuration for Cloudflare DNS records +# +# Prerequisites: +# - Terraform installed (https://www.terraform.io/) +# - Cloudflare provider configured +# - Cloudflare API token with DNS:Edit permissions +# +# Usage: +# terraform init +# terraform plan +# terraform apply +# + +terraform { + required_providers { + cloudflare = { + source = "cloudflare/cloudflare" + version = "~> 4.0" + } + } +} + +# Configure the Cloudflare Provider +provider "cloudflare" { + api_token = var.cloudflare_api_token +} + +# Get zone ID +data "cloudflare_zones" "d_bis_org" { + filter { + name = "d-bis.org" + } +} + +# Variables +variable "cloudflare_api_token" { + description = "Cloudflare API token" + type = string + sensitive = true +} + +variable "production_api_ip" { + description = "Production REST API IPv4 address" + type = string + default = "192.0.2.1" +} + +variable "production_api_ipv6" { + description = "Production REST API IPv6 address" + type = string + default = "2001:db8::1" +} + +variable "production_mappings_ip" { + description = "Production Mapping Service IPv4 address" + type = string + default = "192.0.2.2" +} + +variable "production_mappings_ipv6" { + description = "Production Mapping Service IPv6 address" + type = string + default = "2001:db8::2" +} + +variable "production_webhooks_ip" { + description = "Production Webhook Service IPv4 address" + type = string + default = "192.0.2.3" +} + +variable "production_webhooks_ipv6" { + description = "Production Webhook Service IPv6 address" + type = string + default = "2001:db8::3" +} + +variable "production_orchestrator_ip" { + description = "Production Orchestrator Service IPv4 address" + type = string + default = "192.0.2.4" +} + +variable "production_orchestrator_ipv6" { + description = "Production Orchestrator Service IPv6 address" + type = string + default = "2001:db8::4" +} + +variable "production_packets_ip" { + description = "Production Packet Service IPv4 address" + type = string + default = "192.0.2.5" +} + +variable "production_packets_ipv6" { + description = "Production Packet Service IPv6 address" + type = string + default = "2001:db8::5" +} + +variable "staging_api_ip" { + description = "Staging REST API IPv4 address" + type = string + default = "192.0.2.10" +} + +variable "staging_api_ipv6" { + description = "Staging REST API IPv6 address" + type = string + default = "2001:db8::10" +} + +variable "staging_mappings_ip" { + description = "Staging Mapping Service IPv4 address" + type = string + default = "192.0.2.11" +} + +variable "staging_mappings_ipv6" { + description = "Staging Mapping Service IPv6 address" + type = string + default = "2001:db8::11" +} + +variable "staging_webhooks_ip" { + description = "Staging Webhook Service IPv4 address" + type = string + default = "192.0.2.12" +} + +variable "staging_webhooks_ipv6" { + description = "Staging Webhook Service IPv6 address" + type = string + default = "2001:db8::12" +} + +variable "staging_orchestrator_ip" { + description = "Staging Orchestrator Service IPv4 address" + type = string + default = "192.0.2.13" +} + +variable "staging_orchestrator_ipv6" { + description = "Staging Orchestrator Service IPv6 address" + type = string + default = "2001:db8::13" +} + +variable "staging_packets_ip" { + description = "Staging Packet Service IPv4 address" + type = string + default = "192.0.2.14" +} + +variable "staging_packets_ipv6" { + description = "Staging Packet Service IPv6 address" + type = string + default = "2001:db8::14" +} + +# Production DNS Records +# ====================== + +# Production REST API +resource "cloudflare_record" "api_production_a" { + zone_id = data.cloudflare_zones.d_bis_org.zones[0].id + name = "api" + type = "A" + value = var.production_api_ip + ttl = 1 # Auto + proxied = true +} + +resource "cloudflare_record" "api_production_aaaa" { + zone_id = data.cloudflare_zones.d_bis_org.zones[0].id + name = "api" + type = "AAAA" + value = var.production_api_ipv6 + ttl = 1 # Auto + proxied = true +} + +# Production Mapping Service +resource "cloudflare_record" "mappings_production_a" { + zone_id = data.cloudflare_zones.d_bis_org.zones[0].id + name = "mappings.api" + type = "A" + value = var.production_mappings_ip + ttl = 1 # Auto + proxied = true +} + +resource "cloudflare_record" "mappings_production_aaaa" { + zone_id = data.cloudflare_zones.d_bis_org.zones[0].id + name = "mappings.api" + type = "AAAA" + value = var.production_mappings_ipv6 + ttl = 1 # Auto + proxied = true +} + +# Production Webhook Service +resource "cloudflare_record" "webhooks_production_a" { + zone_id = data.cloudflare_zones.d_bis_org.zones[0].id + name = "webhooks.api" + type = "A" + value = var.production_webhooks_ip + ttl = 1 # Auto + proxied = true +} + +resource "cloudflare_record" "webhooks_production_aaaa" { + zone_id = data.cloudflare_zones.d_bis_org.zones[0].id + name = "webhooks.api" + type = "AAAA" + value = var.production_webhooks_ipv6 + ttl = 1 # Auto + proxied = true +} + +# Production Orchestrator Service +resource "cloudflare_record" "orchestrator_production_a" { + zone_id = data.cloudflare_zones.d_bis_org.zones[0].id + name = "orchestrator.api" + type = "A" + value = var.production_orchestrator_ip + ttl = 1 # Auto + proxied = true +} + +resource "cloudflare_record" "orchestrator_production_aaaa" { + zone_id = data.cloudflare_zones.d_bis_org.zones[0].id + name = "orchestrator.api" + type = "AAAA" + value = var.production_orchestrator_ipv6 + ttl = 1 # Auto + proxied = true +} + +# Production Packet Service +resource "cloudflare_record" "packets_production_a" { + zone_id = data.cloudflare_zones.d_bis_org.zones[0].id + name = "packets.api" + type = "A" + value = var.production_packets_ip + ttl = 1 # Auto + proxied = true +} + +resource "cloudflare_record" "packets_production_aaaa" { + zone_id = data.cloudflare_zones.d_bis_org.zones[0].id + name = "packets.api" + type = "AAAA" + value = var.production_packets_ipv6 + ttl = 1 # Auto + proxied = true +} + +# Staging DNS Records +# =================== + +# Staging REST API +resource "cloudflare_record" "api_staging_a" { + zone_id = data.cloudflare_zones.d_bis_org.zones[0].id + name = "api-staging" + type = "A" + value = var.staging_api_ip + ttl = 1 # Auto + proxied = true +} + +resource "cloudflare_record" "api_staging_aaaa" { + zone_id = data.cloudflare_zones.d_bis_org.zones[0].id + name = "api-staging" + type = "AAAA" + value = var.staging_api_ipv6 + ttl = 1 # Auto + proxied = true +} + +# Staging Mapping Service +resource "cloudflare_record" "mappings_staging_a" { + zone_id = data.cloudflare_zones.d_bis_org.zones[0].id + name = "mappings.api-staging" + type = "A" + value = var.staging_mappings_ip + ttl = 1 # Auto + proxied = true +} + +resource "cloudflare_record" "mappings_staging_aaaa" { + zone_id = data.cloudflare_zones.d_bis_org.zones[0].id + name = "mappings.api-staging" + type = "AAAA" + value = var.staging_mappings_ipv6 + ttl = 1 # Auto + proxied = true +} + +# Staging Webhook Service +resource "cloudflare_record" "webhooks_staging_a" { + zone_id = data.cloudflare_zones.d_bis_org.zones[0].id + name = "webhooks.api-staging" + type = "A" + value = var.staging_webhooks_ip + ttl = 1 # Auto + proxied = true +} + +resource "cloudflare_record" "webhooks_staging_aaaa" { + zone_id = data.cloudflare_zones.d_bis_org.zones[0].id + name = "webhooks.api-staging" + type = "AAAA" + value = var.staging_webhooks_ipv6 + ttl = 1 # Auto + proxied = true +} + +# Staging Orchestrator Service +resource "cloudflare_record" "orchestrator_staging_a" { + zone_id = data.cloudflare_zones.d_bis_org.zones[0].id + name = "orchestrator.api-staging" + type = "A" + value = var.staging_orchestrator_ip + ttl = 1 # Auto + proxied = true +} + +resource "cloudflare_record" "orchestrator_staging_aaaa" { + zone_id = data.cloudflare_zones.d_bis_org.zones[0].id + name = "orchestrator.api-staging" + type = "AAAA" + value = var.staging_orchestrator_ipv6 + ttl = 1 # Auto + proxied = true +} + +# Staging Packet Service +resource "cloudflare_record" "packets_staging_a" { + zone_id = data.cloudflare_zones.d_bis_org.zones[0].id + name = "packets.api-staging" + type = "A" + value = var.staging_packets_ip + ttl = 1 # Auto + proxied = true +} + +resource "cloudflare_record" "packets_staging_aaaa" { + zone_id = data.cloudflare_zones.d_bis_org.zones[0].id + name = "packets.api-staging" + type = "AAAA" + value = var.staging_packets_ipv6 + ttl = 1 # Auto + proxied = true +} + +# Outputs +output "zone_id" { + description = "Cloudflare Zone ID" + value = data.cloudflare_zones.d_bis_org.zones[0].id +} + +output "zone_name" { + description = "Cloudflare Zone Name" + value = data.cloudflare_zones.d_bis_org.zones[0].name +} + diff --git a/nginx-setup.md b/nginx-setup.md new file mode 100644 index 0000000..3bc7dbc --- /dev/null +++ b/nginx-setup.md @@ -0,0 +1,349 @@ +# Nginx Configuration Setup Guide + +This guide explains how to set up and deploy the nginx configuration for the eMoney Token Factory API. + +## Overview + +The nginx configuration handles: +- **10 production domains** (5 services × 2 protocols) +- **10 staging domains** (5 services × 2 protocols) +- SSL/TLS termination +- Load balancing +- Rate limiting +- Security headers +- Health checks + +## Prerequisites + +- Nginx 1.18+ installed +- SSL certificates for all domains +- Backend services running on specified ports +- Root or sudo access + +## Installation Steps + +### 1. Install Nginx + +```bash +# Ubuntu/Debian +sudo apt update +sudo apt install nginx + +# CentOS/RHEL +sudo yum install nginx + +# Verify installation +nginx -v +``` + +### 2. Backup Default Configuration + +```bash +sudo cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.backup +``` + +### 3. Copy Configuration File + +```bash +sudo cp nginx.conf /etc/nginx/nginx.conf +``` + +### 4. Create SSL Certificate Directories + +```bash +sudo mkdir -p /etc/ssl/certs +sudo mkdir -p /etc/ssl/private +sudo chmod 700 /etc/ssl/private +``` + +### 5. Install SSL Certificates + +For each domain, install SSL certificates: + +```bash +# Production domains +sudo cp api.d-bis.org.crt /etc/ssl/certs/ +sudo cp api.d-bis.org.key /etc/ssl/private/ +sudo cp api.d-bis.org-chain.crt /etc/ssl/certs/ + +# Repeat for all domains: +# - mappings.api.d-bis.org +# - webhooks.api.d-bis.org +# - orchestrator.api.d-bis.org +# - packets.api.d-bis.org +# - api-staging.d-bis.org +# - mappings.api-staging.d-bis.org +# - webhooks.api-staging.d-bis.org +# - orchestrator.api-staging.d-bis.org +# - packets.api-staging.d-bis.org + +# Set proper permissions +sudo chmod 644 /etc/ssl/certs/*.crt +sudo chmod 600 /etc/ssl/private/*.key +``` + +### 6. Update Upstream Server IPs + +Edit `/etc/nginx/nginx.conf` and replace placeholder IPs with actual backend server IPs: + +```bash +sudo nano /etc/nginx/nginx.conf +``` + +Update these sections: +- `upstream rest_api_production` - Replace `192.0.2.1:3000` +- `upstream mapping_service_production` - Replace `192.0.2.2:3004` +- `upstream webhook_service_production` - Replace `192.0.2.3:3001` +- `upstream orchestrator_service_production` - Replace `192.0.2.4:3002` +- `upstream packet_service_production` - Replace `192.0.2.5:3003` +- All staging upstreams similarly + +### 7. Test Configuration + +```bash +sudo nginx -t +``` + +Expected output: +``` +nginx: the configuration file /etc/nginx/nginx.conf syntax is ok +nginx: configuration file /etc/nginx/nginx.conf test is successful +``` + +### 8. Create Log Directories + +```bash +sudo mkdir -p /var/log/nginx +sudo chown nginx:nginx /var/log/nginx +``` + +### 9. Start and Enable Nginx + +```bash +sudo systemctl start nginx +sudo systemctl enable nginx +sudo systemctl status nginx +``` + +### 10. Verify Services + +```bash +# Check nginx is listening on ports +sudo netstat -tlnp | grep nginx +# Should show ports 80 and 443 + +# Test health endpoints +curl -k https://api.d-bis.org/health +curl -k https://mappings.api.d-bis.org/health +curl -k https://webhooks.api.d-bis.org/health +curl -k https://orchestrator.api.d-bis.org/health +curl -k https://packets.api.d-bis.org/health +``` + +## Configuration Details + +### Rate Limiting + +- **API endpoints**: 100 requests/minute with burst of 20 +- **Webhook endpoints**: 50 requests/minute with burst of 10 +- **Staging**: Reduced limits (burst of 10 for API, 5 for webhooks) + +### Upstream Configuration + +- **Load balancing**: Least connections algorithm +- **Health checks**: Max 3 failures, 30s timeout +- **Keepalive**: 32 connections per upstream + +### SSL/TLS + +- **Protocols**: TLSv1.2, TLSv1.3 +- **Ciphers**: Modern, secure cipher suites +- **Session cache**: 10MB shared cache +- **Session timeout**: 10 minutes +- **OCSP stapling**: Enabled + +### Security Headers + +- **HSTS**: 1 year with subdomains and preload +- **X-Frame-Options**: DENY +- **X-Content-Type-Options**: nosniff +- **X-XSS-Protection**: Enabled +- **Referrer-Policy**: strict-origin-when-cross-origin +- **CSP**: Default-src 'self' with script/style exceptions + +### Timeouts + +- **Connection**: 30 seconds +- **Send**: 60 seconds (120s for packet service) +- **Read**: 60 seconds (120s for packet service) +- **Keepalive**: 65 seconds + +## Monitoring + +### Log Locations + +- **Access log**: `/var/log/nginx/access.log` +- **Error log**: `/var/log/nginx/error.log` + +### Log Rotation + +Create `/etc/logrotate.d/nginx`: + +``` +/var/log/nginx/*.log { + daily + missingok + rotate 52 + compress + delaycompress + notifempty + create 0640 nginx adm + sharedscripts + postrotate + [ -f /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid` + endscript +} +``` + +### Health Check Monitoring + +Set up monitoring for health endpoints: + +```bash +# Example monitoring script +#!/bin/bash +for domain in api.d-bis.org mappings.api.d-bis.org webhooks.api.d-bis.org \ + orchestrator.api.d-bis.org packets.api.d-bis.org; do + if ! curl -f -s https://$domain/health > /dev/null; then + echo "ALERT: $domain health check failed" + # Send alert notification + fi +done +``` + +## Troubleshooting + +### Check Nginx Status + +```bash +sudo systemctl status nginx +sudo journalctl -u nginx -n 50 +``` + +### View Error Logs + +```bash +sudo tail -f /var/log/nginx/error.log +``` + +### Test Specific Configuration + +```bash +# Test configuration syntax +sudo nginx -t + +# Test specific server block +sudo nginx -T | grep -A 50 "server_name api.d-bis.org" +``` + +### Common Issues + +1. **SSL certificate errors** + - Verify certificate paths are correct + - Check certificate permissions (644 for .crt, 600 for .key) + - Ensure certificate chain is complete + +2. **502 Bad Gateway** + - Check backend services are running + - Verify upstream IPs and ports are correct + - Check firewall rules allow nginx to reach backends + +3. **Rate limiting too aggressive** + - Adjust `limit_req_zone` rates in http block + - Increase burst values in server blocks + +4. **Connection timeouts** + - Increase `proxy_connect_timeout`, `proxy_send_timeout`, `proxy_read_timeout` + - Check backend service response times + +## Reload Configuration + +After making changes: + +```bash +# Test configuration +sudo nginx -t + +# Reload nginx (graceful, no downtime) +sudo nginx -s reload + +# Or restart (brief downtime) +sudo systemctl restart nginx +``` + +## Firewall Configuration + +Ensure firewall allows HTTP/HTTPS: + +```bash +# UFW (Ubuntu) +sudo ufw allow 80/tcp +sudo ufw allow 443/tcp + +# firewalld (CentOS/RHEL) +sudo firewall-cmd --permanent --add-service=http +sudo firewall-cmd --permanent --add-service=https +sudo firewall-cmd --reload +``` + +## Performance Tuning + +### Worker Processes + +Set `worker_processes` to number of CPU cores: + +```nginx +worker_processes auto; # Auto-detects CPU cores +``` + +### Worker Connections + +Adjust based on expected load: + +```nginx +worker_connections 2048; # Increase for high traffic +``` + +### File Descriptors + +Increase system limits: + +```bash +# Edit /etc/security/limits.conf +nginx soft nofile 65535 +nginx hard nofile 65535 +``` + +## Backup and Recovery + +### Backup Configuration + +```bash +sudo tar -czf nginx-backup-$(date +%Y%m%d).tar.gz \ + /etc/nginx/nginx.conf \ + /etc/ssl/certs/ \ + /etc/ssl/private/ +``` + +### Restore Configuration + +```bash +sudo tar -xzf nginx-backup-YYYYMMDD.tar.gz -C / +sudo nginx -t +sudo systemctl reload nginx +``` + +## Support + +For nginx configuration issues, contact: infrastructure@d-bis.org + diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..899fb6f --- /dev/null +++ b/nginx.conf @@ -0,0 +1,720 @@ +# Nginx configuration for eMoney Token Factory API +# Matches DNS configuration for d-bis.org domain +# +# This configuration handles: +# - Production API services (api.d-bis.org, mappings.api.d-bis.org, etc.) +# - Staging API services (api-staging.d-bis.org, etc.) +# - SSL/TLS termination +# - Load balancing +# - Rate limiting +# - Security headers +# - Health checks + +# User and worker processes +user nginx; +worker_processes auto; +error_log /var/log/nginx/error.log warn; +pid /var/run/nginx.pid; + +events { + worker_connections 1024; + use epoll; + multi_accept on; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + # Logging format + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for" ' + 'rt=$request_time uct="$upstream_connect_time" ' + 'uht="$upstream_header_time" urt="$upstream_response_time"'; + + access_log /var/log/nginx/access.log main; + + # Basic settings + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 65; + types_hash_max_size 2048; + server_tokens off; + client_max_body_size 10M; + + # Gzip compression + gzip on; + gzip_vary on; + gzip_proxied any; + gzip_comp_level 6; + gzip_types text/plain text/css text/xml text/javascript + application/json application/javascript application/xml+rss + application/rss+xml font/truetype font/opentype + application/vnd.ms-fontobject image/svg+xml; + + # Rate limiting zones + limit_req_zone $binary_remote_addr zone=api_limit:10m rate=100r/m; + limit_req_zone $binary_remote_addr zone=api_burst:10m rate=10r/s; + limit_req_zone $binary_remote_addr zone=webhook_limit:10m rate=50r/m; + + # Connection limiting + limit_conn_zone $binary_remote_addr zone=conn_limit:10m; + limit_conn conn_limit 20; + + # Upstream servers - Production REST API + upstream rest_api_production { + least_conn; + server 192.0.2.1:3000 max_fails=3 fail_timeout=30s; + # Add more servers for high availability + # server 192.0.2.101:3000 max_fails=3 fail_timeout=30s; + keepalive 32; + } + + # Upstream servers - Production Mapping Service + upstream mapping_service_production { + least_conn; + server 192.0.2.2:3004 max_fails=3 fail_timeout=30s; + keepalive 32; + } + + # Upstream servers - Production Webhook Service + upstream webhook_service_production { + least_conn; + server 192.0.2.3:3001 max_fails=3 fail_timeout=30s; + keepalive 32; + } + + # Upstream servers - Production Orchestrator Service + upstream orchestrator_service_production { + least_conn; + server 192.0.2.4:3002 max_fails=3 fail_timeout=30s; + keepalive 32; + } + + # Upstream servers - Production Packet Service + upstream packet_service_production { + least_conn; + server 192.0.2.5:3003 max_fails=3 fail_timeout=30s; + keepalive 32; + } + + # Upstream servers - Staging REST API + upstream rest_api_staging { + least_conn; + server 192.0.2.10:3000 max_fails=3 fail_timeout=30s; + keepalive 32; + } + + # Upstream servers - Staging Mapping Service + upstream mapping_service_staging { + least_conn; + server 192.0.2.11:3004 max_fails=3 fail_timeout=30s; + keepalive 32; + } + + # Upstream servers - Staging Webhook Service + upstream webhook_service_staging { + least_conn; + server 192.0.2.12:3001 max_fails=3 fail_timeout=30s; + keepalive 32; + } + + # Upstream servers - Staging Orchestrator Service + upstream orchestrator_service_staging { + least_conn; + server 192.0.2.13:3002 max_fails=3 fail_timeout=30s; + keepalive 32; + } + + # Upstream servers - Staging Packet Service + upstream packet_service_staging { + least_conn; + server 192.0.2.14:3003 max_fails=3 fail_timeout=30s; + keepalive 32; + } + + # SSL Configuration + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384'; + ssl_prefer_server_ciphers off; + ssl_session_cache shared:SSL:10m; + ssl_session_timeout 10m; + ssl_session_tickets off; + ssl_stapling on; + ssl_stapling_verify on; + + # Security headers + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; + add_header X-Frame-Options "DENY" always; + add_header X-Content-Type-Options "nosniff" always; + add_header X-XSS-Protection "1; mode=block" always; + add_header Referrer-Policy "strict-origin-when-cross-origin" always; + add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline';" always; + + # ============================================================================ + # PRODUCTION SERVERS + # ============================================================================ + + # Production REST API - api.d-bis.org + server { + listen 80; + listen [::]:80; + server_name api.d-bis.org; + + # Redirect HTTP to HTTPS + return 301 https://$server_name$request_uri; + } + + server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + server_name api.d-bis.org; + + # SSL certificates (update paths) + ssl_certificate /etc/ssl/certs/api.d-bis.org.crt; + ssl_certificate_key /etc/ssl/private/api.d-bis.org.key; + ssl_trusted_certificate /etc/ssl/certs/api.d-bis.org-chain.crt; + + # Rate limiting + limit_req zone=api_limit burst=20 nodelay; + limit_req_status 429; + + # Health check endpoint (no rate limiting) + location = /health { + access_log off; + proxy_pass http://rest_api_production; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + # API endpoints + location /v1/ { + proxy_pass http://rest_api_production; + proxy_http_version 1.1; + proxy_set_header Connection ""; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Request-ID $request_id; + + # Timeouts + proxy_connect_timeout 30s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + + # Buffering + proxy_buffering on; + proxy_buffer_size 4k; + proxy_buffers 8 4k; + proxy_busy_buffers_size 8k; + } + + # Deny access to hidden files + location ~ /\. { + deny all; + access_log off; + log_not_found off; + } + } + + # Production Mapping Service - mappings.api.d-bis.org + server { + listen 80; + listen [::]:80; + server_name mappings.api.d-bis.org; + return 301 https://$server_name$request_uri; + } + + server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + server_name mappings.api.d-bis.org; + + ssl_certificate /etc/ssl/certs/mappings.api.d-bis.org.crt; + ssl_certificate_key /etc/ssl/private/mappings.api.d-bis.org.key; + ssl_trusted_certificate /etc/ssl/certs/mappings.api.d-bis.org-chain.crt; + + limit_req zone=api_limit burst=20 nodelay; + limit_req_status 429; + + location = /health { + access_log off; + proxy_pass http://mapping_service_production; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + location /v1/ { + proxy_pass http://mapping_service_production; + proxy_http_version 1.1; + proxy_set_header Connection ""; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Request-ID $request_id; + + proxy_connect_timeout 30s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + } + + location ~ /\. { + deny all; + access_log off; + log_not_found off; + } + } + + # Production Webhook Service - webhooks.api.d-bis.org + server { + listen 80; + listen [::]:80; + server_name webhooks.api.d-bis.org; + return 301 https://$server_name$request_uri; + } + + server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + server_name webhooks.api.d-bis.org; + + ssl_certificate /etc/ssl/certs/webhooks.api.d-bis.org.crt; + ssl_certificate_key /etc/ssl/private/webhooks.api.d-bis.org.key; + ssl_trusted_certificate /etc/ssl/certs/webhooks.api.d-bis.org-chain.crt; + + limit_req zone=webhook_limit burst=10 nodelay; + limit_req_status 429; + + location = /health { + access_log off; + proxy_pass http://webhook_service_production; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + location /v1/ { + proxy_pass http://webhook_service_production; + proxy_http_version 1.1; + proxy_set_header Connection ""; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Request-ID $request_id; + + proxy_connect_timeout 30s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + } + + location ~ /\. { + deny all; + access_log off; + log_not_found off; + } + } + + # Production Orchestrator Service - orchestrator.api.d-bis.org + server { + listen 80; + listen [::]:80; + server_name orchestrator.api.d-bis.org; + return 301 https://$server_name$request_uri; + } + + server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + server_name orchestrator.api.d-bis.org; + + ssl_certificate /etc/ssl/certs/orchestrator.api.d-bis.org.crt; + ssl_certificate_key /etc/ssl/private/orchestrator.api.d-bis.org.key; + ssl_trusted_certificate /etc/ssl/certs/orchestrator.api.d-bis.org-chain.crt; + + limit_req zone=api_limit burst=20 nodelay; + limit_req_status 429; + + location = /health { + access_log off; + proxy_pass http://orchestrator_service_production; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + location /v1/ { + proxy_pass http://orchestrator_service_production; + proxy_http_version 1.1; + proxy_set_header Connection ""; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Request-ID $request_id; + + proxy_connect_timeout 30s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + } + + location ~ /\. { + deny all; + access_log off; + log_not_found off; + } + } + + # Production Packet Service - packets.api.d-bis.org + server { + listen 80; + listen [::]:80; + server_name packets.api.d-bis.org; + return 301 https://$server_name$request_uri; + } + + server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + server_name packets.api.d-bis.org; + + ssl_certificate /etc/ssl/certs/packets.api.d-bis.org.crt; + ssl_certificate_key /etc/ssl/private/packets.api.d-bis.org.key; + ssl_trusted_certificate /etc/ssl/certs/packets.api.d-bis.org-chain.crt; + + limit_req zone=api_limit burst=20 nodelay; + limit_req_status 429; + + # Increase body size for packet downloads + client_max_body_size 50M; + + location = /health { + access_log off; + proxy_pass http://packet_service_production; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + location /v1/ { + proxy_pass http://packet_service_production; + proxy_http_version 1.1; + proxy_set_header Connection ""; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Request-ID $request_id; + + proxy_connect_timeout 30s; + proxy_send_timeout 120s; # Longer timeout for packet generation + proxy_read_timeout 120s; + } + + location ~ /\. { + deny all; + access_log off; + log_not_found off; + } + } + + # ============================================================================ + # STAGING SERVERS + # ============================================================================ + + # Staging REST API - api-staging.d-bis.org + server { + listen 80; + listen [::]:80; + server_name api-staging.d-bis.org; + return 301 https://$server_name$request_uri; + } + + server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + server_name api-staging.d-bis.org; + + ssl_certificate /etc/ssl/certs/api-staging.d-bis.org.crt; + ssl_certificate_key /etc/ssl/private/api-staging.d-bis.org.key; + ssl_trusted_certificate /etc/ssl/certs/api-staging.d-bis.org-chain.crt; + + limit_req zone=api_limit burst=10 nodelay; + limit_req_status 429; + + location = /health { + access_log off; + proxy_pass http://rest_api_staging; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + location /v1/ { + proxy_pass http://rest_api_staging; + proxy_http_version 1.1; + proxy_set_header Connection ""; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Request-ID $request_id; + + proxy_connect_timeout 30s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + } + + location ~ /\. { + deny all; + access_log off; + log_not_found off; + } + } + + # Staging Mapping Service - mappings.api-staging.d-bis.org + server { + listen 80; + listen [::]:80; + server_name mappings.api-staging.d-bis.org; + return 301 https://$server_name$request_uri; + } + + server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + server_name mappings.api-staging.d-bis.org; + + ssl_certificate /etc/ssl/certs/mappings.api-staging.d-bis.org.crt; + ssl_certificate_key /etc/ssl/private/mappings.api-staging.d-bis.org.key; + ssl_trusted_certificate /etc/ssl/certs/mappings.api-staging.d-bis.org-chain.crt; + + limit_req zone=api_limit burst=10 nodelay; + limit_req_status 429; + + location = /health { + access_log off; + proxy_pass http://mapping_service_staging; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + location /v1/ { + proxy_pass http://mapping_service_staging; + proxy_http_version 1.1; + proxy_set_header Connection ""; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Request-ID $request_id; + + proxy_connect_timeout 30s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + } + + location ~ /\. { + deny all; + access_log off; + log_not_found off; + } + } + + # Staging Webhook Service - webhooks.api-staging.d-bis.org + server { + listen 80; + listen [::]:80; + server_name webhooks.api-staging.d-bis.org; + return 301 https://$server_name$request_uri; + } + + server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + server_name webhooks.api-staging.d-bis.org; + + ssl_certificate /etc/ssl/certs/webhooks.api-staging.d-bis.org.crt; + ssl_certificate_key /etc/ssl/private/webhooks.api-staging.d-bis.org.key; + ssl_trusted_certificate /etc/ssl/certs/webhooks.api-staging.d-bis.org-chain.crt; + + limit_req zone=webhook_limit burst=5 nodelay; + limit_req_status 429; + + location = /health { + access_log off; + proxy_pass http://webhook_service_staging; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + location /v1/ { + proxy_pass http://webhook_service_staging; + proxy_http_version 1.1; + proxy_set_header Connection ""; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Request-ID $request_id; + + proxy_connect_timeout 30s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + } + + location ~ /\. { + deny all; + access_log off; + log_not_found off; + } + } + + # Staging Orchestrator Service - orchestrator.api-staging.d-bis.org + server { + listen 80; + listen [::]:80; + server_name orchestrator.api-staging.d-bis.org; + return 301 https://$server_name$request_uri; + } + + server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + server_name orchestrator.api-staging.d-bis.org; + + ssl_certificate /etc/ssl/certs/orchestrator.api-staging.d-bis.org.crt; + ssl_certificate_key /etc/ssl/private/orchestrator.api-staging.d-bis.org.key; + ssl_trusted_certificate /etc/ssl/certs/orchestrator.api-staging.d-bis.org-chain.crt; + + limit_req zone=api_limit burst=10 nodelay; + limit_req_status 429; + + location = /health { + access_log off; + proxy_pass http://orchestrator_service_staging; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + location /v1/ { + proxy_pass http://orchestrator_service_staging; + proxy_http_version 1.1; + proxy_set_header Connection ""; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Request-ID $request_id; + + proxy_connect_timeout 30s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + } + + location ~ /\. { + deny all; + access_log off; + log_not_found off; + } + } + + # Staging Packet Service - packets.api-staging.d-bis.org + server { + listen 80; + listen [::]:80; + server_name packets.api-staging.d-bis.org; + return 301 https://$server_name$request_uri; + } + + server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + server_name packets.api-staging.d-bis.org; + + ssl_certificate /etc/ssl/certs/packets.api-staging.d-bis.org.crt; + ssl_certificate_key /etc/ssl/private/packets.api-staging.d-bis.org.key; + ssl_trusted_certificate /etc/ssl/certs/packets.api-staging.d-bis.org-chain.crt; + + limit_req zone=api_limit burst=10 nodelay; + limit_req_status 429; + + client_max_body_size 50M; + + location = /health { + access_log off; + proxy_pass http://packet_service_staging; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + location /v1/ { + proxy_pass http://packet_service_staging; + proxy_http_version 1.1; + proxy_set_header Connection ""; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Request-ID $request_id; + + proxy_connect_timeout 30s; + proxy_send_timeout 120s; + proxy_read_timeout 120s; + } + + location ~ /\. { + deny all; + access_log off; + log_not_found off; + } + } + + # Default server - catch all undefined domains + server { + listen 80 default_server; + listen [::]:80 default_server; + server_name _; + return 444; + } + + server { + listen 443 ssl default_server; + listen [::]:443 ssl default_server; + server_name _; + ssl_certificate /etc/ssl/certs/default.crt; + ssl_certificate_key /etc/ssl/private/default.key; + return 444; + } +} +