# TOTP Gateway
[](https://crates.io/crates/totp-gateway)
[](https://docs.rs/totp-gateway)
[](LICENSE)
[](https://www.rust-lang.org)
[](https://github.com/cloudflare/pingora)
**TOTP Gateway** is a lightweight, high-performance reverse proxy authentication gateway built on Cloudflare's [Pingora](https://github.com/cloudflare/pingora) framework.
It adds a **Two-Factor Authentication (TOTP)** layer in front of your internal admin panels, private tools, or sensitive API endpoints, effectively blocking unauthorized access. You can enhance security with just a single binary and a configuration file, without setting up complex authentication infrastructure.
## β¨ Key Features
* **π TOTP-based 2FA Enforcement**: Compatible with standard apps like Google Authenticator and Authy.
* **π High Performance**: Built on Pingora's asynchronous architecture for speed and stability.
* **π‘οΈ Robust Security Policies**:
* IP Blacklisting & Automatic Blocking (Brute-force protection).
* Configurable login attempts and ban duration.
* Session expiration control.
* **π Flexible Routing**: Supports Glob pattern matching for Hostnames (Subdomains) and Paths, plus perβroute protection toggle via `protect`.
* **π SSL/HTTPS Support**: Easily enable TLS via configuration.
* **π Hot Reload**: Apply configuration changes (`config.toml`) instantly without downtime.
* **π¨ Custom Login Page**: Fully customizable HTML login interface.

## π Changelog
### v 0.1.4
- Change: Make can cache non-protected routes by default.
### v 0.1.3
- Feature: Perβroute `protect` option to choose whether a route is secured by the gateway or proxied directly. Defaults to `true` for full backward compatibility. See the updated examples above and `example_config.toml`.
### v 0.1.2
- Fix: Make don't cache any pages by default. (Issued when use with Cloudflare Tunnel)
## π¦ Installation
### Option 1: Install from crates.io (Recommended)
```bash
cargo install totp-gateway
```
### Option 2: Build from Source
#### Prerequisites
* Rust Toolchain (1.85 or later recommended)
```bash
git clone https://github.com/your-username/totp-gateway.git
cd totp-gateway
cargo build --release
```
The compiled binary will be located at `target/release/totp-gateway` (or `totp-gateway.exe` on Windows).
## π Quick Start
1. **Generate Config**: Run the binary. If no config exists, it will automatically create `config.toml` from the default template.
```bash
./target/release/totp-gateway
```
2. **Edit Config**: Open `config.toml` and configure `bind_addr` and `totp_secret` to match your environment.
3. **Run**:
```bash
./target/release/totp-gateway --config config.toml
```
## βοΈ Configuration Guide
The `config.toml` file consists of the following sections:
### 1. Server Settings (`[server]`)
```toml
[server]
bind_addr = "0.0.0.0:25000" # Listening address and port
default_upstream = "127.0.0.1:8080" # Default upstream server if no route matches
# Trusted proxy configuration for real IP extraction
# Essential when running behind Cloudflare Tunnel, Nginx, etc.
trusted_proxies = [
["127.0.0.1/32", "CF-Connecting-IP"],
["10.0.0.0/8", "X-Forwarded-For"]
]
```
### 2. Authentication & Session (`[auth]`)
```toml
[auth]
# TOTP Secret (Base32 encoded). Register this key in your Authenticator app.
totp_secret = "JBSWY3DPEHPK3PXP"
# Load from file: totp_secret_file = "./secret.txt"
# Load from env: totp_secret_env = "MY_TOTP_SECRET"
# Path to custom login HTML file (optional)
login_page_file = "./login_page.html"
# Session duration in seconds. Default: 1800 (30 mins)
session_duration = 3600
```
### 3. Security Policy (`[security]`)
Core settings to defend against Brute-force attacks.
```toml
[security]
enabled = true # Enable security features
max_retries = 5 # Max failed attempts before banning
ban_duration = 3600 # IP ban duration (seconds)
ip_limit_duration = 3600 # Time window for tracking failures (seconds)
blacklist_size = 1000 # Max IPs in blacklist
blacklist_strategy = "overwrite" # "overwrite" (remove oldest) or "block" (reject new)
```
### 4. HTTPS/TLS (`[tls]`)
If this section is present, the server runs in HTTPS mode.
```toml
[tls]
cert_file = "./certs/fullchain.pem" # Path to certificate
key_file = "./certs/privkey.pem" # Path to private key
```
### 5. Routing Rules (`[[routes]]`)
Define multiple routes. Matched in order from top to bottom.
- Matching fields:
- `host`: glob pattern for hostname (e.g., `*.example.com`)
- `path`: glob pattern for path (e.g., `/admin/*`)
- `path_prefix`: simple prefix match for path (checked before host/path globs)
- Upstream target:
- `upstream_addr`: target `host:port`
- Protection control:
- `protect` (bool, default `true`): when `false`, the route bypasses authentication, sessions, blacklist, etc.
```toml
# 1. Route specific path to a different port (protected by default)
[[routes]]
path_prefix = "/admin"
upstream_addr = "127.0.0.1:9090"
protect = true
# 2. Subdomain matching (unprotected example)
[[routes]]
host = "api.example.com"
upstream_addr = "127.0.0.1:3000"
protect = false # bypass login and security for this route
# 3. Wildcard support
[[routes]]
host = "*.internal.com"
path = "/legacy/*"
upstream_addr = "127.0.0.1:4000"
protect = true
```
Tip:
- If no route matches, traffic goes to `server.default_upstream` and remains protected (equivalent to `protect = true`).
- If you need a public endpoint, define an explicit route with `protect = false`.
## π‘οΈ How It Works
1. User requests a resource via **TOTP Gateway**.
2. Gateway checks for a valid Session Cookie (`SID`).
3. **No Session**:
* User is redirected to the Login Page.
* User enters the TOTP code.
* **Success**: A session cookie is issued, and the request is proxied to the upstream server.
* **Failure**: Failure count increments. If it exceeds the limit, the IP is **Banned** temporarily.
4. **Valid Session**: Request is immediately proxied to the upstream server.
5. **Unprotected Route (`protect=false`)**: The gateway skips authentication and blacklist checks and proxies the request directly.
### Security Notes
- The fallback route (when no `[[routes]]` matches) is always protected. To expose a public endpoint, create a specific route and set `protect = false`.
- Be careful not to create a `protect = false` route that matches `/auth` unintentionally; doing so would proxy the login endpoint to your upstream instead of handling authentication.
- Blacklist and rate limiting do not apply to `protect = false` routes.
### Migration
- The `protect` field is optional and defaults to `true`. Existing configs without `protect` continue to work unchanged.
### Example: Mixed protected/unprotected
```toml
[server]
bind_addr = "0.0.0.0:25000"
default_upstream = "127.0.0.1:8080"
[auth]
totp_secret = "JBSWY3DPEHPK3PXP"
[[routes]]
# Public healthcheck endpoint
path = "/health"
upstream_addr = "127.0.0.1:8080"
protect = false
[[routes]]
# Protected admin area
path = "/admin/*"
upstream_addr = "127.0.0.1:9090"
protect = true
```
## π Performance
Built on Cloudflare's Pingora framework, TOTP Gateway delivers:
- **Low Latency**: Sub-millisecond proxy overhead
- **High Throughput**: Handles thousands of concurrent connections
- **Memory Efficient**: Minimal resource footprint
- **Production Ready**: Battle-tested async runtime
## π§ͺ Testing
Run the full test suite:
```bash
# Run all tests
cargo test
# Run with verbose output
cargo test -- --nocapture
# Run specific test
cargo test test_basic_auth_and_replay_protection
```
The test suite includes:
- Unit tests for core components
- Integration tests with mock upstream servers
- Security feature tests (rate limiting, IP banning)
- Session management tests
- Concurrent request handling tests
- Route protection tests (`protect = true/false`) validating bypass and enforcement behavior
## π€ Contributing
Bug reports, feature suggestions, and Pull Requests are welcome!
1. Fork the repository.
2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`).
3. Commit your changes (`git commit -m 'Add some AmazingFeature'`).
4. Push to the Branch (`git push origin feature/AmazingFeature`).
5. Open a Pull Request.
## π License
Distributed under the [MIT License](LICENSE).