HxHippy

API Gateway

Using Nginx as an API gateway with routing, rate limiting, and authentication.

Last updated: 2025-01-15

Basic API Gateway

upstream users_service {
    server 10.0.0.1:3001;
    server 10.0.0.2:3001;
}

upstream orders_service {
    server 10.0.0.3:3002;
    server 10.0.0.4:3002;
}

upstream products_service {
    server 10.0.0.5:3003;
}

server {
    listen 443 ssl http2;
    server_name api.example.com;

    # SSL
    ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;

    # Route to services
    location /api/users/ {
        proxy_pass http://users_service/;
        include snippets/proxy-headers.conf;
    }

    location /api/orders/ {
        proxy_pass http://orders_service/;
        include snippets/proxy-headers.conf;
    }

    location /api/products/ {
        proxy_pass http://products_service/;
        include snippets/proxy-headers.conf;
    }

    # Health check
    location /health {
        return 200 '{"status":"ok"}';
        add_header Content-Type application/json;
    }
}

API Gateway with Rate Limiting

# Rate limit zones
limit_req_zone $binary_remote_addr zone=api_general:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=api_auth:10m rate=3r/s;
limit_req_zone $http_authorization zone=api_user:10m rate=100r/s;

server {
    listen 443 ssl http2;
    server_name api.example.com;

    # General API endpoints
    location /api/ {
        limit_req zone=api_general burst=20 nodelay;
        proxy_pass http://backend;
    }

    # Auth endpoints (stricter)
    location /api/auth/ {
        limit_req zone=api_auth burst=5 nodelay;
        proxy_pass http://auth_service;
    }

    # User-specific rate limit (by token)
    location /api/v2/ {
        limit_req zone=api_user burst=50 nodelay;
        proxy_pass http://backend;
    }
}

API Gateway with Auth

# Auth subrequest
server {
    listen 443 ssl http2;
    server_name api.example.com;

    # Internal auth endpoint
    location = /auth/validate {
        internal;
        proxy_pass http://auth_service/validate;
        proxy_pass_request_body off;
        proxy_set_header Content-Length "";
        proxy_set_header X-Original-URI $request_uri;
        proxy_set_header X-Original-Method $request_method;
    }

    # Protected API endpoints
    location /api/ {
        auth_request /auth/validate;
        auth_request_set $auth_user $upstream_http_x_user_id;
        auth_request_set $auth_role $upstream_http_x_user_role;

        proxy_pass http://backend;
        proxy_set_header X-User-Id $auth_user;
        proxy_set_header X-User-Role $auth_role;
    }

    # Public endpoints
    location /api/public/ {
        proxy_pass http://backend;
    }
}

API Versioning

# Map-based versioning
map $http_accept $api_version {
    default "v1";
    ~application/vnd.api.v1 "v1";
    ~application/vnd.api.v2 "v2";
    ~application/vnd.api.v3 "v3";
}

upstream api_v1 {
    server 10.0.0.1:3000;
}

upstream api_v2 {
    server 10.0.0.2:3000;
}

upstream api_v3 {
    server 10.0.0.3:3000;
}

server {
    listen 443 ssl http2;
    server_name api.example.com;

    # URL-based versioning
    location /v1/ {
        proxy_pass http://api_v1/;
    }

    location /v2/ {
        proxy_pass http://api_v2/;
    }

    location /v3/ {
        proxy_pass http://api_v3/;
    }

    # Header-based versioning
    location /api/ {
        proxy_pass http://api_$api_version/;
    }
}

CORS Configuration

# CORS snippet
# /etc/nginx/snippets/cors.conf
set $cors_origin "";
set $cors_methods "GET, POST, PUT, DELETE, OPTIONS";
set $cors_headers "Authorization, Content-Type, X-Requested-With";

if ($http_origin ~* (https://example\.com|https://app\.example\.com)) {
    set $cors_origin $http_origin;
}

add_header Access-Control-Allow-Origin $cors_origin always;
add_header Access-Control-Allow-Methods $cors_methods always;
add_header Access-Control-Allow-Headers $cors_headers always;
add_header Access-Control-Max-Age 86400 always;

if ($request_method = OPTIONS) {
    return 204;
}

Complete API Gateway

# Rate limits
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;

# Upstreams
upstream users { server 10.0.0.1:3001; }
upstream orders { server 10.0.0.2:3002; }
upstream auth { server 10.0.0.3:3003; }

server {
    listen 443 ssl http2;
    server_name api.example.com;

    # SSL
    include snippets/ssl-params.conf;
    ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;

    # Logging
    access_log /var/log/nginx/api.access.log;
    error_log /var/log/nginx/api.error.log;

    # Rate limiting
    limit_req zone=api burst=20 nodelay;
    limit_req_status 429;

    # CORS
    include snippets/cors.conf;

    # Health
    location /health {
        return 200 '{"status":"ok"}';
        add_header Content-Type application/json;
    }

    # Auth (public)
    location /api/auth/ {
        proxy_pass http://auth/;
        include snippets/proxy-headers.conf;
    }

    # Protected routes
    location /api/users/ {
        auth_request /validate;
        proxy_pass http://users/;
        include snippets/proxy-headers.conf;
    }

    location /api/orders/ {
        auth_request /validate;
        proxy_pass http://orders/;
        include snippets/proxy-headers.conf;
    }

    location = /validate {
        internal;
        proxy_pass http://auth/validate;
        proxy_pass_request_body off;
        proxy_set_header Content-Length "";
        proxy_set_header Authorization $http_authorization;
    }
}
advanced Recipes Updated 2025-01-15
  • nginx
  • api gateway
  • microservices
  • routing
  • rate limiting