Deployment guide

Kong 3

Overview

Kong Gateway is an open-source API gateway and microservices ingress. It is a Lua/OpenResty data plane on top of nginx that handles routing, authentication, rate limiting, transformations and observability through its plugin ecosystem.

This image installs Kong Gateway 3.9.1 OSS Community Edition, pinned with apt-mark hold and backed by PostgreSQL 16 on loopback. The Admin API is bound strictly to 127.0.0.1:8001. Kong OSS has no Admin API authentication, so loopback is the security boundary. A first-boot oneshot wires up an example service, route, key-auth plugin and consumer, so the gateway handles real upstream traffic as soon as the VM finishes booting. The decK CLI is bundled at /usr/local/bin/deck for declarative configuration management.

What you get:

  • Kong Gateway 3.9.1 OSS Community Edition (Apache 2.0) from the official Cloudsmith repository gateway-39/noble, pinned with apt-mark hold kong=3.9.1
  • PostgreSQL 16 from Ubuntu noble main, with a per-VM kong role and kong database, listening on 127.0.0.1:5432 only
  • Admin API on 127.0.0.1:8001, loopback only and never exposed
  • Proxy plane on 0.0.0.0:8000 (HTTP) and 0.0.0.0:8443 (HTTPS)
  • decK CLI 1.59.1 at /usr/local/bin/deck for declarative config management
  • kong-firstboot.service oneshot, which runs the migrations bootstrap, generates the per-VM database password and consumer API key, writes /etc/kong/kong-firstboot.env and touches /var/lib/sac/data/kong-firstboot.done
  • kong-postboot.service oneshot, which waits for the Admin API, creates the example service, route, key-auth plugin and consumer through the Admin API, touches /var/lib/sac/data/kong-postboot.done and then disables itself
  • Per-VM credentials log at /stage/scripts/kong-credentials.log (root:root 0600) carrying KONG_DB_PASSWORD, KONG_CONSUMER_API_KEY and KONG_PROXY_URL
  • 24/7 SecureAnyCloud support

There is no web UI. Administer Kong OSS through the Admin API, the decK CLI or any Kong-compatible tooling.

Prerequisites

You need an active Azure subscription, an SSH key, and a virtual network with a subnet. Standard_B2s (4 GB RAM) is comfortable for a single-node Kong and PostgreSQL on the same VM.

In the network security group (NSG), allow 22/tcp inbound from your management CIDR. Allow 8000/tcp and 8443/tcp from any client CIDR that needs to reach the proxy. Never expose 8001/tcp. That port is the Admin API, and it has no authentication in Kong OSS.

Step 1-3: Deploy and connect over SSH

Deploy the VM from the Azure Marketplace, then connect over SSH.

ssh azureuser@<vm-ip>
4

Check service status and versions

Check that the services are running and note the installed versions.

sudo systemctl is-active kong.service postgresql.service kong-firstboot.service kong-postboot.service /usr/local/bin/kong version /usr/local/bin/deck version

All four services report active. Kong reports 3.9.1 and decK reports v1.59.1.

5

Read the per-VM credentials

Print the credentials log.

sudo cat /stage/scripts/kong-credentials.log

Note these values:

  • KONG_CONSUMER_API_KEY is the demo consumer's key-auth credential. You use it in Step 8.
  • KONG_PROXY_URL is the proxy address.
  • KONG_DB_PASSWORD is the per-VM PostgreSQL password Kong uses to reach its database.

The file is root:root 0600.

6

Check Admin API health

Query the Admin API status endpoint.

curl -sf http://127.0.0.1:8001/status | jq

The response shows the gateway's connection counters, lua_shared_dicts memory utilisation and database.reachable: true, which confirms a PostgreSQL round trip.

The Admin API listens on 127.0.0.1:8001 only. It is bound to loopback because the Kong OSS Admin API has no authentication, and exposing it would let any client reconfigure the gateway. For remote administration, tunnel through SSH with ssh -L 8001:127.0.0.1:8001 azureuser@<vm-ip>. You can also front the Admin API with a reverse proxy that does its own authentication.

