Server Configuration
openme server config, openme server YAML, SPA server configuration, knock timeout, replay window, firewall config
Default location: /etc/openme/config.yaml
Override with: openme --config /path/to/config.yaml serve
Full Example
server:
host: "myserver.example.com" # public hostname or IP (used when generating client configs)
udp_port: 54154 # udp knock port
health_port: 54154 # tcp health-check port
firewall: nft
knock_timeout: 30s
replay_window: 60s
open_knock_port: true # set to false if your firewall already opens this port
drop_ports: false # when true, add DROP rules for all managed ports at startup
default_profile: default # profile name used in client configs generated by 'openme add'
private_key: "base64-encoded-curve25519-private-key=="
public_key: "base64-encoded-curve25519-public-key=="
ports:
default:
- 22/tcp # SSH
devops:
- 22/tcp
- 443/tcp
- 8080-8090/tcp # port range
readonly:
- 443/tcp
- 443/udp
clients:
alice:
ed25519_pubkey: "base64-encoded-ed25519-public-key=="
# empty allowed_ports → falls back to the "default" port group
bob:
ed25519_pubkey: "base64-encoded-ed25519-public-key=="
allowed_ports:
- default # the "default" group (SSH)
- 2222/tcp # plus an extra port
expires: "2026-12-31T23:59:59Z"
joe:
ed25519_pubkey: "base64-encoded-ed25519-public-key=="
allowed_ports:
- devops # named group
- 1994/tcp # inline spec
- 2000-2010/tcp # rangeserver Block
| Key | Type | Default | Description |
|---|---|---|---|
host |
string | — | Public hostname or IP of this server. Used when generating client configs with openme add. |
udp_port |
uint16 | 54154 |
UDP port to listen for knock packets. |
health_port |
uint16 | same as udp_port |
TCP port for health checks (openme status). |
firewall |
string | "nft" |
Firewall backend. One of "nft" or "iptables". |
knock_timeout |
duration | "30s" |
How long a firewall rule stays open after a valid knock. |
replay_window |
duration | "60s" |
Maximum accepted age of a knock timestamp. |
private_key |
base64 | — | Secret. Server’s Curve25519 private key (32 bytes). |
public_key |
base64 | — | Server’s Curve25519 public key (32 bytes). Convenience copy — derived from private_key. |
open_knock_port |
bool | true |
When true the server inserts a firewall rule that accepts UDP traffic on udp_port at startup and removes it on shutdown. Set to false if your existing firewall configuration already opens that port. |
drop_ports |
bool | false |
When true, installs DROP rules for every port managed by openme (all named groups + per-client inline specs) at startup. Per-client ACCEPT rules take priority, so authenticated clients can still connect. Removes the DROP rules at shutdown. Set to false (default) if your base firewall policy already drops those ports. |
default_profile |
string | "default" |
Profile name used in client config files generated by openme add. Override with openme add --profile NAME. |
Duration values use Go duration syntax: "30s", "1m", "90s".
openme serve Flags
These flags are passed on the command line to openme serve, not in the config file.
| Flag | Default | Description |
|---|---|---|
--config |
/etc/openme/config.yaml |
Path to the server YAML config file. |
--state-file |
/run/openme/sessions.json |
Path where the server writes live session state. Read by openme sessions. Pass an empty string to disable. |
--log-level |
info |
Log verbosity: debug, info, warn, error. |
Session State File
When openme serve is running, it continuously writes a JSON snapshot of active firewall sessions to --state-file (default /run/openme/sessions.json).
The file is written atomically (temp file → rename) and is readable by openme sessions. It has permissions 0600 so only the process owner (root when run via the systemd unit) can read it.
Schema
{
"updated_at": "2026-03-17T14:23:01Z",
"active_sessions": [
{
"client_name": "alice",
"ip": "203.0.113.4",
"ports": [{"port": 54154, "proto": "tcp"}, {"port": 22, "proto": "tcp"}],
"opened_at": "2026-03-17T14:22:48Z",
"expires_at": "2026-03-17T14:23:18Z"
}
],
"last_seen": {
"alice": "2026-03-17T14:22:48Z",
"bob": "2026-03-17T13:55:02Z"
}
}| Field | Description |
|---|---|
active_sessions |
Clients whose firewall rules are currently open. |
active_sessions[].opened_at |
Wall-clock time the rule was created (or last refreshed by a repeated knock). |
active_sessions[].expires_at |
Wall-clock time the rule will be automatically removed. |
last_seen |
Most recent successful knock time for every client, including those no longer active. Persists across repeated knocks. |
ports Block
The top-level ports map defines named groups of port specs. Clients reference these groups by name in their allowed_ports list.
ports:
default: # built-in fallback name — used when a client has no allowed_ports
- 22/tcp
admin:
- 22/tcp
- 443/tcp
- 8080-8090/tcpPort spec syntax
Each entry in a group (or in a client’s allowed_ports list) is a compact string in the form PORT[-END][/PROTO]:
| Spec | Expands to |
|---|---|
22/tcp |
port 22, TCP only |
53/udp |
port 53, UDP only |
80 |
port 80, both TCP and UDP |
80-82/tcp |
ports 80, 81, 82 — TCP only |
80-82 |
ports 80, 81, 82 — both TCP and UDP |
The range span must not exceed 1000 ports.
clients Block
Each key under clients is a client name (e.g. alice).
| Key | Type | Required | Description |
|---|---|---|---|
ed25519_pubkey |
base64 | ✅ | Client’s Ed25519 public key (32 bytes). |
allowed_ports |
list | — | Port group names and/or inline port specs. Omit to use the default group. |
expires |
RFC3339 | — | Key expiry date. Omit for no expiry. |
disable_health_port |
bool | — | When true, the health port is not opened for this client. openme status will not work after knocking. |
allowed_ports list
Each item is either a named group (defined in ports:) or an inline port spec (see syntax table above). Items are processed in order and their results merged.
allowed_ports:
- default # reference the "default" group
- 443/tcp # inline spec — HTTPS only
- 2000-2010/tcp # inline rangeIf allowed_ports is omitted or empty, the client falls back to the default group when it exists. If no default group is defined, no ports are opened.