Skip to content

Commit b5d6c11

Browse files
committed
feature: apex init command & architecture docs
1 parent 7acc04a commit b5d6c11

5 files changed

Lines changed: 217 additions & 33 deletions

File tree

.github/docs/architecture.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Apex Proxy Architectural Documentation
2+
3+
This document describes the CLI layout, and administrative mechanisms implemented inside Apex Proxy.
4+
5+
## 1. CLI Structure & Commands
6+
7+
The CLI layer uses `github.com/spf13/cobra` to expose operational controls:
8+
9+
* `apex init`: Installs the running binary into `/usr/local/bin`, creates the configuration path `/etc/apex/`, writes the default `apex.yaml` file, and hooks the runtime up to `systemd` via a managed `apexproxy.service` file. Must be executed with root privileges (`UID 0`).
10+
* `apex start`: Starts the reverse proxy engine. It binds to the configured server ports and mounts an unexposed internal metrics runtime on a separate goroutine (`127.0.0.1:9090`).
11+
* `apex status`: Fires an isolated Bubble Tea TUI instance that reads real-time stats from the internal metrics endpoint.
12+
13+
### Systemd Service Blueprint
14+
The service file deployed by the lifecycle initialization runs with a high file descriptor threshold to sustain heavy connection volumes:
15+
16+
```ini
17+
[Unit]
18+
Description=Apex Proxy Server
19+
After=network.target
20+
21+
[Service]
22+
Type=simple
23+
ExecStart=/usr/local/bin/apex start --config /etc/apex/apex.yaml
24+
Restart=always
25+
RestartSec=5
26+
LimitNOFILE=65536
27+
28+
[Install]
29+
WantedBy=multi-user.target
30+
```
31+
32+
## 2. Metrics Engine & Inter-process Communication
33+
34+
Telemetry is separated from standard client data traffic pipelines. The backend mounts a dedicated telemetry router bound to `127.0.0.1:9090` exposing two structural endpoints:
35+
36+
* `GET /metrics`: Returns a structural JSON block mapping active operational status (`ProxyStats`).
37+
* `GET /reset`: Clears the stored metric state variables.
38+
39+
### Security Token Enforcement
40+
41+
To guarantee that local processes requesting system state have authorization clearance, the communication layer utilizes an inline cryptographic signature check via `metrics.SignRequest(req)`. Requests hitting the internal management endpoints without verified authentication headers or from interfaces outside localhost are rejected.
42+
43+
## 3. TUI Architecture (`apex status`)
44+
45+
The terminal visual system uses `github.com/charmbracelet/bubbletea` as an Event-Driven loop executing asynchronously from the primary proxy system.
46+
47+
### Loop Cycle Lifecycle
48+
49+
1. **Init Event**: Fires concurrent `fetchMetrics()` and a time-based tick command (`time.Tick` every 1 second).
50+
2. **Update Event**: Receives either a metric package payload (`responseMsg`), an error context (`errorMsg`), or standard keystrokes.
51+
3. **State Modifiers**:
52+
* `q` / `ctrl+c`: Aborts execution cleanly.
53+
* `p`: Sets a `paused` Boolean flag inside the internal data model, halting viewport updates while the backend continue accumulating structural traffic data.
54+
* `r`: Dispatches an automated network trigger payload targeting the `/reset` handler to set operational values back to baseline zero.

