Corvus
Docker app from Jikwang's Repository
Overview
Unraid's own web interface usually uses ports 80 and 443, so this template publishes Corvus on 1880 (HTTP) and 18443 (HTTPS). Forward 80 and 443 from your router to these ports, or give the container its own IP (br0 / custom network). The one-time setup token for the first sign-in is in the container log; or set Setup Token before the first start.
Readme
View on GitHubEnglish · 한국어 · 简体中文 · 日本語 · Русский · Français · Deutsch · Español
Active Web Protection Gateway
External image (view source) External image (view source) External image (view source) External image (view source)
External image (view source) External image (view source) External image (view source) External image (view source) External image (view source) External image (view source) External image (view source) External image (view source)Corvus is a self-hosted gateway that sits in front of your web services. It is as easy to run as Nginx Proxy Manager — domains, forwarding and free SSL in a few clicks — and it also watches, protects and controls the traffic that passes through it: live monitoring, attack blocking, rate limiting and an access queue for traffic spikes. Everything runs on your own server; no traffic is sent to a third-party cloud.

Project Goal
Small teams usually end up with a reverse proxy for TLS, a separate WAF they never tune, and no idea what is happening when a launch or an attack hits. Corvus puts these in one box with safe defaults: basic attack detection works the moment a host is added, without writing a single rule, and every advanced option stays optional. The goal is a gateway you can install in five minutes and still trust on the day your traffic goes ten times higher.
Corvus is not a fork of Nginx Proxy Manager. It is a new implementation (OpenResty data plane, Go control plane, React console) that can import an existing NPM setup.
Features
Proxy & TLS
- Proxy hosts with wildcards, WebSocket, HTTP/2, forced HTTPS and custom Nginx snippets
- Notes on hosts and streams, to remember what each one is for (searchable)
- Custom locations: route paths (e.g.
/api) to their own upstream, with the host's protections - Redirection hosts: send domains to another domain (301/302/303/307/308, optionally keeping the path), with the same TLS and protection
- Free Let's Encrypt certificates (HTTP-01, or DNS-01 via Cloudflare, DigitalOcean, DuckDNS, Gandi, GoDaddy, Hetzner, Namecheap, with saved, reusable provider credentials) with automatic renewal, or upload your own (and replace it in place when it is renewed)
- Streams: forward TCP/UDP ports (databases, SSH, MQTT, game servers) to another host, with optional TLS termination for TCP
- Unknown host names get a 404 page, a closed connection or a redirect: your choice
- Real client IP behind Cloudflare or trusted proxies; optional password protection per host
- Security header presets per host (basic / strict: nosniff, frame and referrer policy, report-only CSP, HttpOnly/SameSite/Secure cookie flags), never overriding what the app already sends
- Gzip compression of text responses (on by default), and per-host upload size limit and upstream timeout
- Every change is validated with
openresty -t, applied atomically and can be rolled back - The console shows when a new Corvus release is out, with a link to its release notes (can be turned off)
Corvus Sentinel — security engine
- Security rules: match IP, IP list, country, path, query, method, header or User-Agent list → block, allow, log or challenge, globally or per host
- IP and User-Agent lists kept up to date from a URL (e.g. Tor exit nodes, bad-bot lists; presets included), refreshed in the background and redeployed only when they change
- Browser challenge without third-party services: a JavaScript proof of work (adjustable difficulty) or a lightweight cookie check, with a signed, IP-bound pass cookie
- "Under attack" mode per host: challenge every visitor — switched on by hand, or automatically while requests per second or the share of blocked requests exceed a threshold (with alerts when it turns on and off)
- Request body inspection for JSON, form and multipart bodies (log or block)
- One-click virtual patches for recent CVEs (React2Shell, wp2shell, PHP-CGI, Vite, n8n …)
- Managed signature updates, accepted only when signed and newer (no tampering, no downgrade)
- Automatic IP bans for repeat offenders, with escalation and exemptions; optional immediate bans on bad behaviour (too many 4xx responses per IP and site)
- Rate limits with a dry-run mode; exploit-path blocking out of the box
Access Queue
- Admit visitors up to a capacity and queue the rest fairly during spikes
- Admission rate, fail-open / fail-closed policy, live active/waiting counts, emergency release
- Waiting page localized in 8 languages
Monitoring & alerts
- Live requests/s, status codes, p50/p95/p99 latency, per-host and per-path breakdown
- Request log search and CSV/JSON export, security events, persistent history with retention and log rotation
- Alerts to Slack, Mattermost, Discord, Teams, Telegram or signed webhooks
- Prometheus
/metrics
Administration
- Roles, MFA (TOTP + recovery codes), OIDC single sign-on, API tokens
- Admin-console IP allowlist, audit log, deployment history
- SQLite by default or PostgreSQL; admin console in 8 languages with light and dark themes
Hardened by default
- Non-root containers with a read-only root filesystem and no Linux capabilities
- Redis protected by a generated password and a minimal ACL
- OpenResty built from signature-verified sources
Screenshots
| Traffic monitor | Security rules |
|---|---|
![]() |
![]() |
| Proxy host | Access queues |
![]() |
![]() |
Quick Setup
- Install Docker with the Compose plugin.
- Create a
docker-compose.ymlfile like this:
services:
corvus:
image: 'ghcr.io/corvus-gateway/gateway:latest'
restart: unless-stopped
ports:
- '80:80'
- '443:443'
- '9443:9443'
volumes:
- ./data:/data
This is the whole installation: gateway, admin console and access-queue store run in this one container. See the documentation for options.
- Bring up your stack by running
docker compose up -d
- Read the one-time setup token
docker compose logs corvus | grep setup_token
- Log in to the admin console at
https://<your-server>:9443, enter the token and create the first administrator. The console uses a self-signed certificate until you configure your own.
[!TIP] Point your domain's DNS at the server, add a proxy host, and request a Let's Encrypt certificate in the same form.
Upgrading
docker compose pull
docker compose up -d
Settings, certificates and history in ./data are kept; database changes are applied
automatically on start.
Documentation
Configuration, the hardened install, forward hosts, streams, backups, migrating from Nginx Proxy Manager, security rules, the access queue and troubleshooting are covered in the documentation (English · 한국어).
Performance
Measured with the benchmark workflow on a GitHub-hosted ubuntu-24.04
runner (4 vCPU AMD EPYC 9V45): Corvus pinned to 2 vCPU, wrk and the backend on the other two,
64 keep-alive connections, GET / with a 3-byte response.
| Scenario | req/s | p50 | p99 | Memory |
|---|---|---|---|---|
| nginx 1.28 reverse proxy (baseline) | 97,227 | 0.63 ms | 1.16 ms | 17 MB |
| Corvus, default host | 75,473 | 0.79 ms | 1.83 ms | 72 MB |
| Corvus, 30 rules + 1,000-CIDR list + exploit blocking + headers + rate limit | 54,585 | 1.12 ms | 2.29 ms | 77 MB |
| Corvus, HTTPS (ECDSA P-256), keep-alive | 59,697 | 1.00 ms | 2.18 ms | 80 MB |
| Corvus, HTTPS, new TLS handshake per request | 4,348 handshakes/s | 5.88 ms | 11.62 ms | 88 MB |
| Corvus, access queue (admitted visitors) | 57,954 | 1.05 ms | 2.22 ms | 84 MB |
| Corvus, challenge rule (visitors with a pass) | 62,901 | 0.96 ms | 1.94 ms | 88 MB |
On the base request path Corvus reaches about three quarters of plain nginx's throughput (keep-alive upstream pools, access log batched per worker); the full protection set — 30 rules with a 1,000-CIDR list, exploit blocking, security headers and a rate limit — costs about 28 % on top of that. Caveat: a shared CI runner with the load generator on the same machine and tiny responses — the numbers are conservative and meant for comparing scenarios and versions, not as capacity guarantees. Memory includes the control plane and embedded Valkey.
Development
npm --prefix web ci && npm --prefix web run build # admin UI → embedded into the Go binary
go test ./control/... # unit tests
go build -o bin/corvus-control ./control/cmd/corvus-control
CORVUS_GATEWAY=0 CORVUS_ADMIN_TLS=0 CORVUS_DATA_DIR=./tmp bin/corvus-control # console only, no OpenResty
| Path | Contents |
|---|---|
gateway/ |
Data plane: OpenResty + Lua (rules, body inspection, access queue) |
control/ |
Control plane (Go): settings DB, config generation, deploy/rollback, API |
web/ |
Admin console (React + Vite + TypeScript) |
deploy/ |
Dockerfile, verified OpenResty build, Compose files, integration tests |
tools/ |
Load-test and rule-bundle signing tools |
Security
Please report vulnerabilities privately — see SECURITY.md.
License
Apache License 2.0 © 2026 Jikwang Moon. IP-to-country data by DB-IP (CC BY 4.0). See NOTICE.
Media gallery
1 / 3Categories
Related apps
Explore more like this
Explore allDetails
ghcr.io/corvus-gateway/gateway:latestRuntime arguments
- Web UI
https://[IP]:[PORT:9443]- Network
bridge- Shell
sh- Privileged
- false
Template configuration
Admin console (HTTPS, self-signed certificate at first). Keep it closed to the internet.
- Target
- 9443
- Default
- 9443
- Value
- 9443
Your sites over HTTP and Let's Encrypt HTTP validation. Forward port 80 from your router here.
- Target
- 80
- Default
- 1880
- Value
- 1880
Your sites over HTTPS. Forward port 443 from your router here.
- Target
- 443
- Default
- 18443
- Value
- 18443
Database, certificates and encryption keys. Back up this folder, especially secrets/.
- Target
- /data
- Default
- /mnt/user/appdata/corvus
- Value
- /mnt/user/appdata/corvus
Optional: choose the one-time setup token for the first sign-in (at least 12 characters). Empty: a random token is written to the container log.
- Target
- CORVUS_SETUP_TOKEN
Optional: extra names or IPs for the admin console certificate, e.g. corvus.example.com,192.168.1.10
- Target
- CORVUS_ADMIN_HOSTS
User that owns the Data folder (Unraid default: 99, nobody).
- Default
- 99
- Value
- 99
Group that owns the Data folder (Unraid default: 100, users).
- Default
- 100
- Value
- 100



