NapiGate Route-centric API gateway

Published Docker image. Built-in control plane. Protocols made explicit.

Install a real API gateway without adopting a platform.

NapiGate keeps the edge small and explicit: route-level protection, scoped clients, multiple auth methods, output profiles, response caching, trusted hooks, built-in monitor surfaces, and a published Docker image at napigate/napigate. It keeps HTTP ingress simple, supports HTTP and gRPC upstream execution today, and carries an explicit protocol catalog for services and routes so coverage does not collapse into one vague “HTTP-only” bucket.

Image: napigate/napigate Public port: 8000 Admin port: 8001 HTTP ingress + gRPC upstreams State: file or Postgres
4 route strategies
7 service protocol types
2 runtime transports implemented today
/__admin Operator-ready

Runtime surface

NapiGate operations

Healthy

Routes

24 single, failover, race, and round robin

Protocols

7 / 5 service and route protocol catalogs

State

RAM hot path never reads config from Postgres
protected_headers route auth + output profile + cache 200
hello_grpc HTTP route into a unary gRPC upstream 200
ws_demo declared protocol stays visible until runtime support lands 501

Route contract

Protection, targets, output, and protocol stay explicit.

Validated
routes:
  - slug: hello-grpc
    protocol: http
    gateway_path: /demo/grpc/hello
    methods: [POST]
    strategy: single
    targets:
      - service: greeter_grpc
        endpoint: say_hello

services:
  greeter_grpc:
    protocol: grpc
    target: localhost:50051

Published image

Use the Docker image directly.

napigate/napigate
mkdir -p napigate/{config,data,logs}
curl -L https://raw.githubusercontent.com/napigate/napigate/main/config/services.example.yaml -o napigate/config/services.yaml
curl -L https://raw.githubusercontent.com/napigate/napigate/main/config/security.example.yaml -o napigate/config/security.yaml

docker run -d --name napigate \
  -p 8000:8000 -p 8001:8001 \
  -v "$PWD/napigate/config:/code/config" \
  -v "$PWD/napigate/data:/code/data" \
  -v "$PWD/napigate/logs:/code/logs" \
  -e NAPIGATE_ADMIN_USERNAME=admin \
  -e NAPIGATE_ADMIN_PASSWORD=change-me \
  napigate/napigate:latest
Image includes Redis, Postgres, and gRPC extras

Overview

A gateway that stays understandable under real operational pressure.

NapiGate is designed for teams that want routing, auth, shaping, caching, and monitoring without dragging in a large control plane or opaque plugin ecosystem.

Route-centric exposure

Gateway paths, methods, strategies, and protection live on routes instead of being scattered across endpoint definitions.

Protocol-aware contract

Service and route protocol types stay explicit, so HTTP, gRPC, WebSocket, gRPC-Web, HTTP/3, TCP, and UDP are not flattened into one vague upstream shape.

Scoped clients

Attach multiple auth methods to each client and scope access to all services, selected services, or exact endpoints.

Output control

Shape responses with reusable output profiles, endpoint transforms, route envelopes, and safe custom logic.

Trusted hooks

Use pre_call and external_service to fetch tokens, validate requests, and enrich downstream calls.

Built-in operations

Live monitor, JSON logs, admin UI, audit trail, and daily rotating file logs ship as part of the product surface.

Optional backends

Keep config file-backed, or move state to Postgres. Add Redis only when distributed rate limiting and response caching matter.

Coverage

Broader protocol coverage, without pretending every transport is identical.

NapiGate now keeps an APISIX-inspired protocol catalog visible in config and admin. The runtime is deliberately honest: HTTP ingress is the stable edge today, and actual execution currently covers HTTP upstreams plus unary gRPC upstreams.

Available now

REST and JSON APIs

Match routes by method and path, inject headers and query values, shape output, and cache successful responses.

Available now

GraphQL over HTTP

Front GraphQL services like any other HTTP target when you need auth, monitoring, route scoping, or admin visibility at the edge.

Available now

Webhooks and callbacks

Accept inbound partner traffic and trigger downstream async success hooks or structured log forwarding after successful gateway responses.

Available now

Unary gRPC upstreams

Keep HTTP on the public side while calling gRPC services behind the route with reflection or descriptor-set backed method resolution.

Available now

SOAP, XML, and form-encoded flows

Keep the gateway contract readable while proxying legacy HTTP integrations that still rely on XML bodies, headers, cookies, or form fields.

Available now

Token brokers and auth facades

Use pre_call and external_service to fetch tokens, validate credentials, or bridge awkward auth flows.

Declared today

WebSocket, gRPC-Web, and HTTP/3

These protocol types are already first-class in the config and admin contract so future runtime work does not start from a route model that only understood plain HTTP.

Declared today

TCP and UDP upstream classes

Service protocol types also cover lower-level stream shapes. Unsupported transports fail loudly instead of being mislabeled as ordinary HTTP.

Protocol catalog

Keep protocol intent readable in the config itself.

Services: http grpc websocket grpc_web http3 tcp udp
Routes: http websocket grpc grpc_web http3

Runtime truth