README.md

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
[![Go Reference](https://pkg.go.dev/badge/github.com/niix-dan/apexproxy.svg)](https://pkg.go.dev/github.com/niix-dan/apexproxy)
66
[![License: MIT](https://img.shields.io/badge/license-MIT-blue)](LICENSE)
77

8-
A lightweight, high-performance reverse proxy and load balancer written in Go, featuring an instant, zero-dependency TUI dashboard for real-time traffic monitoring.
8+
A lightweight, high-performance reverse proxy and load balancer written in Go, featuring a zero-dependency TUI dashboard for real-time traffic monitoring.
99

10-
> Work in progress. Core proxy engine and TUI dashboard are functional.
10+
> **Note:** Work in progress. The core proxy engine and TUI dashboard are functional.
1111
1212
## Features
1313

@@ -18,30 +18,52 @@ A lightweight, high-performance reverse proxy and load balancer written in Go, f
1818
- Real-time TUI dashboard (`apex status`)
1919
- Internal metrics endpoint on `:9090` (localhost-only, HMAC-signed)
2020

21-
## Installation
21+
## Quick Start
2222

23+
### Installation
24+
25+
26+
### Installation
2327
```bash
2428
go install github.com/niix-dan/apexproxy@latest
2529
```
2630

27-
## Usage
31+
### Initialization (Linux / systemd)
32+
33+
Run the init command as root to install the binary to `/usr/local/bin`, generate the default configuration in `/etc/apex/apex.yaml`, and start the systemd background service:
34+
35+
```bash
36+
sudo $(which apexproxy) init
37+
```
38+
39+
### CLI Usage
2840

2941
```bash
30-
apex start --config ./apex.yaml
42+
# Start the proxy server in foreground (uses apex.yaml by default)
43+
apex start --config /etc/apex/apex.yaml
44+
45+
# Open the real-time TUI metrics dashboard
3146
apex status
3247
```
3348

34-
## Configuration
49+
## Configuration Example
50+
51+
The configuration is managed via `/etc/apex/apex.yaml`:
3552

3653
```yaml
3754
server:
3855
http_port: 80
3956
https_port: 443
40-
auto_tls: false
57+
auto_tls: true
4158
tls:
4259
cert_file: "/etc/ssl/certs/server.crt"
4360
key_file: "/etc/ssl/certs/server.key"
4461

62+
logging:
63+
csv_enabled: true
64+
csv_path: "/var/log/apex.csv"
65+
redact_headers: ["Authorization", "Cookie"]
66+
4567
middlewares:
4668
rate_limit:
4769
enabled: true
@@ -88,12 +110,12 @@ routing:
88110
- [x] Round-robin (weighted) and ip-hash load balancing
89111
- [x] Metrics collection (latency, bandwidth, status codes, per-route stats)
90112
- [x] TUI dashboard
113+
- [x] `apex init` command
114+
- [x] Automatic TLS via Let's Encrypt
91115
- [ ] Hot-reload via `fsnotify` (no dropped connections)
92116
- [ ] Rate limiting (token bucket)
93-
- [ ] Response compression
94-
- [x] Automatic TLS via Let's Encrypt
117+
- [ ] Response compression middleware
95118
- [ ] `dynamic-lookup` strategy (Redis)
96-
- [ ] `apex init` command
97119
- [ ] Unit tests
98120

99121
## License

apex.yaml

Lines changed: 5 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
# apex.yaml
1+
# Apex Proxy Configuration
2+
# High-performance reverse proxy configuration file
23

34
server:
45
http_port: 80
56
https_port: 443
67
auto_tls: true
7-
logging:
8+
9+
logging:
810
csv_enabled: true
911
csv_path: "/var/log/apex.csv"
1012
redact_headers: ["Authorization", "Cookie"]
@@ -28,28 +30,9 @@ routing:
2830
- url: "http://127.0.0.1:3001"
2931
weight: 1
3032

31-
- host: example.com
32-
path: /auth
33-
strategy: ip-hash
34-
priority: 90
35-
targets:
36-
- url: "http://10.0.0.5:8080"
37-
3833
- host: example.com
3934
path: /
4035
strategy: single
4136
priority: 10
4237
targets:
43-
- url: "http://127.0.0.1:5173"
44-
45-
- host: "*.saas-app.com"
46-
strategy: dynamic-lookup
47-
priority: 50
48-
resolver: "redis://localhost:6379"
49-
50-
# Default catch-all route if no other routes match (optional)
51-
- path: /
52-
strategy: single
53-
priority: 1
54-
targets:
55-
- url: "http://127.0.0.1:3000"
38+
- url: "http://127.0.0.1:5173"

cmd/init.go

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"os/exec"
7+
8+
"github.com/spf13/cobra"
9+
)
10+
11+
const defaultYAML = `# Apex Proxy Configuration
12+
# High-performance reverse proxy configuration file
13+
14+
server:
15+
http_port: 80
16+
https_port: 443
17+
auto_tls: true
18+
19+
logging:
20+
csv_enabled: true
21+
csv_path: "/var/log/apex.csv"
22+
redact_headers: ["Authorization", "Cookie"]
23+
24+
middlewares:
25+
rate_limit:
26+
enabled: true
27+
requests_per_minute: 1000
28+
compression:
29+
enabled: true
30+
types: ["text/html", "application/json"]
31+
32+
routing:
33+
- host: api.example.com
34+
path: /
35+
strategy: round-robin
36+
priority: 100
37+
targets:
38+
- url: "http://127.0.0.1:3000"
39+
weight: 3
40+
- url: "http://127.0.0.1:3001"
41+
weight: 1
42+
43+
- host: example.com
44+
path: /
45+
strategy: single
46+
priority: 10
47+
targets:
48+
- url: "http://127.0.0.1:5173"
49+
`
50+
51+
const systemdTemplate = `[Unit]
52+
Description=Apex Proxy Server
53+
After=network.target
54+
55+
[Service]
56+
Type=simple
57+
ExecStart=/usr/local/bin/apex start --config /etc/apex/apex.yaml
58+
Restart=always
59+
RestartSec=5
60+
LimitNOFILE=65536
61+
62+
[Install]
63+
WantedBy=multi-user.target
64+
`
65+
66+
var initCmd = &cobra.Command{
67+
Use: "init",
68+
Short: "Installs apex globally and configures the systemd service",
69+
Run: func(cmd *cobra.Command, args []string) {
70+
if os.Geteuid() != 0 {
71+
fmt.Println("Error: apex init must be run as root. Try 'sudo apex init'")
72+
os.Exit(1)
73+
}
74+
75+
execPath, err := os.Executable()
76+
if err != nil {
77+
fmt.Printf("Error resolving executable path: %v\n", err)
78+
os.Exit(1)
79+
}
80+
81+
binData, err := os.ReadFile(execPath)
82+
if err != nil {
83+
fmt.Printf("Error reading binary: %v\n", err)
84+
os.Exit(1)
85+
}
86+
87+
err = os.WriteFile("/usr/local/bin/apex", binData, 0755)
88+
if err != nil {
89+
fmt.Printf("Error writing binary to /usr/local/bin: %v\n", err)
90+
os.Exit(1)
91+
}
92+
93+
err = os.MkdirAll("/etc/apex", 0755)
94+
if err != nil {
95+
fmt.Printf("Error creating /etc/apex directory: %v\n", err)
96+
os.Exit(1)
97+
}
98+
99+
if _, err := os.Stat("/etc/apex/apex.yaml"); os.IsNotExist(err) {
100+
err = os.WriteFile("/etc/apex/apex.yaml", []byte(defaultYAML), 0644)
101+
if err != nil {
102+
fmt.Printf("Error writing config file: %v\n", err)
103+
os.Exit(1)
104+
}
105+
}
106+
107+
err = os.WriteFile("/etc/systemd/system/apexproxy.service", []byte(systemdTemplate), 0644)
108+
if err != nil {
109+
fmt.Printf("Error writing systemd service: %v\n", err)
110+
os.Exit(1)
111+
}
112+
113+
exec.Command("systemctl", "daemon-reload").Run()
114+
exec.Command("systemctl", "enable", "apexproxy").Run()
115+
exec.Command("systemctl", "restart", "apexproxy").Run()
116+
117+
fmt.Println("Installation complete.")
118+
fmt.Println("Binary path: /usr/local/bin/apex")
119+
fmt.Println("Config path: /etc/apex/apex.yaml")
120+
fmt.Println("Service: apexproxy (running)")
121+
},
122+
}
123+
124+
func init() {
125+
rootCmd.AddCommand(initCmd)
126+
}

cmd/watch.go

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)