Server Configuration

Keywords

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   # range

server 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. Remove these 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/tcp

Port 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 range

If 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.