Last active
January 31, 2026 03:18
-
-
Save jpawlowski/a20b5dc4f2df787ed67caf4ca451bde1 to your computer and use it in GitHub Desktop.
PowerDNS API Proxy configuration for NGINX, including API navigation via RapiDoc and API key management.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # /etc/nginx/sites-available/pdns-api | |
| # | |
| # `ln -s /etc/nginx/sites-available/pdns-api /etc/nginx/sites-enabled/pdns-api` | |
| map_hash_bucket_size 128; | |
| # --- MAPS GO HERE --- | |
| map $http_x_api_key:$remote_addr $internal_pdns_key { | |
| default ""; | |
| include /etc/powerdns/api-keys.map; | |
| } | |
| map $uri $ext_accept_header { | |
| default "application/json"; | |
| "~*\.json$" "application/json"; | |
| "~*\.ya?ml$" "application/x-yaml"; | |
| } | |
| # --- SERVER BLOCK --- | |
| server { | |
| listen 443 ssl; | |
| server_name fancyname.ns.example.com; | |
| include snippets/snakeoil.conf; | |
| # Real IP & Proxy Headers | |
| set_real_ip_from 192.0.2.1; | |
| real_ip_header X-Forwarded-For; | |
| proxy_set_header Host $host; | |
| proxy_set_header X-Real-IP $remote_addr; | |
| proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; | |
| # Custom Error Pages | |
| error_page 403 = @empty_403; | |
| error_page 404 = @json_404; | |
| # 1. Smart Docs (HTML vs Raw) | |
| location /api/docs { | |
| if ($http_accept ~* "json|yaml") { | |
| error_page 418 = @raw_docs; | |
| return 418; | |
| } | |
| default_type text/html; | |
| return 200 '<!doctype html><html><head><meta charset="utf-8"><script type="module" src="https://unpkg.com/rapidoc/dist/rapidoc-min.js"></script><title>$host</title></head><body><rapi-doc spec-url="/swagger.json" render-style="focused" show-header="false" allow-server-selection="false"><img slot="nav-logo" src="/.resources/pdns-logo.svg"/></rapi-doc></body></html>'; | |
| } | |
| location /.resources/pdns-logo.svg { | |
| proxy_pass https://upload.wikimedia.org/wikipedia/commons/9/9e/Logo_of_PowerDNS.svg; | |
| proxy_set_header Host upload.wikimedia.org; | |
| } | |
| # 2. Raw Docs Handler | |
| location @raw_docs { | |
| include snippets/pdns-secret.conf; | |
| rewrite ^ /api/docs break; | |
| proxy_pass http://127.0.0.1:8081; | |
| } | |
| # 3. Regex Path for .json | |
| location ~* ^/(openapi|swagger)\.json$ { | |
| include snippets/pdns-secret.conf; | |
| proxy_set_header Accept $ext_accept_header; | |
| # Inject servers list (could be multiple) | |
| sub_filter_once on; | |
| sub_filter_types application/json; | |
| sub_filter '"swagger": "2.0",' '"swagger": "2.0", "servers":[{"url":"https://secondary.ns.example.com/api/v1","description":"site-dns01 (internal DNS)"}],'; | |
| # CORS | |
| add_header "Access-Control-Allow-Origin" "https://$host,https://secondary.ns.example.com" always; | |
| add_header "Access-Control-Allow-Methods" "GET, OPTIONS" always; | |
| add_header "Access-Control-Allow-Headers" "DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,X-API-Key" always; | |
| rewrite ^ /api/docs break; | |
| proxy_pass http://127.0.0.1:8081; | |
| } | |
| # 4. Standard API v1 | |
| location /api/v1/ { | |
| if ($internal_pdns_key = "") { return 403; } | |
| include snippets/pdns-secret.conf; | |
| proxy_pass http://127.0.0.1:8081; | |
| } | |
| location /api { | |
| return 302 /api/docs; | |
| } | |
| location /metrics { | |
| rewrite ^ /metrics break; | |
| proxy_pass http://127.0.0.1:8081; | |
| } | |
| # 5. Fallback | |
| location = / { | |
| default_type text/html; | |
| return 200 '<!doctype html><html><head><meta charset="utf-8"><script type="module" src="https://unpkg.com/rapidoc/dist/rapidoc-min.js"></script><title>$host</title></head><body><rapi-doc spec-url="/swagger.json" render-style="focused" show-header="false" default-api-server="https://$host/api/v1"><img slot="nav-logo" src="/.resources/pdns-logo.svg"/></rapi-doc></body></html>'; | |
| } | |
| # Error Handlers | |
| location @empty_403 { | |
| add_header Content-Type application/problem+json always; | |
| return 403 '{"type":"https://$host/probs/forbidden","title":"Forbidden","status":403,"detail":"Invalid API Key or IP address"}'; | |
| } | |
| location @json_404 { | |
| add_header Content-Type application/problem+json always; | |
| return 404 '{"type":"https://$host/probs/not-found","title":"Not Found","status":404}'; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # /etc/nginx/snippets/pdns-secret.conf | |
| # | |
| # `chmod 640 /etc/nginx/snippets/pdns-secret.conf; chown :www-data /etc/nginx/snippets/pdns-secret.conf` | |
| proxy_set_header X-API-Key "changeme"; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # /etc/powerdns/api-keys.map | |
| # | |
| # `chmod 640 /etc/powerdns/api-keys.map; chown :www-data /etc/powerdns/api-keys.map` | |
| "MyExampleAPIkey:192.0.2.1" "site-fw01-v4"; | |
| "MyExampleAPIkey:2001:db8:0:0:8:800:200c:417a" "site-fw01-v6"; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment