-
-
Save lcrilly/af4e351f300969455c8032fac5793045 to your computer and use it in GitHub Desktop.
How to Deploy NGINX as an API Gateway
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
log_format api_main '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$http_x_forwarded_for" "$api_name"'; | |
include api_backends.conf; | |
include api_keys.conf; | |
server { | |
set $api_name -; # Start with an undefined API name, each API will update this value | |
access_log /var/log/nginx/api_access.log api_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.1 TLSv1.2; | |
# 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 | |
} | |
# 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 | |
# | |
# swagger2nginx.sh (c) NGINX, Inc. [v0.3 03-Jul-2018] Liam Crilly <[email protected]> | |
# | |
# Requires shyaml for YAML processing: https://github.com/0k/shyaml | |
if [ $# -lt 1 ]; then | |
echo "### USAGE: `basename $0` [options] swagger_file.yaml" | |
echo "### Options:" | |
echo "### -b | --basepath <basePath> # Override Swagger basePath" | |
echo "### -l | --location # Create policy location (requires -u)" | |
echo "### -n | --api-name <API name> # Override Swagger title" | |
echo "### -p | --prefix <prefix path> # Apply prefix to basePath" | |
echo "### -u | --upstream <upstream name> # Specify upstream group" | |
exit 1 | |
fi | |
which shyaml | |
if [ $? -ne 0 ]; then | |
echo "### `basename $0` ERROR: shyaml not found, see https://github.com/0k/shyaml" | |
exit 1 | |
fi | |
API_NAME="" | |
DO_LOCATION=0 | |
BASEPATH="" | |
PREFIX_PATH="" | |
UPSTREAM="" | |
while [ $# -gt 1 ]; do | |
case "$1" in | |
"-b" | "--basepath") | |
BASEPATH=$2 | |
shift; shift | |
;; | |
"-l" | "--location") | |
DO_LOCATION=1 | |
shift | |
;; | |
"-n" | "--api-name") | |
API_NAME=$2 | |
shift; shift | |
;; | |
"-p" | "--prefix") | |
PREFIX_PATH=$2 | |
shift; shift | |
;; | |
"-u" | "--upstream") | |
UPSTREAM=$2 | |
shift; shift | |
;; | |
*) | |
echo "### `basename $0` ERROR: Invalid command line option ($1)" | |
exit 1 | |
;; | |
esac | |
done | |
if [ $DO_LOCATION -eq 1 ] && [ "$UPSTREAM" == "" ]; then | |
echo "### `basename $0` ERROR: Policy location requires upstream --upstream name" | |
exit 1 | |
fi | |
if [ ! -f $1 ]; then | |
echo "### `basename $0` ERROR: Cannot open $1" | |
exit 1 | |
fi | |
if [ "$API_NAME" == "" ]; then | |
# Convert title to NGINX-friendly API name | |
API_NAME=`shyaml get-value info.title < $1 | tr '[:space:]' '_' | tr -cd '[:alnum:]_-' 2> /dev/null` | |
if [ "$API_NAME" == "" ]; then | |
echo "### `basename $0` ERROR: Swagger file has missing/invalid title for API name" | |
exit 1 | |
fi | |
fi | |
if [ "$BASEPATH" == "" ]; then | |
BASEPATH=`shyaml get-value basePath < $1 2> /dev/null` | |
if [ "$BASEPATH" == "" ]; then | |
echo "### `basename $0` ERROR: No basePath found in Swagger" | |
exit 1 | |
fi | |
fi | |
BASEPATH=$PREFIX_PATH$BASEPATH | |
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 | |
echo "location = $BASEPATH$URI {" # Exact match when no path templates | |
else | |
echo "location ~ ^$BASEPATH$URI\$ {" # Regex match | |
fi | |
METHODS=`shyaml keys paths.$SWAGGER_PATH < $1 | grep -v parameters | tr '\n' ' '` | |
if [ "$METHODS" != "" ]; then | |
echo " limit_except $METHODS{ deny all; }" | |
echo " error_page 403 = @405;" | |
fi | |
if [ "$UPSTREAM" != "" ]; then | |
echo " set \$upstream $UPSTREAM;" | |
fi | |
echo " rewrite ^ /_$API_NAME last;" | |
echo "}" | |
done | |
if [ $DO_LOCATION -eq 1 ]; then | |
echo "" | |
echo "location = /_$API_NAME {" | |
echo " proxy_pass http://\$upstream\$request_uri;" | |
echo "}" | |
fi |
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
# API definition | |
# | |
location /api/warehouse/pricing { | |
limit_except GET POST {} | |
set $upstream pricing_service; | |
rewrite ^ /_warehouse last; | |
} | |
location /api/warehouse/inventory { | |
limit_except GET {} | |
set $upstream inventory_service; | |
rewrite ^(.*)$ /_warehouse$1 last; | |
} | |
# Policy section | |
# | |
location = /_warehouse { | |
internal; | |
set $api_name "Warehouse"; | |
if ($http_apikey = "") { | |
return 401; # Unauthorized (please authenticate) | |
} | |
if ($api_client_name = "") { | |
return 403; # Forbidden (invalid API key) | |
} | |
proxy_pass http://$upstream$request_uri; | |
} | |
# 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
# API definition (precise) | |
# | |
location = /api/warehouse/inventory { # Complete inventory | |
set $upstream inventory_service; | |
rewrite ^ /_warehouse last; | |
} | |
location ~ ^/api/warehouse/inventory/shelf/[^/]*$ { # Shelf inventory | |
set $upstream inventory_service; | |
rewrite ^ /_warehouse last; | |
} | |
location ~ ^/api/warehouse/inventory/shelf/[^/]*/box/[^/]*$ { # Box on shelf | |
set $upstream inventory_service; | |
rewrite ^ /_warehouse last; | |
} | |
location ~ ^/api/warehouse/pricing/[^/]*$ { # Price for specific item | |
set $upstream pricing_service; | |
rewrite ^ /_warehouse last; | |
} | |
# Policy section | |
# | |
location = /_warehouse { | |
internal; | |
set $api_name warehouse_api; | |
# Policy configuration here (authentication, rate limiting, logging, more...) | |
proxy_pass http://$upstream$request_uri; | |
} | |
# 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; | |
# API definition | |
# | |
location /api/warehouse/inventory { | |
set $upstream inventory_service; | |
rewrite ^(.*)$ /_warehouse$1 last; | |
} | |
location /api/warehouse/pricing { | |
set $upstream pricing_service; | |
rewrite ^(.*) /_warehouse$1 last; | |
} | |
# Policy section | |
# | |
location /_warehouse { | |
internal; | |
set $api_name "Warehouse"; | |
# Policy configuration here (authentication, rate limiting, logging, more...) | |
rewrite ^/_warehouse/(.*)$ /$1 break; # Remove /_warehouse prefix | |
proxy_pass http://$upstream; # Proxy the rewritten URI | |
} | |
# 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
# API definition | |
# | |
location /api/warehouse/inventory { | |
set $upstream warehouse_inventory; | |
rewrite ^ /_warehouse last; | |
} | |
location /api/warehouse/pricing { | |
set $upstream warehouse_pricing; | |
rewrite ^ /_warehouse last; | |
} | |
# Policy section | |
# | |
location = /_warehouse { | |
internal; | |
set $api_name "Warehouse"; | |
# Policy configuration here (authentication, rate limiting, logging, more...) | |
proxy_pass http://$upstream$request_uri; | |
} | |
# vim: syntax=nginx |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment