-
-
Save nginx-gists/37ce65292a06219ff8d35d293c05e0b5 to your computer and use it in GitHub Desktop.
Deploying NGINX Plus as an API Gateway, Part 1
This file contains 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
upstream warehouse_inventory { | |
zone inventory_service 64k; | |
server 10.0.0.1:80; | |
server 10.0.0.2:80; | |
server 10.0.0.3:80; | |
} | |
upstream warehouse_pricing { | |
zone pricing_service 64k; | |
server 10.0.0.7:80; | |
server 10.0.0.8:80; | |
server 10.0.0.9:80; | |
} | |
# vim: syntax=nginx |
This file contains 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
include api_backends.conf; | |
include api_keys.conf; | |
server { | |
access_log /var/log/nginx/api_access.log main; # Each API may also log to a | |
# separate file | |
listen 443 ssl; | |
server_name api.example.com; | |
# TLS config | |
ssl_certificate /etc/ssl/certs/api.example.com.crt; | |
ssl_certificate_key /etc/ssl/private/api.example.com.key; | |
ssl_session_cache shared:SSL:10m; | |
ssl_session_timeout 5m; | |
ssl_ciphers HIGH:!aNULL:!MD5; | |
ssl_protocols TLSv1.2 TLSv1.3; | |
# API definitions, one per file | |
include api_conf.d/*.conf; | |
# Error responses | |
error_page 404 = @400; # Treat invalid paths as bad requests | |
proxy_intercept_errors on; # Do not send backend errors to client | |
include api_json_errors.conf; # API client-friendly JSON errors | |
default_type application/json; # If no content-type, assume JSON | |
} | |
# vim: syntax=nginx |
This file contains 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
include api_backends.conf; | |
include api_keys.conf; | |
server { | |
access_log /var/log/nginx/api_access.log main; # Each API may also log to a | |
# separate file | |
listen 443 ssl; | |
server_name api.example.com; | |
# TLS config | |
ssl_certificate /etc/ssl/certs/api.example.com.crt; | |
ssl_certificate_key /etc/ssl/private/api.example.com.key; | |
ssl_session_cache shared:SSL:10m; | |
ssl_session_timeout 5m; | |
ssl_ciphers HIGH:!aNULL:!MD5; | |
ssl_protocols TLSv1.2 TLSv1.3; | |
# API definitions, one per file | |
include api_conf.d/*.conf; | |
# Error responses | |
error_page 404 = @400; # Invalid paths are treated as bad requests | |
proxy_intercept_errors on; # Do not send backend errors to the client | |
include api_json_errors.conf; # API client friendly JSON error responses | |
default_type application/json; # If no content-type then assume JSON | |
# API key validation | |
location = /_validate_apikey { | |
internal; | |
if ($http_apikey = "") { | |
return 401; # Unauthorized | |
} | |
if ($api_client_name = "") { | |
return 403; # Forbidden | |
} | |
return 204; # OK (no content) | |
} | |
} | |
# vim: syntax=nginx |
This file contains 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
error_page 400 = @400; | |
location @400 { return 400 '{"status":400,"message":"Bad request"}\n'; } | |
error_page 401 = @401; | |
location @401 { return 401 '{"status":401,"message":"Unauthorized"}\n'; } | |
error_page 403 = @403; | |
location @403 { return 403 '{"status":403,"message":"Forbidden"}\n'; } | |
error_page 404 = @404; | |
location @404 { return 404 '{"status":404,"message":"Resource not found"}\n'; } | |
error_page 405 = @405; | |
location @405 { return 405 '{"status":405,"message":"Method not allowed"}\n'; } | |
error_page 408 = @408; | |
location @408 { return 408 '{"status":408,"message":"Request timeout"}\n'; } | |
error_page 413 = @413; | |
location @413 { return 413 '{"status":413,"message":"Payload too large"}\n'; } | |
error_page 414 = @414; | |
location @414 { return 414 '{"status":414,"message":"Request URI too large"}\n'; } | |
error_page 415 = @415; | |
location @415 { return 415 '{"status":415,"message":"Unsupported media type"}\n'; } | |
error_page 426 = @426; | |
location @426 { return 426 '{"status":426,"message":"HTTP request was sent to HTTPS port"}\n'; } | |
error_page 429 = @429; | |
location @429 { return 429 '{"status":429,"message":"API rate limit exceeded"}\n'; } | |
error_page 495 = @495; | |
location @495 { return 495 '{"status":495,"message":"Client certificate authentication error"}\n'; } | |
error_page 496 = @496; | |
location @496 { return 496 '{"status":496,"message":"Client certificate not presented"}\n'; } | |
error_page 497 = @497; | |
location @497 { return 497 '{"status":497,"message":"HTTP request was sent to mutual TLS port"}\n'; } | |
error_page 500 = @500; | |
location @500 { return 500 '{"status":500,"message":"Server error"}\n'; } | |
error_page 501 = @501; | |
location @501 { return 501 '{"status":501,"message":"Not implemented"}\n'; } | |
error_page 502 = @502; | |
location @502 { return 502 '{"status":502,"message":"Bad gateway"}\n'; } | |
# vim: syntax=nginx |
This file contains 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
map $http_apikey $api_client_name { | |
default ""; | |
"7B5zIqmRGXmrJTFmKa99vcit" "client_one"; | |
"QzVV6y1EmQFbbxOfRCwyJs35" "client_two"; | |
"mGcjH8Fv6U9y3BVF9H3Ypb9T" "client_six"; | |
} | |
# vim: syntax=nginx |
This file contains 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
user nginx; | |
worker_processes auto; | |
error_log /var/log/nginx/error.log notice; | |
pid /var/run/nginx.pid; | |
load_module /etc/nginx/modules/ngx_http_js_module.so; | |
events { | |
worker_connections 1024; | |
} | |
http { | |
include /etc/nginx/mime.types; | |
default_type application/octet-stream; | |
log_format main '$remote_addr - $remote_user [$time_local] "$request" ' | |
'$status $body_bytes_sent "$http_referer" ' | |
'"$http_user_agent" "$http_x_forwarded_for"'; | |
access_log /var/log/nginx/access.log main; | |
sendfile on; | |
#tcp_nopush on; | |
keepalive_timeout 65; | |
include /etc/nginx/api_gateway.conf; # All API gateway configuration | |
include /etc/nginx/conf.d/*.conf; # Regular web traffic | |
} |
This file contains 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
#!/usr/bin/env bash | |
# | |
# oas2nginx.sh (c) NGINX, Inc. [v0.5 13-Jan-2020] Liam Crilly <[email protected]> | |
# | |
# Converts OpenAPI/Swagger spec into nginx.conf snippet (server context) as per | |
# https://www.nginx.com/blog/deploying-nginx-plus-as-an-api-gateway-part-1/ | |
# Requires shyaml for YAML processing: https://github.com/0k/shyaml | |
# Defaults | |
# | |
BASEPATH="" | |
PREFIX_PATH="" | |
UPSTREAM="my_backend" | |
if [ $# -lt 1 ]; then | |
echo "USAGE: ${0##*/} [options] oas_spec.yaml" | |
echo " Converts OpenAPI/Swagger spec into nginx.conf snippet" | |
echo " Options:" | |
echo " -b | --basepath <basePath> # Override OAS basePath / servers path" | |
echo " -p | --prefix <prefix path> # Apply further prefix to basePath" | |
echo " -u | --upstream <upstream name> # Specify upstream group (default: $UPSTREAM)" | |
exit 1 | |
fi | |
which shyaml > /dev/null | |
if [ $? -ne 0 ]; then | |
echo "${0##*/} ERROR: shyaml not found, see https://github.com/0k/shyaml" | |
exit 1 | |
fi | |
while [ $# -gt 1 ]; do | |
case "$1" in | |
"-b" | "--basepath") | |
BASEPATH=$2 | |
shift; shift | |
;; | |
"-p" | "--prefix") | |
PREFIX_PATH=$2 | |
shift; shift | |
;; | |
"-u" | "--upstream") | |
UPSTREAM=$2 | |
shift; shift | |
;; | |
*) | |
echo "${0##*/} ERROR: Invalid command line option ($1)" | |
exit 1 | |
;; | |
esac | |
done | |
if [ ! -f $1 ]; then | |
echo "${0##*/} ERROR: Cannot open $1" | |
exit 1 | |
fi | |
if [ "$BASEPATH" == "" ]; then | |
OAS_VERSION=`shyaml -q get-value openapi < $1` | |
if [ $? -eq 0 ]; then | |
echo "${0##*/} INFO: OpenAPI $OAS_VERSION" > /dev/stderr | |
BASEPATH=`shyaml get-value servers < $1 2> /dev/null | grep url: | cut -f2- -d: | tail -1 | tr -d '[:blank:]'` | |
else | |
echo "${0##*/} INFO: OAS/Swagger v2" > /dev/stderr | |
BASEPATH=`shyaml -q get-value basePath < $1` | |
fi | |
if [ "$BASEPATH" == "" ]; then | |
echo "${0##*/}: WARNING: No basePath found in OAS" > /dev/stderr | |
BASEPATH=/ | |
fi | |
fi | |
if [ "`echo $BASEPATH | grep -c http`" == "1" ]; then | |
echo "${0##*/}: INFO: Stripping scheme and hostname from basepath URL" > /dev/stderr | |
BASEPATH=/`echo $BASEPATH | cut -f4- -d/` | |
fi | |
echo "${0##*/}: INFO: Using basePath $BASEPATH" | |
if [ "$PREFIX_PATH" != "" ]; then | |
echo "# Strip prefix" | |
echo "rewrite ^$PREFIX_PATH/\(.*\)$ \1 last;" | |
echo "" | |
fi | |
echo "location $BASEPATH/ {" | sed -e 's_//_/_g' | |
echo " # Policy section here" | |
echo " #" | |
echo " error_page 403 = @405;" | |
echo "" | |
for SWAGGER_PATH in `shyaml keys paths < $1`; do | |
# Convert path templates to regular expressions | |
URI=`echo $SWAGGER_PATH | sed -e "s/\({.*}\)/\[\^\/\]\+/g"` | |
if [ "$SWAGGER_PATH" == "$URI" ]; then | |
# Exact match when no path templates | |
echo " location = $BASEPATH$URI {" | sed -e 's_//_/_g' | |
else | |
# Regex match | |
echo " location ~ ^$BASEPATH$URI\$ {" | sed -e 's_//_/_g' | |
fi | |
ESCAPED_PATH=`echo $SWAGGER_PATH | sed -e 's/\./\\\./g'` | |
METHODS=`shyaml keys paths.$ESCAPED_PATH < $1 | grep -v parameters | tr '\n' ' '` | |
if [ "$METHODS" != "" ]; then | |
echo " limit_except $METHODS{ deny all; }" | |
fi | |
echo " proxy_pass http://$UPSTREAM;" | |
echo " }" | |
done | |
echo "" | |
echo " return 404;" | |
echo "}" |
This file contains 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
# Warehouse API | |
# | |
location /api/warehouse/ { | |
# Policy configuration here (authentication, rate limiting, logging...) | |
# | |
access_log /var/log/nginx/warehouse_api.log main; | |
auth_request /_validate_apikey; | |
# URI routing | |
# | |
location /api/warehouse/inventory { | |
proxy_pass http://warehouse_inventory; | |
} | |
location /api/warehouse/pricing { | |
proxy_pass http://warehouse_pricing; | |
} | |
return 404; # Catch-all | |
} | |
# vim: syntax=nginx |
This file contains 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
# Warehouse API (precise definition) | |
# | |
location /api/warehouse/ { | |
# Policy configuration here (authentication, rate limiting, logging...) | |
# | |
access_log /var/log/nginx/warehouse_api.log main; | |
# URI routing | |
# | |
location = /api/warehouse/inventory { # Complete inventory | |
proxy_pass http://warehouse_inventory; | |
} | |
location ~ ^/api/warehouse/inventory/shelf/[^/]+$ { # Shelf inventory | |
proxy_pass http://warehouse_inventory; | |
} | |
location ~ ^/api/warehouse/inventory/shelf/[^/]+/box/[^/]+$ { # Box on shelf | |
proxy_pass http://warehouse_inventory; | |
} | |
location ~ ^/api/warehouse/pricing/[^/]+$ { # Price for specific item | |
proxy_pass http://warehouse_pricing; | |
} | |
return 404; # Catch-all | |
} | |
# vim: syntax=nginx |
This file contains 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
# Rewrite rules | |
# | |
rewrite ^/api/warehouse/inventory/item/price/(.*) /api/warehouse/pricing/$1; | |
# Warehouse API | |
# | |
location /api/warehouse/ { | |
# Policy configuration here (authentication, rate limiting, logging...) | |
# | |
access_log /var/log/nginx/warehouse_api.log main; | |
# URI routing | |
# | |
location /api/warehouse/inventory { | |
proxy_pass http://warehouse_inventory; | |
} | |
location /api/warehouse/pricing { | |
proxy_pass http://warehouse_pricing; | |
} | |
return 404; # Catch-all | |
} | |
# vim: syntax=nginx |
This file contains 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
# Warehouse API | |
# | |
location /api/warehouse/ { | |
# Policy configuration here (authentication, rate limiting, logging...) | |
# | |
access_log /var/log/nginx/warehouse_api.log main; | |
# URI routing | |
# | |
location /api/warehouse/inventory { | |
proxy_pass http://warehouse_inventory; | |
} | |
location /api/warehouse/pricing { | |
proxy_pass http://warehouse_pricing; | |
} | |
return 404; # Catch-all | |
} | |
# vim: syntax=nginx |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
For a discussion of these files, see Deploying NGINX Plus as an API Gateway, Part 1