Accessing the cockpit¶
The cockpit is served over HTTPS at the COCKPIT_DOMAIN chosen during installation.
Port-knocking is optional, strongly recommended and enabled by default. When enabled,
send the generated sequence before opening the cockpit; every cockpit page, API and
attached admin tool also requires a valid SpawnWP session.
flowchart LR
A[Port-knock<br/>when enabled] --> B[HTTPS]
B --> C[SpawnWP login]
C --> D[Passkey]
C --> E[Password + TOTP]
D --> F[Cockpit]
E --> F
Port-knocking¶
The credentials report contains three random TCP ports. Send them in order within ten seconds; refused connections are expected because no application listens on these ports.
The source IP remains allowed while the cockpit is active and expires after 30 minutes
of inactivity. Send the ports in reverse order to close access immediately. Provider
firewalls must allow the three generated ports to reach knockd, preferably restricted
to trusted source IPs. If knocking was disabled during installation, open the cockpit
URL directly.
First enrollment¶
After knocking when required, open the cockpit URL and use the one-time activation code from
/root/spawnwp-credentials.txt. The code expires after 24 hours and is consumed by a
successful enrollment.
- Choose the administrator name and a strong password. This password is used only when signing in without a passkey and always requires TOTP or a recovery code.
- Scan the QR code with any TOTP authenticator, such as 2FAS, Aegis (Android), Google Authenticator, Microsoft Authenticator, 1Password or Bitwarden, then enter its six-digit code. The manual secret is available when scanning is not possible.
- Let the browser create a passkey using the device PIN or biometrics, a hardware security key, or a compatible password manager.
- Store the ten single-use recovery codes outside the server.
Passkeys are the preferred daily login. Signing in with a password always requires a second factor: either a current TOTP code or one unused recovery code.
Protected tools¶
Adminer and Mailpit are routed through the cockpit hostname. Nginx uses an internal
authentication check against the SpawnWP session before proxying either tool. An
anonymous request is redirected to /login; their loopback container ports must never
be exposed publicly.
Session behavior¶
- Cookies are
Secure,HttpOnlywhere applicable andSameSite=Strict. - Sessions have idle and absolute expiration limits.
- State-changing requests require a CSRF token.
- Destructive operations require recent authentication.
- Authentication endpoints have both Nginx and application rate limits.
Signing out revokes the current server-side session. Use sudo spawnwp auth reset from
an interactive root shell only for account recovery; it revokes every session and
creates a new one-time activation code.
Problems signing in¶
- Activation code rejected: check that it was copied completely and has not expired or
already been consumed. Run
sudo spawnwp auth resetif recovery is required. - Passkey unavailable: sign in with the password plus TOTP.
- TOTP rejected: verify that the phone and server clocks are synchronized.
- Recovery code rejected: recovery codes are single-use. Try an unused code.
- Too many attempts: wait for the rate-limit window before retrying.
- Cockpit returns 403: verify the knock order, current source IP and provider firewall.
Next: Using the cockpit.