dcb581a359
Reflect config/ vs data/ split, install-time Jinja2 templating, auto-discovered paths, ZeroSSL/ACME support, and the new firewall save-then-apply API in all reference docs.
1021 lines
23 KiB
Markdown
1021 lines
23 KiB
Markdown
# REST API Reference
|
|
|
|
All endpoints are served by the management WebUI Flask application bound to `127.0.0.1:9090`, proxied through nginx with SSL termination and HTTP basic authentication. Requests target the management domain (e.g., `https://<hostname>.local/api/...`).
|
|
|
|
Every request and response uses `Content-Type: application/json`.
|
|
|
|
## Conventions
|
|
|
|
### Success Responses
|
|
|
|
```json
|
|
{
|
|
"ok": true,
|
|
"data": <value>
|
|
}
|
|
```
|
|
|
|
The `data` field contains the payload, which may be an object, array, string, or `null`.
|
|
|
|
### Error Responses
|
|
|
|
```json
|
|
{
|
|
"ok": false,
|
|
"error": "<human-readable message>"
|
|
}
|
|
```
|
|
|
|
Error responses carry one of the following HTTP status codes:
|
|
|
|
| Code | Meaning |
|
|
|------|---------|
|
|
| `400` | Bad request — invalid body, missing required field, or malformed value |
|
|
| `404` | Not found — the requested resource does not exist |
|
|
| `500` | Internal server error — unexpected failure in the backend |
|
|
|
|
---
|
|
|
|
## Firewall API
|
|
|
|
Endpoints prefixed with `/api/firewall/...`. Interact with firewalld for zone management, rich rules, NAT, and masquerade.
|
|
|
|
### Zone Management
|
|
|
|
#### List All Zones
|
|
|
|
```
|
|
GET /api/firewall/zones
|
|
```
|
|
|
|
Returns active zone-to-interface mappings and all available zone definitions.
|
|
|
|
**Response:**
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `data.active` | `object<name, [interface, ...]>` | Currently assigned interfaces per zone |
|
|
| `data.available` | `[string, ...]` | All zones known to firewalld |
|
|
|
|
---
|
|
|
|
#### Get Zone Details
|
|
|
|
```
|
|
GET /api/firewall/zones/<name>
|
|
```
|
|
|
|
Return detailed configuration for a single zone.
|
|
|
|
**Response (`data`):**
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `target` | `string` | Zone target (e.g., `"default"`, `"ACCEPT"`, `"REJECT"`) |
|
|
| `interfaces` | `[string, ...]` | Interfaces assigned to this zone |
|
|
| `services` | `[string, ...]` | Services allowed through the zone |
|
|
| `ports` | `[string, ...]` | Explicit port rules (format: `"443/tcp"`) |
|
|
| `masquerade` | `boolean` | Whether masquerade (NAT) is enabled |
|
|
| `forward_ports` | `[{port: number, proto: string, toaddr: string, toport: number}, ...]` | Port forward rules |
|
|
| `rich_rules` | `[string, ...]` | Rich rule definitions |
|
|
|
|
Returns HTTP `404` if the zone does not exist.
|
|
|
|
---
|
|
|
|
#### Create Zone
|
|
|
|
```
|
|
POST /api/firewall/zones
|
|
```
|
|
|
|
Create a new firewalld zone.
|
|
|
|
**Request Body:**
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `name` | `string` | Yes | Zone name |
|
|
| `target` | `string` | No | Zone target; defaults to `"default"` |
|
|
|
|
**Response:** `data` is `null` on success.
|
|
|
|
---
|
|
|
|
#### Delete Zone
|
|
|
|
```
|
|
DELETE /api/firewall/zones/<name>
|
|
```
|
|
|
|
Remove a zone from firewalld.
|
|
|
|
**Response:** `data` is `null` on success.
|
|
|
|
Returns HTTP `404` if the zone does not exist.
|
|
|
|
### Zone Configuration
|
|
|
|
#### Set Zone Interfaces
|
|
|
|
```
|
|
POST /api/firewall/zones/<name>/interfaces
|
|
```
|
|
|
|
Replace all interfaces assigned to the zone with the provided list.
|
|
|
|
**Request Body:**
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `interfaces` | `[string, ...]` | Yes | List of interface names |
|
|
|
|
**Response (`data`):**
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `zone` | `string` | Zone name |
|
|
| `interfaces` | `[string, ...]` | List of interface names now assigned to the zone |
|
|
|
|
---
|
|
|
|
#### Set Zone Services
|
|
|
|
```
|
|
POST /api/firewall/zones/<name>/services
|
|
```
|
|
|
|
Replace all services allowed in the zone with the provided list.
|
|
|
|
**Request Body:**
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `services` | `[string, ...]` | Yes | List of firewalld service names |
|
|
|
|
**Response (`data`):**
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `zone` | `string` | Zone name |
|
|
| `services` | `[string, ...]` | List of services now allowed in the zone |
|
|
|
|
### Firewall Rules
|
|
|
|
#### Add Rich Rule
|
|
|
|
```
|
|
POST /api/firewall/rich-rules
|
|
```
|
|
|
|
Add a firewalld rich rule to a zone.
|
|
|
|
**Request Body:**
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `zone` | `string` | Yes | Zone to add the rule to |
|
|
| `rule` | `string` | Yes | Full rich rule string |
|
|
|
|
**Response (`data`):**
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `zone` | `string` | Zone name |
|
|
| `rule` | `string` | Full rich rule string |
|
|
|
|
---
|
|
|
|
#### Remove Rich Rule
|
|
|
|
```
|
|
DELETE /api/firewall/rich-rules
|
|
```
|
|
|
|
Remove an existing rich rule from a zone. The `rule` string must match exactly.
|
|
|
|
**Request Body:**
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `zone` | `string` | Yes | Zone the rule belongs to |
|
|
| `rule` | `string` | Yes | Exact rich rule string to remove |
|
|
|
|
**Response (`data`):**
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `zone` | `string` | Zone name |
|
|
| `rule` | `string` | Exact rich rule string that was removed |
|
|
|
|
---
|
|
|
|
#### List Rich Rules
|
|
|
|
```
|
|
GET /api/firewall/rich-rules/<zone>
|
|
```
|
|
|
|
Return all rich rules for the specified zone.
|
|
|
|
**Response:**
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `data` | `[string, ...]` | Rich rule strings |
|
|
|
|
### NAT
|
|
|
|
#### Enable / Disable Masquerade
|
|
|
|
```
|
|
POST /api/firewall/masquerade
|
|
```
|
|
|
|
Toggle masquerade (source NAT) for a zone.
|
|
|
|
**Request Body:**
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `zone` | `string` | Yes | Zone to configure |
|
|
| `enable` | `boolean` | Yes | `true` to enable, `false` to disable |
|
|
|
|
**Response (`data`):**
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `zone` | `string` | Zone name |
|
|
| `masquerade` | `boolean` | Whether masquerade is now enabled for the zone |
|
|
|
|
---
|
|
|
|
#### Add Port Forward
|
|
|
|
```
|
|
POST /api/firewall/forward-port
|
|
```
|
|
|
|
Add a port forwarding rule to a zone.
|
|
|
|
**Request Body:**
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `zone` | `string` | Yes | Zone to add the rule to |
|
|
| `port` | `number` | Yes | External port |
|
|
| `proto` | `string` | Yes | Protocol (`"tcp"` or `"udp"`) |
|
|
| `toaddr` | `string` | No | Internal destination address |
|
|
| `toport` | `number` | No | Internal destination port |
|
|
|
|
**Response (`data`):**
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `zone` | `string` | Zone name |
|
|
| `port` | `number` | External port |
|
|
| `proto` | `string` | Protocol (`"tcp"` or `"udp"`) |
|
|
|
|
---
|
|
|
|
#### Remove Port Forward
|
|
|
|
```
|
|
DELETE /api/firewall/forward-port
|
|
```
|
|
|
|
Remove a port forwarding rule. The body must match the original rule exactly.
|
|
|
|
**Request Body:**
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `zone` | `string` | Yes | Zone the rule belongs to |
|
|
| `port` | `number` | Yes | External port |
|
|
| `proto` | `string` | Yes | Protocol (`"tcp"` or `"udp"`) |
|
|
| `toaddr` | `string` | No | Internal destination address |
|
|
| `toport` | `number` | No | Internal destination port |
|
|
|
|
**Response (`data`):**
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `zone` | `string` | Zone name |
|
|
| `port` | `number` | External port |
|
|
| `proto` | `string` | Protocol (`"tcp"` or `"udp"`) |
|
|
|
|
### Info
|
|
|
|
#### Available Services
|
|
|
|
```
|
|
GET /api/firewall/services
|
|
```
|
|
|
|
List all service names known to firewalld.
|
|
|
|
**Response:**
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `data` | `[string, ...]` | Service names |
|
|
|
|
---
|
|
|
|
#### Available Interfaces
|
|
|
|
```
|
|
GET /api/firewall/interfaces
|
|
```
|
|
|
|
List all network interfaces currently available on the system.
|
|
|
|
**Response:**
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `data` | `[string, ...]` | Interface names |
|
|
|
|
---
|
|
|
|
## DHCP / DNS API
|
|
|
|
Endpoints prefixed with `/api/dhcp/...`. Manage dnsmasq configuration, DHCP leases, and custom DNS records.
|
|
|
|
### Configuration
|
|
|
|
#### Get Configuration
|
|
|
|
```
|
|
GET /api/dhcp/config
|
|
```
|
|
|
|
Return the current DHCP/DNS configuration object.
|
|
|
|
**Response:**
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `data` | `object` | Full dnsmasq configuration dictionary |
|
|
|
|
---
|
|
|
|
#### Replace Configuration
|
|
|
|
```
|
|
POST /api/dhcp/config
|
|
```
|
|
|
|
Replace the entire configuration with the provided JSON object.
|
|
|
|
**Request Body:**
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| *(entire body)* | `object` | Yes | Complete configuration object |
|
|
|
|
**Response:** `data` is `null` on success.
|
|
|
|
---
|
|
|
|
#### Partial Update Configuration
|
|
|
|
```
|
|
PATCH /api/dhcp/config
|
|
```
|
|
|
|
Deep-merge the provided fields into the existing configuration. Useful for targeted updates (e.g., changing DNS upstream servers without replacing the full config).
|
|
|
|
**Request Body:**
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| *(any subset)* | `any` | Yes | Fields to merge into the existing config |
|
|
|
|
**Response:** `data` is `null` on success.
|
|
|
|
---
|
|
|
|
#### Apply Configuration
|
|
|
|
```
|
|
POST /api/dhcp/apply
|
|
```
|
|
|
|
Write the in-memory configuration to `/etc/dnsmasq.d/vacuum-wall.conf` and reload the dnsmasq service.
|
|
|
|
**Response:** `data` is `null` on success.
|
|
|
|
### Leases
|
|
|
|
#### Get Live Leases
|
|
|
|
```
|
|
GET /api/dhcp/leases
|
|
```
|
|
|
|
Return the current DHCP lease table from dnsmasq.
|
|
|
|
**Response:**
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `data` | `[object, ...]` | Array of lease objects |
|
|
|
|
---
|
|
|
|
#### Add Static Lease
|
|
|
|
```
|
|
POST /api/dhcp/static-lease
|
|
```
|
|
|
|
Add a static (reserved) DHCP lease.
|
|
|
|
**Request Body:**
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `mac` | `string` | Yes | MAC address (`"aa:bb:cc:dd:ee:ff"`) |
|
|
| `ip` | `string` | Yes | Reserved IP address |
|
|
| `hostname` | `string` | No | Hostname for the reservation |
|
|
|
|
**Response (`data`):**
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `mac` | `string` | MAC address |
|
|
| `ip` | `string` | Reserved IP address |
|
|
| `hostname` | `string` | Hostname for the reservation |
|
|
|
|
---
|
|
|
|
#### Remove Static Lease
|
|
|
|
```
|
|
DELETE /api/dhcp/static-lease?mac=aa:bb:cc:dd:ee:ff
|
|
```
|
|
|
|
Remove a previously configured static lease.
|
|
|
|
**Query Parameters:**
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `mac` | `string` | Yes | MAC address of the lease to remove |
|
|
|
|
**Response:** `data` is `null` on success.
|
|
|
|
Returns HTTP `404` if no matching lease is found.
|
|
|
|
### DNS Records
|
|
|
|
#### Add DNS Record
|
|
|
|
```
|
|
POST /api/dhcp/dns-record
|
|
```
|
|
|
|
Add a custom DNS A record served by dnsmasq.
|
|
|
|
**Request Body:**
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `name` | `string` | Yes | Fully qualified domain name |
|
|
| `address` | `string` | Yes | IP address to resolve to |
|
|
|
|
**Response (`data`):**
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `name` | `string` | Fully qualified domain name |
|
|
| `address` | `string` | IP address |
|
|
| `hostname` | `string` | Short hostname |
|
|
|
|
---
|
|
|
|
#### Remove DNS Record
|
|
|
|
```
|
|
DELETE /api/dhcp/dns-record?name=nas.lan
|
|
```
|
|
|
|
Remove a custom DNS record.
|
|
|
|
**Query Parameters:**
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `name` | `string` | Yes | Fully qualified domain name to remove |
|
|
|
|
**Response:** `data` is `null` on success.
|
|
|
|
Returns HTTP `404` if no matching record is found.
|
|
|
|
---
|
|
|
|
## Proxy API
|
|
|
|
Endpoints prefixed with `/api/proxy/...`. Manage reverse proxy domains, nginx configuration generation, and the management WebUI proxy.
|
|
|
|
### Domain Management
|
|
|
|
#### List All Domains
|
|
|
|
```
|
|
GET /api/proxy/domains
|
|
```
|
|
|
|
Return all configured proxy domains.
|
|
|
|
**Response:**
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `data` | `[object, ...]` | Array of domain configuration objects |
|
|
|
|
---
|
|
|
|
#### Add Domain
|
|
|
|
```
|
|
POST /api/proxy/domains
|
|
```
|
|
|
|
Add a new reverse proxy domain.
|
|
|
|
**Request Body:**
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `domain` | `string` | Yes | Domain name to proxy |
|
|
| `backend_host` | `string` | Yes | Backend server IP or hostname |
|
|
| `backend_port` | `number` | Yes | Backend server port |
|
|
| `backend_proto` | `string` | No | Backend protocol (`"http"` or `"https"`); defaults to `"http"` |
|
|
|
|
**Response (`data`):**
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `domain` | `string` | Domain name |
|
|
|
|
Returns HTTP `400` if the domain is already configured.
|
|
|
|
---
|
|
|
|
#### Get Domain Details
|
|
|
|
```
|
|
GET /api/proxy/domains/<domain>
|
|
```
|
|
|
|
Return the configuration for a single proxy domain.
|
|
|
|
**Response (`data`):**
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `domain` | `string` | Domain name |
|
|
| `backend_host` | `string` | Backend server address |
|
|
| `backend_port` | `number` | Backend server port |
|
|
| `backend_proto` | `string` | Backend protocol |
|
|
|
|
Returns HTTP `404` if the domain is not configured.
|
|
|
|
---
|
|
|
|
#### Update Domain
|
|
|
|
```
|
|
PUT /api/proxy/domains/<domain>
|
|
```
|
|
|
|
Update one or more fields of an existing domain entry. Only the fields present in the body are modified.
|
|
|
|
**Request Body:**
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `backend_host` | `string` | No | Backend server IP or hostname |
|
|
| `backend_port` | `number` | No | Backend server port |
|
|
| `backend_proto` | `string` | No | Backend protocol |
|
|
|
|
**Response (`data`):**
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `domain` | `string` | Domain name |
|
|
|
|
Returns HTTP `404` if the domain is not configured.
|
|
|
|
---
|
|
|
|
#### Remove Domain
|
|
|
|
```
|
|
DELETE /api/proxy/domains/<domain>
|
|
```
|
|
|
|
Remove a proxy domain and its nginx configuration.
|
|
|
|
**Response (`data`):**
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `domain` | `string` | Domain name |
|
|
|
|
Returns HTTP `404` if the domain is not configured.
|
|
|
|
### Apply / Test
|
|
|
|
#### Apply Configuration
|
|
|
|
```
|
|
POST /api/proxy/apply
|
|
```
|
|
|
|
Regenerate nginx configuration files for all proxy domains and reload the nginx service.
|
|
|
|
**Response:** `data` is `null` on success.
|
|
|
|
Returns HTTP `500` if nginx config generation fails or the reload fails.
|
|
|
|
---
|
|
|
|
#### Test Configuration
|
|
|
|
```
|
|
POST /api/proxy/test
|
|
```
|
|
|
|
Run `nginx -t` against the generated configuration without reloading. Useful for validating changes before applying.
|
|
|
|
**Response:**
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `data.valid` | `boolean` | Whether the configuration syntax is valid |
|
|
| `data.output` | `string` | Raw nginx test output |
|
|
|
|
### Management
|
|
|
|
#### Configure Management WebUI Proxy
|
|
|
|
```
|
|
POST /api/proxy/management
|
|
```
|
|
|
|
Configure the nginx proxy block for the management WebUI itself, including optional HTTP basic authentication.
|
|
|
|
**Request Body:**
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `domain` | `string` | Yes | Management domain (e.g., `"myhost.local"`) |
|
|
| `flask_host` | `string` | No | Flask app bind host; defaults to `"127.0.0.1"` |
|
|
| `flask_port` | `number` | No | Flask app bind port; defaults to `9090` |
|
|
| `auth_user` | `string` | No | Username for basic auth. An `.htpasswd` entry is created when this field is present. |
|
|
| `auth_pass` | `string` | No | Password for basic auth. Used together with `auth_user`. |
|
|
|
|
**Response:** `data` is `null` on success.
|
|
|
|
If `auth_user` and `auth_pass` are provided, the endpoint creates or updates the corresponding `.htpasswd` file entry.
|
|
|
|
---
|
|
|
|
## Certificate API
|
|
|
|
Endpoints prefixed with `/api/certs/...`. Manage TLS certificates via ACME (ZeroSSL, Let's Encrypt, etc.).
|
|
|
|
### Listing & Details
|
|
|
|
#### List All Certificates
|
|
|
|
```
|
|
GET /api/certs/list
|
|
```
|
|
|
|
Return all managed certificates with metadata.
|
|
|
|
**Response:**
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `data` | `[object, ...]` | Array of certificate objects |
|
|
|
|
Each certificate object:
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `domain` | `string` | Domain the certificate covers |
|
|
| `expires_at` | `string` | Expiration date (ISO 8601) |
|
|
| `days_until_expiry` | `number` | Remaining days until expiration |
|
|
| `cert_path` | `string` | Path to the certificate file |
|
|
| `key_path` | `string` | Path to the private key file |
|
|
|
|
---
|
|
|
|
#### Get Certificate Details
|
|
|
|
```
|
|
GET /api/certs/<domain>
|
|
```
|
|
|
|
Return details for a single certificate.
|
|
|
|
**Response (`data`):**
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `domain` | `string` | Domain |
|
|
| `expires_at` | `string` | Expiration date (ISO 8601) |
|
|
| `days_until_expiry` | `number` | Remaining days |
|
|
| `cert_path` | `string` | Certificate file path |
|
|
| `key_path` | `string` | Private key file path |
|
|
|
|
Returns HTTP `404` if no certificate is found for the domain.
|
|
|
|
### Operations
|
|
|
|
#### Issue Certificate
|
|
|
|
```
|
|
POST /api/certs/issue
|
|
```
|
|
|
|
Request a new certificate for a domain.
|
|
|
|
**Request Body:**
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `domain` | `string` | Yes | Domain to issue the certificate for |
|
|
| `webroot` | `string` | No | Custom webroot path for HTTP-01 validation |
|
|
|
|
**Response:** `data` is `null` on success.
|
|
|
|
Returns HTTP `400` if the domain is missing or the request is malformed. Returns HTTP `500` if the ACME challenge or certificate issuance fails.
|
|
|
|
---
|
|
|
|
#### Renew Certificate
|
|
|
|
```
|
|
POST /api/certs/<domain>/renew
|
|
```
|
|
|
|
Force-renew an existing certificate, regardless of its current expiry status.
|
|
|
|
**Response:** `data` is `null` on success.
|
|
|
|
Returns HTTP `404` if the certificate is not found. Returns HTTP `500` if renewal fails.
|
|
|
|
---
|
|
|
|
#### Remove Certificate
|
|
|
|
```
|
|
DELETE /api/certs/<domain>
|
|
```
|
|
|
|
Delete a certificate and remove it from auto-renewal tracking.
|
|
|
|
**Response:** `data` is `null` on success.
|
|
|
|
Returns HTTP `404` if the certificate is not found.
|
|
|
|
### Account
|
|
|
|
#### Set ACME Contact Email
|
|
|
|
```
|
|
POST /api/certs/email
|
|
```
|
|
|
|
Set or update the ACME account contact email (used by the CA for expiration and security notices).
|
|
|
|
**Request Body:**
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `email` | `string` | Yes | Contact email address |
|
|
|
|
**Response (`data`):**
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `email` | `string` | Contact email address |
|
|
|
|
---
|
|
|
|
## WireGuard API
|
|
|
|
Endpoints prefixed with `/api/wireguard/...`. Manage the WireGuard VPN server, peers, and client configuration.
|
|
|
|
### Configuration
|
|
|
|
#### Get Configuration
|
|
|
|
```
|
|
GET /api/wireguard/config
|
|
```
|
|
|
|
Return the current WireGuard server configuration. The `private_key` field is stripped from the response.
|
|
|
|
**Response:**
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `data` | `object` | Full WireGuard configuration dictionary (`private_key` omitted) |
|
|
|
|
---
|
|
|
|
#### Replace Configuration
|
|
|
|
```
|
|
POST /api/wireguard/config
|
|
```
|
|
|
|
Replace the entire WireGuard configuration. The `private_key` field is stripped from the response.
|
|
|
|
**Request Body:**
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| *(entire body)* | `object` | Yes | Complete WireGuard configuration object |
|
|
|
|
**Response:**
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `data` | `object` | Updated configuration (`private_key` omitted) |
|
|
|
|
### Tunnel Control
|
|
|
|
#### Apply Configuration
|
|
|
|
```
|
|
POST /api/wireguard/apply
|
|
```
|
|
|
|
Write the current configuration to `wg0.conf` on disk and bring the WireGuard tunnel up.
|
|
|
|
**Response:** `data` is `null` on success.
|
|
|
|
Returns HTTP `500` if config write or interface bring-up fails.
|
|
|
|
---
|
|
|
|
#### Bring Tunnel Down
|
|
|
|
```
|
|
POST /api/wireguard/down
|
|
```
|
|
|
|
Bring down the WireGuard tunnel interface (`wg0`).
|
|
|
|
**Response:** `data` is `null` on success.
|
|
|
|
### Status
|
|
|
|
#### Tunnel Status
|
|
|
|
```
|
|
GET /api/wireguard/status
|
|
```
|
|
|
|
Return live tunnel state, including interface metrics and per-peer connection statistics.
|
|
|
|
**Response (`data`):**
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `up` | `boolean` | Whether the tunnel interface is up |
|
|
| `interface` | `object` | Interface info (listen port, public key, etc.) |
|
|
| `peers` | `[object, ...]` | Per-peer connection stats (handshake time, transfer bytes, endpoint, etc.) |
|
|
|
|
---
|
|
|
|
#### Initialize
|
|
|
|
```
|
|
POST /api/wireguard/initialize
|
|
```
|
|
|
|
Perform first-time setup: generate a server key pair, write an initial configuration, and prepare for peer enrollment. This endpoint is idempotent — calling it multiple times has no additional effect.
|
|
|
|
**Response:** `data` is `null` on success.
|
|
|
|
### Peer Management
|
|
|
|
#### Add Peer
|
|
|
|
```
|
|
POST /api/wireguard/add-peer
|
|
```
|
|
|
|
Add a new WireGuard peer. A key pair is auto-generated for the peer. The response includes peer details with the private key stripped.
|
|
|
|
**Request Body:**
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `name` | `string` | Yes | Peer identifier name |
|
|
| `endpoint` | `string` | No | Allowed endpoint address (`"ip:port"`) |
|
|
| `allowed_ips` | `[string, ...]` | No | Allowed IPs; defaults to `["0.0.0.0/0"]` |
|
|
| `persistent_keepalive` | `number` | No | Persistent keepalive interval in seconds |
|
|
|
|
**Response (`data`):**
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `name` | `string` | Peer name |
|
|
| `public_key` | `string` | Peer's public key |
|
|
| `allowed_ips` | `[string, ...]` | Allowed IPs |
|
|
| `endpoint` | `string` | Allowed endpoint |
|
|
| `persistent_keepalive` | `number` | Keepalive interval |
|
|
|
|
---
|
|
|
|
#### Remove Peer
|
|
|
|
```
|
|
DELETE /api/wireguard/remove-peer?name=alice
|
|
```
|
|
|
|
Remove a configured peer.
|
|
|
|
**Query Parameters:**
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `name` | `string` | Yes | Peer name to remove |
|
|
|
|
**Response (`data`):**
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `name` | `string` | Peer name |
|
|
|
|
Returns HTTP `404` if the peer is not found.
|
|
|
|
---
|
|
|
|
#### List Peers
|
|
|
|
```
|
|
GET /api/wireguard/peers
|
|
```
|
|
|
|
Return all configured peers. Private keys are stripped from the response.
|
|
|
|
**Response:**
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `data` | `[object, ...]` | Array of peer objects (private keys omitted) |
|
|
|
|
---
|
|
|
|
#### Peer Connection Status
|
|
|
|
```
|
|
GET /api/wireguard/peer-status
|
|
```
|
|
|
|
Return live per-peer connection status from `wg show`, including last handshake time, transfer bytes, and current endpoint.
|
|
|
|
**Response:**
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `data` | `[object, ...]` | Array of live peer status objects |
|
|
|
|
### Client Configuration
|
|
|
|
#### Generate Client Config
|
|
|
|
```
|
|
POST /api/wireguard/generate-client
|
|
```
|
|
|
|
Generate a complete WireGuard client configuration file for provisioning a device. The returned config includes the peer's private key for the client to use.
|
|
|
|
**Request Body:**
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `name` | `string` | Yes | Peer name to generate config for |
|
|
| `server_endpoint` | `string` | Yes | Server public address (`"ip:port"`) for the client's `[Peer]` section |
|
|
|
|
**Response (`data`):**
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `config` | `string` | Complete WireGuard client config text (`[Interface]` + `[Peer]` block) |
|
|
|
|
The client config includes the generated private key so the client can be provisioned directly. Note that this is the only endpoint that returns a WireGuard private key — all other endpoints strip private keys from responses.
|
|
|
|
Returns HTTP `404` if the peer is not found.
|