refactor layout and structure

This commit is contained in:
Alisdair MacLeod
2026-01-21 13:52:22 +00:00
parent 2851e38a1f
commit 1d8390b935
51 changed files with 2298 additions and 4430 deletions

View File

@@ -1,177 +1,50 @@
# Netbird Reverse Proxy
A lightweight, configurable reverse proxy server with graceful shutdown support.
The NetBird Reverse Proxy is a separate service that can act as a public entrypoint to certain resources within a NetBird network.
At a high level, the way that it operates is:
- Configured routes are communicated from the Management server to the proxy.
- For each route the proxy creates a NetBird connection to the NetBird Peer that hosts the resource.
- When traffic hits the proxy at the address and path configured for the proxied resource, the NetBird Proxy brings up a relevant authentication method for that resource.
- On successful authentication the proxy will forward traffic onwards to the NetBird Peer.
## Features
Proxy Authentication methods supported are:
- No authentication
- Oauth2/OIDC
- Emailed Magic Link
- Simple PIN
- HTTP Basic Auth Username and Password
- Simple reverse proxy with customizable headers
- Configuration via environment variables or JSON file
- Graceful shutdown with configurable timeout
- Structured logging with logrus
- Configurable timeouts (read, write, idle)
- Health monitoring support
## Management Connection
## Building
The Proxy communicates with the Management server over a gRPC connection.
Proxies act as clients to the Management server, the following RPCs are used:
- Server-side streaming for proxied service updates.
- Client-side streaming for proxy logs.
```bash
# Build the binary
GOWORK=off go build -o bin/proxy ./cmd/proxy
## Authentication
# Or use make if available
make build
```
When a request hits the Proxy, it looks up the permitted authentication methods for the Host domain.
If no authentication methods are registered for the Host domain, then no authentication will be applied (for fully public resources).
If any authentication methods are registered for the Host domain, then the Proxy will first serve an authentication page allowing the user to select an authentication method (from the permitted methods) and enter the required information for that authentication method.
If the user is successfully authenticated, their request will be forwarded through to the Proxy to be proxied to the relevant Peer.
Successful authentication does not guarantee a successful forwarding of the request as there may be failures behind the Proxy, such as with Peer connectivity or the underlying resource.
## TLS
Due to the authentication provided, the Proxy uses HTTPS for its endpoint, even if the underlying service is HTTP.
Certificate generation can either be via ACME (by default, using Let's Encrypt, but alternative ACME providers can be used) or through certificate files.
When not using ACME, the proxy server attempts to load a certificate and key from the files `tls.crt` and `tls.key` in a specified certificate directory.
When using ACME, the proxy server will store generated certificates in the specified certificate directory.
## Configuration
The proxy can be configured using either environment variables or a JSON configuration file. Environment variables take precedence over file-based configuration.
### Environment Variables
| Variable | Description | Default |
|----------|-------------|---------|
| `NB_PROXY_LISTEN_ADDRESS` | Address to listen on | `:8080` |
| `NB_PROXY_TARGET_URL` | Target URL to proxy requests to | **(required)** |
| `NB_PROXY_READ_TIMEOUT` | Read timeout duration | `30s` |
| `NB_PROXY_WRITE_TIMEOUT` | Write timeout duration | `30s` |
| `NB_PROXY_IDLE_TIMEOUT` | Idle timeout duration | `60s` |
| `NB_PROXY_SHUTDOWN_TIMEOUT` | Graceful shutdown timeout | `10s` |
| `NB_PROXY_LOG_LEVEL` | Log level (debug, info, warn, error) | `info` |
### Configuration File
Create a JSON configuration file:
```json
{
"listen_address": ":8080",
"target_url": "http://localhost:3000",
"read_timeout": "30s",
"write_timeout": "30s",
"idle_timeout": "60s",
"shutdown_timeout": "10s",
"log_level": "info"
}
```
## Usage
### Using Environment Variables
```bash
export NB_PROXY_TARGET_URL=http://localhost:3000
export NB_PROXY_LOG_LEVEL=debug
./bin/proxy
```
### Using Configuration File
```bash
./bin/proxy -config config.json
```
### Combining Both
Environment variables override file configuration:
```bash
export NB_PROXY_LOG_LEVEL=debug
./bin/proxy -config config.json
```
### Docker Example
```bash
docker run -e NB_PROXY_TARGET_URL=http://backend:3000 \
-e NB_PROXY_LISTEN_ADDRESS=:8080 \
-p 8080:8080 \
netbird-proxy
```
## Architecture
The application follows a clean architecture with clear separation of concerns:
```
proxy/
├── cmd/
│ └── proxy/
│ └── main.go # Entry point, CLI handling, signal management
├── config.go # Configuration loading and validation
├── server.go # Server lifecycle (Start/Stop)
├── go.mod # Module dependencies
└── README.md
```
### Key Components
- **config.go**: Handles configuration loading from environment variables and files using the `github.com/caarlos0/env/v11` library
- **server.go**: Encapsulates the HTTP server and reverse proxy logic with proper lifecycle management
- **cmd/proxy/main.go**: Entry point that orchestrates startup, graceful shutdown, and signal handling
## Graceful Shutdown
The server handles SIGINT and SIGTERM signals for graceful shutdown:
1. Signal received (Ctrl+C or kill command)
2. Server stops accepting new connections
3. Existing connections are allowed to complete within the shutdown timeout
4. Server exits cleanly
Press `Ctrl+C` to trigger graceful shutdown:
```bash
^C2026-01-13 22:40:00 INFO Received signal: interrupt
2026-01-13 22:40:00 INFO Shutting down server gracefully...
2026-01-13 22:40:00 INFO Server stopped successfully
2026-01-13 22:40:00 INFO Server exited successfully
```
## Headers
The proxy automatically sets the following headers on proxied requests:
- `X-Forwarded-Host`: Original request host
- `X-Origin-Host`: Target backend host
- `X-Real-IP`: Client's remote address
## Error Handling
- Invalid backend connections return `502 Bad Gateway`
- All proxy errors are logged with details
- Configuration errors are reported at startup
## Development
### Prerequisites
- Go 1.25 or higher
- Access to `github.com/sirupsen/logrus`
- Access to `github.com/caarlos0/env/v11`
### Testing Locally
Start a test backend:
```bash
# Terminal 1: Start a simple backend
python3 -m http.server 3000
```
Start the proxy:
```bash
# Terminal 2: Start the proxy
export NB_PROXY_TARGET_URL=http://localhost:3000
./bin/proxy
```
Test the proxy:
```bash
# Terminal 3: Make requests
curl http://localhost:8080
```
## License
Part of the Netbird project.
NetBird Proxy deployment configuration is via flags or environment variables, with flags taking precedence over the environment.
The following deployment configuration is available:
| Flag | Env | Purpose | Default |
+------+-----+---------+---------+
| `-mgmt` | `NB_PROXY_MANAGEMENT_ADDRESS` | The address of the management server for the proxy to get configuration from. | `"https://api.netbird.io:443"` |
| `-addr` | `NB_PROXY_ADDRESS` | The address that the reverse proxy will listen on. | `":443` |
| `-cert-dir` | `NB_PROXY_CERTIFICATE_DIRECTORY` | The location that certficates are stored in. | `"./certs"` |
| `-acme-certs` | `NB_PROXY_ACME_CERTIFICATES` | Whether to use ACME to generate certificates. | `false` |
| `-acme-addr` | `NB_PROXY_ACME_ADDRESS` | The HTTP address the proxy will listen on to respond to HTTP-01 ACME challenges | `":80"` |
| `-acme-dir` | `NB_PROXY_ACME_DIRECTORY` | The directory URL of the ACME server to be used | `"https://acme-v02.api.letsencrypt.org/directory"` |