7

List services and routes

List the services and routes that the first-boot oneshot created.

curl -sf http://127.0.0.1:8001/services | jq '.data[].name'
curl -sf http://127.0.0.1:8001/routes | jq '.data[].paths'

You see sac-firstboot-service and ["/example"]. This is the demo set up by the postboot oneshot. The service points to https://httpbin.org/anything, and a key-auth plugin protects the route.

8

Test the proxy with key-auth

Read the consumer's API key from the credentials log. Then call the proxy with and without the key.

KEY=$(sudo grep '^KONG_CONSUMER_API_KEY=' /stage/scripts/kong-credentials.log | cut -d= -f2)
curl -sf -H "apikey: $KEY" http://127.0.0.1:8000/example | jq '.url'
curl -sI http://127.0.0.1:8000/example | head -1

The first call returns the upstream URL string from httpbin.org, which shows that Kong proxied the request. The second call has no apikey header and returns HTTP/1.1 401 Unauthorized, which shows that the key-auth plugin enforces the credential.

9

Manage routes with the Admin API

Add a new service and route with the Admin API. This example adds a route on /github that proxies to https://api.github.com.

curl -s -X POST http://127.0.0.1:8001/services \
  -d 'name=github-api' \
  -d 'url=https://api.github.com'
curl -s -X POST http://127.0.0.1:8001/services/github-api/routes \
  -d 'name=github-route' \
  -d 'paths[]=/github'
curl -sf http://127.0.0.1:8001/routes | jq '.data[].paths'

To remove a route or service, send DELETE to the same endpoints.

curl -s -X DELETE http://127.0.0.1:8001/routes/github-route
curl -s -X DELETE http://127.0.0.1:8001/services/github-api
10

Manage routes with decK (declarative)

decK treats the gateway's configuration as a YAML file that you can keep under version control. Dump the current configuration, edit it, then sync it back.

sudo /usr/local/bin/deck gateway dump --kong-addr http://127.0.0.1:8001 -o /tmp/kong.yaml
sudo /usr/local/bin/deck gateway diff --kong-addr http://127.0.0.1:8001 /tmp/kong.yaml

dump writes a snapshot of every service, route, plugin, consumer and credential. diff shows the difference between the YAML file and the live gateway. It reports no changes immediately after a fresh dump.

To apply the YAML back, run deck gateway sync. In production, keep the YAML in git and run deck gateway sync from CI.

11

Add plugins

Kong's plugin ecosystem covers rate limiting, authentication (jwt, oauth2, basic-auth, ldap-auth), transformations, observability (prometheus, opentelemetry, zipkin), traffic control and more. Attach the rate-limiting plugin to the example service.

curl -s -X POST http://127.0.0.1:8001/services/sac-firstboot-service/plugins \
  -d 'name=rate-limiting' \
  -d 'config.minute=10'

Browse the full plugin catalogue at https://docs.konghq.com/hub/. You can attach plugins at the global, service, route or consumer scope.

12

Tune worker processes

Kong inherits nginx's worker model. Edit /etc/kong/kong.conf to set nginx_worker_processes.

sudo sed -i 's/^#nginx_worker_processes.*/nginx_worker_processes = auto/' /etc/kong/kong.conf
sudo systemctl restart kong.service

The defaults on Standard_B2s are:

  • admin_listen: 127.0.0.1:8001 (loopback only, which is the security boundary)
  • proxy_listen: 0.0.0.0:8000, 0.0.0.0:8443 ssl
  • database: postgres
  • pg_host: 127.0.0.1
  • nginx_worker_processes: auto (one worker per vCPU)

On bigger VMs, auto is usually the right choice for higher throughput. Kong's data plane is heavily I/O-bound and benefits from one worker per CPU core.

13

Open the proxy to public traffic

The NSG attached to this VM at deploy time already allows 8000/tcp and 8443/tcp from your chosen client CIDR. To restrict access further, for example to your CDN's egress ranges only, edit the NSG inbound rules in the Azure portal or run the following command.

