Getting Started

Project Structure

How the Quayel Gateway repository is organized and where the gateway keeps its files at runtime.

Project Structure

Repository layout

quayel-gateway/
├── setup.sh              # bootstrap: datasets + cargo packages
├── Dockerfile            # multi-stage image build (rust:1-bookworm → debian-slim)
├── docker-compose.yml    # SSL-ready compose file (ports 80/443, cert volume)
├── Cargo.toml            # crate dependencies
├── config.json           # live config (hot-reloaded on change)
├── config.demo.json      # full-featured demo config
├── config.all-rules.json # every feature enabled — used by the test suite
├── src/
│   ├── main.rs           # entry point
│   ├── gateway/          # Pingora proxy pipeline
│   ├── plugins/          # ip_intel, firewall, rate_limit, cache, load_balancer
│   ├── auto_ssl/         # ACME / Let's Encrypt automation
│   ├── condition/        # request matching engine
│   ├── config/           # JSON config loader + hot reload
│   ├── data/             # embedded MMDB + CIDR datasets (setup.sh)
│   └── utils/            # embedded_data, CIDR sets, helpers
├── docs/                 # full documentation (+ ai-guide.md, config.schema.json)
├── skills/               # AI skill package (skills/quayel-gateway/SKILL.md)
└── scripts/              # benchmarks, live test suite, nginx/APISIX mirrors
PathWhat it is for
setup.shOne-time bootstrap: downloads embedded datasets and installs the Rust toolchain + crates
src/gateway/The Pingora proxy pipeline: request context, upstream selection, response handling
src/plugins/Plugin implementations — IP intel, firewall, rate limiting, cache, load balancer
src/auto_ssl/On-demand ACME / Let's Encrypt certificate automation
src/condition/The matching engine shared by firewall, rate limit, cache, and LB rules
src/config/Config schema (schema.rs — authoritative) and loader (loader.rs — startup validation)
src/data/MMDB databases + CIDR lists, compiled into the binary via include_str!
docs/Markdown docs, ai-guide.md, and config.schema.json
skills/The portable AI skill package (install it)
scripts/Benchmarks and test-all-rules.sh (the 57-assertion live suite)

What setup.sh does

  1. Downloads the embedded datasets into src/data/ (latest versions):
    FileContent
    dbip-city-lite.mmdbDB-IP City Lite — country, region, city, lat/lon
    dbip-asn-lite.mmdbDB-IP ASN Lite — ASN + organization
    dbip-country.mmdbDB-IP Country Lite — country fallback
    cloudflare.txtCloudflare edge ranges (IPv4 + IPv6)
    hosting-asns.txtASNs known for hosting / abuse
    proxy.txtFireHOL anonymous proxy ranges
    tor.txtTor Project exit nodes
    vpn.txtX4BNet VPN provider ranges
    provider-asns.txt(versioned in repo, not downloaded) — provider ASN registry: ASN|Label (e.g. 47583|Hostinger)
  2. Installs cargo packages — Rust toolchain (rustup) and system build tools if missing, then fetches every crate dependency from Cargo.toml / Cargo.lock.

Flags: ./setup.sh --data-only · ./setup.sh --asns-only · ./setup.sh --cargo-only

Datacenter/hosting detection is ASN-based: the ASN MMDB resolves any client IP to its ASN, and provider-asns.txt + hosting-asns.txt classify the network. Adding a provider is one line in src/data/provider-asns.txt, then rebuild.

Runtime layout (Docker image)

PathPurpose
/usr/local/bin/quayel-gatewayThe gateway binary (entrypoint)
/etc/quayel-gateway/config.jsonThe config file (image WORKDIR is /etc/quayel-gateway)
/var/lib/quayel/certsAuto-SSL certificate storage — persist this as a volume
/var/log/quayel/access.jsonlStructured JSONL access log
PortPurpose
80HTTP — ACME HTTP-01 challenges + plain HTTP (map to container 8080)
443HTTPS — SNI cert resolver / Auto-SSL (map to container 8443)
8080 / 8443The demo config's listeners inside the container

Environment variables

VariableDefaultDescription
RUST_LOGinfoLog level (debug, info, warn, error)
QUAYEL_IP_INTEL_CACHE_SIZE65536LRU cache size for IP lookups

Config and hot reload

The gateway watches its config file and reloads it on change:

  • A valid save is applied without a restart (log line: Config hot-reloaded successfully).
  • An invalid save is rejected and the previous config keeps serving.
  • Edit atomically (write to a temp file, then rename) so the watcher never sees a half-written file.
Bump config_version on every config change — it is stamped into every log line so you can tell exactly which config handled a request. See Versioning.
Copyright © 2026