Creating customers
Onboard a new client with one form
In Proxima Gateway, every customer owns exactly one server. Creating a customer therefore provisions both the user account and the server stub in a single transaction.
The flow
Admin → Users → Add User opens a small form:
| Field | Required | Notes |
|---|---|---|
| Username | Yes | Lowercase, must be unique |
| Password | Yes | Customer can change later |
| Display Name | No | Shown in the sidebar profile |
| Login URL Slug | No | Gives the customer a personal /login/<slug> link |
| Role | Yes | Customer (owns one server) or Admin (no server) |
| Server name | No | Defaults to <username>'s Server if blank |
Click Create User. Inside one Postgres transaction, the system:
- Creates the
Userrow (bcrypt-hashed password) - Creates a
Serverrow owned by that user - Generates a 256-bit
apiKey(the license key) and stores it on the server row - Generates a 256-bit
apiSecret(used for dashboard → proxy auth on the proxy's:6060endpoints)
If any step fails, the whole thing rolls back — you never end up with a half-provisioned customer.
What the customer sees
When they log in for the first time:
- Their server is already in their list —
/appshows it with status "Not installed" - A Connect your server card asks for SSH credentials
- Once they save credentials and click Install, the runner uses the apiKey/apiSecret you provisioned — they never see or type them
What you don't have to do
- ❌ Generate API keys by hand (the old
openssl rand -hex 32flow is retired — they're auto-generated) - ❌ Email the keys to the customer
- ❌ Pre-create a server entry separately
- ❌ Set up SSH keys for them — they enter their own root password into the dashboard
Editing later
Admin → Users → Edit lets you change the username, password, display name, role, or login slug. The license key and server settings live in their own card on the same page — see Managing licenses.
To delete a customer, click the trash icon on the users list. The related server row is cascade-deleted; the proxy on their box keeps running but its heartbeat will start returning 401 (treated as Expired on the proxy side, so it shuts down on next heartbeat).