az network nsg rule update -g <rg> --nsg-name <nsg> -n allow-kong-8000 \
  --source-address-prefixes <your-cidr>

Inside the VM, the Ubuntu firewall (ufw) is disabled, so Kong listens directly. If you enable ufw, add sudo ufw allow 8000/tcp and sudo ufw allow 8443/tcp.

14

Install a Let's Encrypt certificate

Kong has an official ACME plugin that handles Let's Encrypt issuance and renewal inside the gateway. Enable it with the following command.

curl -s -X POST http://127.0.0.1:8001/plugins \
  -d 'name=acme' \
  -d 'config.account_email=you@example.com' \
  -d 'config.tos_accepted=true' \
  -d 'config.domains[]=apps.example.com'

Point your domain's DNS A record at this VM, then run curl https://apps.example.com:8443/example. Kong requests a certificate from Let's Encrypt on the first request and serves it from then on. Kong's internal scheduler renews the certificate automatically.

Alternatively, terminate SSL at nginx or Caddy in front of Kong and proxy to 127.0.0.1:8000. This older pattern is useful if you already have a reverse proxy in front. For new deployments, the ACME plugin is the simpler choice.

15

Back up

Kong's only persistent state is its PostgreSQL database. Take a consistent backup while the gateway is running.

PASS=$(sudo grep '^KONG_DB_PASSWORD=' /stage/scripts/kong-credentials.log | cut -d= -f2-) PGPASSWORD="$PASS" pg_dump -h 127.0.0.1 -U kong kong | gzip > /var/backups/kong-db-$(date +%F).sql.gz
sudo cp /etc/kong/kong.conf /var/backups/kong.conf-$(date +%F)

If you manage Kong declaratively with decK (Step 10), also commit your YAML to git. The YAML and a fresh PostgreSQL pg_dump together form a complete, replayable backup. Copy /var/backups to Azure Blob Storage (az storage blob upload-batch) regularly to keep a copy off the VM.

16

Logs and troubleshooting

Read the service logs.

sudo journalctl -u kong.service --no-pager -n 80
sudo journalctl -u kong-firstboot.service --no-pager -n 30
sudo journalctl -u kong-postboot.service --no-pager -n 30
sudo tail -50 /usr/local/kong/logs/access.log
sudo tail -50 /usr/local/kong/logs/error.log

kong reload is a graceful nginx reload. It applies configuration changes without dropping in-flight connections.

sudo /usr/local/bin/kong reload

For a deeper inspection, the Admin API exposes everything: curl http://127.0.0.1:8001/status, /services, /routes, /plugins, /consumers, /upstreams and /targets. It also serves Prometheus-style metrics if you enable the prometheus plugin.

Security

  • The Admin API is bound to 127.0.0.1:8001 only. Kong OSS has no Admin API authentication, so loopback is the boundary. Never bind the Admin API to a routable interface.
  • PostgreSQL listens on 127.0.0.1:5432 only, and Kong is its only consumer.
  • A per-VM KONG_DB_PASSWORD (32 hex chars) is generated at first boot.
  • A per-VM KONG_CONSUMER_API_KEY is generated for the demo consumer. Rotate or replace it once you set up your own consumers.
  • NSG inbound opens 22/tcp, 8000/tcp and 8443/tcp only, never 8001/tcp.
  • Use the decK CLI's gateway diff workflow to catch unintended configuration drift before you apply changes.
  • Use the key-auth, jwt, oauth2 or basic-auth plugins on every public route. Kong does not authenticate requests by default.

Support

SecureAnyCloud provides 24/7/365 expert technical support, with a guaranteed response within 24 hours and a one-hour average for critical issues. Contact sales@secureanycloud.com.

Deploy on Azure

Launch Kong Gateway 3.9.1 OSS on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.

View this image

Need Help?

Our support team is available 24/7.

sales@secureanycloud.com

Deploy on Azure