nginx-api-key-proxy / README.md
AnthropicallyHuggingFaces's picture
Replace stub README with Space docs and configuration reference
777a862 verified
|
Raw History Blame Contribute Delete
3.31 kB
---
title: Nginx API Key Proxy
emoji: πŸ”
colorFrom: gray
colorTo: blue
sdk: docker
app_port: 7860
pinned: false
---
# Nginx API Key Proxy
Builds nginx **from source** and runs it as a reverse proxy that injects an
upstream **API key server-side**. Clients never need the key, and the key is
**never written into `nginx.conf`**.
## What this Space demonstrates
| Concern | Implementation |
| --- | --- |
| Build | `install-nginx.sh` compiles nginx 1.25.3 with `http_ssl`, `stream`, `realip`, `http_v2`, `threads`, `file_aio`, `stub_status` |
| Key discovery | Vault β†’ AWS Secrets Manager β†’ local files β†’ systemd units β†’ placeholder |
| Key at rest | Only `/etc/nginx-upstream.env` (`chmod 600`, root) |
| Key in config | **No** β€” `env upstream_api_key;` + `map` exposes it at runtime |
| Injection | `proxy_set_header Authorization "Bearer $api_key_value"` overrides any client header |
## Verifying the injection
Requests to `/model-api/` are proxied to the demo upstream, which echoes the
headers it received:
```bash
curl -s https://<space-subdomain>.hf.space/model-api/
```
The response shows `received_headers.Authorization` β€” a value nginx added
server-side. Send your own `Authorization` header and note it is **overridden**,
not passed through.
## Key sources (in precedence order)
| # | Source | Configuration |
| --- | --- | --- |
| 1 | Explicit env var | `UPSTREAM_API_KEY=...` |
| 2 | Cached secrets file | `/etc/nginx-secrets.env`, `/etc/nginx-upstream.env` |
| 3 | HashiCorp Vault | `VAULT_ADDR`, `VAULT_SECRET_PATH`, `VAULT_SECRET_FIELD` |
| 4 | Vault AppRole | `VAULT_ROLE_ID` + `VAULT_SECRET_ID_FILE` |
| 5 | AWS Secrets Manager | `AWS_SECRET_ID`, `AWS_SECRET_FIELD`, `AWS_REGION` |
| 6 | Local files | `/etc/myapp/api.key`, `/etc/myapp/secrets.env`, `/opt/app/.env`, `/etc/environment` |
| 7 | Backend systemd units | `myapp.service`, `model-api.service` |
| 8 | Placeholder | `__REPLACE_ME__` (visible, deliberately invalid) |
Tune `LOCAL_KEY_SOURCES` and `BACKEND_UNITS` in `install-nginx.sh` for your
real paths.
## Deploying on a systemd host
`install-nginx.sh` is written for a VM/EC2-style host:
```bash
sudo AWS_SECRET_ID=myapp/api-key AWS_REGION=us-east-1 ./install-nginx.sh
```
It installs the unit at `/etc/systemd/system/nginx.service` with
`EnvironmentFile=/etc/nginx-upstream.env` and enables it.
Vault via AppRole, avoiding a static token on disk:
```bash
sudo install -m 600 /dev/stdin /etc/vault-approle-secret-id <<< "$SECRET_ID"
sudo VAULT_ADDR=https://vault.example.com:8200 \
VAULT_SECRET_PATH=secret/data/myapp \
VAULT_ROLE_ID=... ./install-nginx.sh
```
## Honest limitations
- **The key is still on disk**, moved from `nginx.conf` to a root-only env file.
Truly diskless requires a vault agent or custom module.
- **Env vars are readable by root** via `/proc/<pid>/environ`. Inherent to the
`EnvironmentFile` mechanism.
- **Scraping `.env` / systemd files is heuristic** β€” it assumes simple
`KEY=value` lines and will miss values fetched from a vault at runtime.
- **No systemd in this container.** The unit file is written for parity but the
entrypoint runs nginx in the foreground.
- **Build time is several minutes** β€” nginx is compiled from source on every
image build rather than installed from a package.