Support is explicit, and so are the gaps.

  • Implemented: route=http -> service=http
  • Implemented: route=http -> service=grpc
  • Declared but not executed yet: WebSocket, gRPC ingress, gRPC-Web, HTTP/3, TCP, UDP
  • Unsupported protocol matches return 501 instead of silently faking HTTP semantics.

Operational control

Keep admin and monitor surfaces close to the runtime.

  • Separate public and admin listeners by default
  • Live request visibility through HTML, JSON, and SSE monitor endpoints
  • Admin audit log for service, route, client, and security changes
  • File-backed or Postgres-backed state with in-memory runtime snapshots
  • Protocol catalog visible in the same admin surface that operators already use

Request lifecycle

  1. Match the incoming method and path to a route.
  2. Resolve route targets and enforce route-level protection.
  3. Run trusted hook code, rate limits, and cache checks.
  4. Execute the configured upstream transport, shape output, and record monitor data.

Config model

Readable enough to review in a pull request, explicit enough to debug at 2 AM.

clients:
  - slug: partner-ops
    code: partner_ops
    title: Partner Operations
    access:
      mode: endpoints
      endpoints:
        - service: protected_httpbin
          endpoint: protected_headers
    auth_methods:
      - code: partner_oauth
        type: oauth_client_credentials
        client_id: demo-client-id
        client_secret: demo-client-secret

routes:
  - slug: hello-grpc
    protocol: http
    gateway_path: /demo/grpc/hello
    auth: { required: true }

services:
  greeter_grpc:
    protocol: grpc
    target: localhost:50051

What stays explicit

One top-level client model

No service-local client blocks to hunt down later.

Protection follows the route

Auth requirements stay with the public gateway path that operators actually expose.

Protocols stay declared

Service and route protocol types stay visible in admin and YAML instead of getting lost behind generic base_url fields.

Cache precedence is visible

Endpoint first, then service, then route, with optional Redis when the hot path grows beyond one process.

Reverse proxy aware

Trusted proxy IPs, separate admin URLs, and public versus admin listeners are all part of the runtime contract.

Unsupported does not masquerade as supported

Declared but unimplemented protocol matches fail with a direct 501 instead of half-working under HTTP assumptions.

Install

Pick the install path that matches how your team already ships software.

The fastest path is the published Docker image. If you want the full repo workflow, NapiGate also ships a runtime Compose stack and a direct Python entrypoint.

Recommended

Run the published Docker image

Use the image directly from Docker Hub when you want the shortest path from download to a running gateway.

mkdir -p napigate/{config,data,logs}
curl -L https://raw.githubusercontent.com/napigate/napigate/main/config/services.example.yaml -o napigate/config/services.yaml
curl -L https://raw.githubusercontent.com/napigate/napigate/main/config/security.example.yaml -o napigate/config/security.yaml

docker run -d --name napigate \
  -p 8000:8000 -p 8001:8001 \
  -v "$PWD/napigate/config:/code/config" \
  -v "$PWD/napigate/data:/code/data" \
  -v "$PWD/napigate/logs:/code/logs" \
  -e NAPIGATE_ADMIN_USERNAME=admin \
  -e NAPIGATE_ADMIN_PASSWORD=change-me \
  napigate/napigate:latest

Repo runtime

Use Docker Compose from source

Clone the main repo when you want the published runtime image plus the full local config, data, and logs layout.

git clone https://github.com/napigate/napigate.git
cd napigate
cp .env.example .env
cp config/services.example.yaml config/services.yaml
cp config/security.example.yaml config/security.yaml
docker compose pull
docker compose up -d

Source install

Run from Python

Install locally when you want to hack on the gateway itself, step through runtime behavior, or package your own image.

git clone https://github.com/napigate/napigate.git
cd napigate
pip install .
# Optional when you want local gRPC upstream support outside Docker:
# pip install ".[grpc]"
cp config/services.example.yaml config/services.yaml
cp config/security.example.yaml config/security.yaml
python3 -m gateway.main \
  --host 0.0.0.0 \
  --port 8000 \
  --admin-host 0.0.0.0 \
  --admin-port 8001 \
  --config config/services.yaml \
  --security-config config/security.yaml

Optional backends

Turn on Postgres, Redis, or source-side gRPC extras only when you need them

Keep the default install light, then add state, distributed caching, or local development extras when your operational footprint grows.

# Optional Postgres-backed state
docker compose --profile postgres up -d

# In .env
NAPIGATE_STATE_STORE=postgres
NAPIGATE_POSTGRES_DSN=postgresql://napigate:napigate@postgres:5432/napigate

# Optional Redis-backed cache and rate limiting
NAPIGATE_REDIS_URL=redis://localhost:6379/0

# Optional local source extras for gRPC upstream work
pip install ".[grpc]"

After boot

Know where each surface lives.

  • Public health: http://127.0.0.1:8000/__health
  • OAuth token endpoint: http://127.0.0.1:8000/__oauth/token
  • Admin UI: http://127.0.0.1:8001/__admin
  • Monitor UI: http://127.0.0.1:8001/__monitor

Why the split matters

Keep admin off the public port.

NapiGate does not expose /__admin, /__monitor, or /__logout on the public listener. That makes firewall and reverse-proxy isolation much simpler.

For teams that still read their own infrastructure

NapiGate keeps the gateway understandable from install to production.