first commit
This commit is contained in:
272
README.md
Normal file
272
README.md
Normal file
@@ -0,0 +1,272 @@
|
||||
# server18004 🚀
|
||||
|
||||
A high-performance, production-ready QR code generation server written in Rust. It utilizes the [Axum](https://github.com/tokio-rs/axum) web framework and is highly optimized for maximum execution speed, minimal memory footprint, and low-latency rendering.
|
||||
|
||||
The server leverages a multi-port paradigm to separate public restricted QR rendering from internal/unrestricted administration and generation APIs.
|
||||
|
||||
---
|
||||
|
||||
## 🌟 Key Features
|
||||
|
||||
- **Multi-Port Isolation**:
|
||||
- **Port 4081 (SVG)**: Restricted vector QR generation via catch-all/fallback handler.
|
||||
- **Port 4082 (PNG)**: Restricted high-speed raster QR generation.
|
||||
- **Port 4084 (AVIF)**: Restricted high-speed modern AVIF QR generation.
|
||||
- **Port 4083 (API)**: Unrestricted administration API for domain management and custom generation.
|
||||
- **High-Performance Graphic Encoders**:
|
||||
- **PNG Generator**: Features custom 4x manual bit-multiplication scaling to a 1-bit Grayscale raster buffer, completely bypassing expensive image scaling filters. Leverages the standard `png` crate with `Compression::Fast` and `FilterType::NoFilter` for low-latency output.
|
||||
- **AVIF Generator**: Leverages the speed of the `ravif` encoder operating in Speed 10 (Fastest) mode with Lossless quality, backed by a custom 4x RGBA scaling loop.
|
||||
- **Smart Reverse-Proxy Support**:
|
||||
- Resolves client hostnames by inspecting `X-Forwarded-Host`, `X-Real-Host`, and standard `Host` headers. Compatible with Nginx, HAProxy, and Apache reverse-proxy setups.
|
||||
- Detects request schema (HTTP vs HTTPS) using the `X-Forwarded-Proto` header.
|
||||
- **Domain Restricted Generation**:
|
||||
- Fallback endpoints validate the requester's base domain against an allowlist.
|
||||
- A designated default domain (e.g., `18004.pro`) is always allowed.
|
||||
- **Runtime Domain Management**:
|
||||
- Read-optimized, thread-safe memory storage (`Arc<RwLock<HashSet<String>>>`).
|
||||
- Dynamic API additions/removals with immediate, safe file persistence.
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Port & Routing Architecture
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
subgraph Restricted Ports (Allowlist Validation)
|
||||
P1[Port 4081: SVG] -->|Catch-all| H_SVG[Handle SVG]
|
||||
P2[Port 4082: PNG] -->|Catch-all| H_PNG[Handle PNG]
|
||||
P4[Port 4084: AVIF] -->|Catch-all| H_AVIF[Handle AVIF]
|
||||
end
|
||||
|
||||
subgraph Unrestricted Port
|
||||
P3[Port 4083: API] -->|POST /generate| API_GEN[Custom QR Generation]
|
||||
P3 -->|POST /domains/add| API_ADD[Add Domain]
|
||||
P3 -->|POST /domains/remove| API_REM[Remove Domain]
|
||||
P3 -->|GET /domains| API_LST[List Domains]
|
||||
P3 -->|GET /health| API_HLT[Health Check]
|
||||
end
|
||||
```
|
||||
|
||||
### 1. Restricted Endpoints (Ports 4081, 4082, 4084)
|
||||
These ports use fallback routes (catch-all). Any request path and query string will be automatically translated into a QR code pointing to the origin host & path.
|
||||
* **How it works**:
|
||||
1. The server reads the hostname from the incoming headers (checking `X-Forwarded-Host`, then `X-Real-Host`, then `Host`).
|
||||
2. The first subdomain is stripped (e.g., `qr.example.com` becomes `example.com`).
|
||||
3. The base domain is checked against the allowlist. If it's not present (and doesn't match the default domain), a `403 Forbidden` response is returned.
|
||||
4. If allowed, it generates a QR code encoding `<scheme>://<base-domain><path><query>` (e.g., `https://example.com/some/path?ref=123`).
|
||||
|
||||
### 2. Unrestricted Endpoints (Port 4083)
|
||||
A standard REST API for programmatic QR generation (without domain restrictions) and runtime control over the allowed domains.
|
||||
|
||||
---
|
||||
|
||||
## 📦 Installation & Setup
|
||||
|
||||
### Requirements
|
||||
- Rust (Cargo) 1.70+
|
||||
|
||||
### Local Development
|
||||
To run the server locally:
|
||||
```bash
|
||||
cargo run -- --config-path ./server.conf --domains-path ./domains.conf
|
||||
```
|
||||
|
||||
### Production Deployment
|
||||
The project comes with a robust installer (`install.sh`) that builds the release binary, creates a dedicated, unprivileged system user (`qrserver`), registers config templates, and configures a `systemd` service:
|
||||
|
||||
```bash
|
||||
# 1. Build and install with root/sudo privileges
|
||||
sudo ./install.sh
|
||||
|
||||
# 2. Start and enable the service
|
||||
sudo systemctl enable --now server18004
|
||||
|
||||
# 3. Verify the status and view logs
|
||||
sudo systemctl status server18004
|
||||
sudo journalctl -u server18004 -f
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ Configuration
|
||||
|
||||
### Server Configuration (`/etc/server18004/server.conf`)
|
||||
An easy-to-use TOML file configuring server ports and the default domain:
|
||||
|
||||
```toml
|
||||
# Port for restricted SVG QR code generation
|
||||
port_svg = 4081
|
||||
|
||||
# Port for restricted PNG QR code generation
|
||||
port_png = 4082
|
||||
|
||||
# Port for unrestricted JSON API
|
||||
port_api = 4083
|
||||
|
||||
# Port for restricted AVIF QR code generation
|
||||
port_avif = 4084
|
||||
|
||||
# Default domain that is always allowed on restricted ports
|
||||
default_domain = "example.com"
|
||||
```
|
||||
|
||||
### Domains Allowlist (`/etc/server18004/domains.conf`)
|
||||
A simple line-based text file. Comments starting with `#` and blank lines are ignored.
|
||||
```text
|
||||
# Allowed base domains
|
||||
example.com
|
||||
mycompany.org
|
||||
testdomain.dev
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📖 Sample Usage & API Specifications
|
||||
|
||||
### 1. Fallback QR Code Generation (Restricted Ports)
|
||||
|
||||
When navigating to or requesting any path from the restricted ports, a QR code is returned directly.
|
||||
|
||||
#### SVG Format (Port 4081)
|
||||
Assuming `example.com` is in the allowed domain list:
|
||||
```bash
|
||||
curl -i -H "Host: qr.example.com" http://localhost:4081/welcome?user=john
|
||||
```
|
||||
* **Result**: Returns an `image/svg+xml` payload containing a QR code that redirects to `https://example.com/welcome?user=john`.
|
||||
|
||||
#### PNG Format (Port 4082)
|
||||
```bash
|
||||
curl -i -H "Host: qr.example.com" http://localhost:4082/app/download
|
||||
```
|
||||
* **Result**: Returns an `image/png` payload containing a QR code encoding `https://example.com/app/download`.
|
||||
|
||||
#### AVIF Format (Port 4084)
|
||||
```bash
|
||||
curl -i -H "Host: qr.example.com" http://localhost:4084/promo
|
||||
```
|
||||
* **Result**: Returns an `image/avif` payload containing a QR code encoding `https://example.com/promo`.
|
||||
|
||||
---
|
||||
|
||||
### 2. Programmatic API (Port 4083)
|
||||
|
||||
The API port allows custom QR generation with flexible format settings and base64 options.
|
||||
|
||||
#### POST `/generate`
|
||||
Generates a QR code for arbitrary text content.
|
||||
|
||||
##### Payload Schema:
|
||||
```json
|
||||
{
|
||||
"text": "Your string here",
|
||||
"ecl": "L", // Error Correction Level: L, M, Q, H (Default: L)
|
||||
"format": "svg", // Output: svg, png, avif, base64, base64url (Default: svg)
|
||||
"base64_source": "png", // For base64: png, svg, avif (Default: png)
|
||||
"module_size": 10 // Optional custom scaling factor
|
||||
}
|
||||
```
|
||||
|
||||
##### Example 1: Direct PNG Output
|
||||
```bash
|
||||
curl -X POST http://localhost:4083/generate \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"text": "https://rust-lang.org",
|
||||
"format": "png",
|
||||
"ecl": "M"
|
||||
}' --output qr.png
|
||||
```
|
||||
|
||||
##### Example 2: Base64 Encoded JSON Response
|
||||
```bash
|
||||
curl -X POST http://localhost:4083/generate \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"text": "Hello World",
|
||||
"format": "base64",
|
||||
"base64_source": "svg"
|
||||
}'
|
||||
```
|
||||
**Response JSON**:
|
||||
```json
|
||||
{
|
||||
"data": "PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMyAzMyIgc2hhcGUtcmVuZGVyaW5nPSJjcmlzcEVkZ2VzIj4...",
|
||||
"format": "base64",
|
||||
"source": "svg"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. Domain Management API (Port 4083)
|
||||
|
||||
#### GET `/domains`
|
||||
Retrieves a list of all currently allowed domains.
|
||||
```bash
|
||||
curl http://localhost:4083/domains
|
||||
```
|
||||
**Response**:
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "3 domain(s) configured",
|
||||
"domains": ["example.com", "mycompany.org", "testdomain.dev"]
|
||||
}
|
||||
```
|
||||
|
||||
#### POST `/domains/add`
|
||||
Adds a domain to the allowlist and immediately persists it to the configuration file on disk.
|
||||
```bash
|
||||
curl -X POST http://localhost:4083/domains/add \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"domain": "newdomain.com"}'
|
||||
```
|
||||
**Response**:
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "Domain 'newdomain.com' added successfully",
|
||||
"domains": ["example.com", "mycompany.org", "testdomain.dev", "newdomain.com"]
|
||||
}
|
||||
```
|
||||
|
||||
#### POST `/domains/remove`
|
||||
Removes a domain from the allowlist and updates the file on disk.
|
||||
```bash
|
||||
curl -X POST http://localhost:4083/domains/remove \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"domain": "newdomain.com"}'
|
||||
```
|
||||
**Response**:
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "Domain 'newdomain.com' removed successfully",
|
||||
"domains": ["example.com", "mycompany.org", "testdomain.dev"]
|
||||
}
|
||||
```
|
||||
|
||||
#### GET `/health`
|
||||
Simple health check endpoint for proxy checking or system monitors.
|
||||
```bash
|
||||
curl -i http://localhost:4083/health
|
||||
```
|
||||
**Response**:
|
||||
```http
|
||||
HTTP/1.1 200 OK
|
||||
content-type: text/plain; charset=utf-8
|
||||
content-length: 2
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Testing
|
||||
|
||||
The codebase has a comprehensive suite of unit tests verifying domain manipulation, Host/IP extraction, and QR encoders.
|
||||
|
||||
To run the tests:
|
||||
```bash
|
||||
cargo test
|
||||
```
|
||||
```
|
||||
Reference in New Issue
Block a user