Add Portainer deploy guide for the login portal
Standalone instructions for the Portainer admin: set AUTH_SECRET_KEY, rebuild + redeploy the stack, and bootstrap the first admin account. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
103
DEPLOY-login-portal.md
Normal file
103
DEPLOY-login-portal.md
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
# Deploy: Work Package Suite — login portal update
|
||||||
|
|
||||||
|
Instructions for the **Portainer admin** to take the new secure login portal live.
|
||||||
|
No prior context needed.
|
||||||
|
|
||||||
|
**Repo:** `Project-SDE-WP-Suite` (primegit) — changes are merged to **`main`**.
|
||||||
|
|
||||||
|
**What changed:** the app now has a username/password login. Going live needs:
|
||||||
|
1. one new environment variable,
|
||||||
|
2. a **rebuild** of the stack (not just a restart), and
|
||||||
|
3. creating the first admin account.
|
||||||
|
|
||||||
|
> **Why a rebuild (not a restart):** both the **nginx/webserver** and **api** images
|
||||||
|
> bake the code in at build time (`COPY html/` and `COPY server/` in their
|
||||||
|
> Dockerfiles). A plain restart will **not** pick up the new code — the images must
|
||||||
|
> be **rebuilt** from the latest `main`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Add an environment variable to the stack
|
||||||
|
|
||||||
|
In the stack's **Environment variables** section, add:
|
||||||
|
|
||||||
|
| Name | Value | Notes |
|
||||||
|
|------|-------|-------|
|
||||||
|
| `AUTH_SECRET_KEY` | a long random string | **Required.** Signs the login session cookies. |
|
||||||
|
| `AUTH_SESSION_HOURS` | `12` | *Optional.* Hours a login lasts before re-auth (defaults to 12). |
|
||||||
|
|
||||||
|
Generate the secret on the host with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
openssl rand -base64 48
|
||||||
|
```
|
||||||
|
|
||||||
|
> If `AUTH_SECRET_KEY` is **not** set, the app still starts but falls back to a random
|
||||||
|
> per-process key — logins then reset on every restart and break across the 2 gunicorn
|
||||||
|
> workers. It must be set to a fixed value.
|
||||||
|
|
||||||
|
The existing database variables (`POSTGRES_*`) are unchanged.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Pull latest `main`, rebuild, and redeploy
|
||||||
|
|
||||||
|
- Pull the latest commit on `main` and redeploy the stack **with image rebuild enabled**
|
||||||
|
(e.g. "Re-pull and redeploy" / force rebuild). This rebuilds both the `webserver` and
|
||||||
|
`api` images.
|
||||||
|
- New Python dependencies (`bcrypt`, `PyJWT`) are in `requirements.txt` and install
|
||||||
|
automatically during the rebuild.
|
||||||
|
- The `users` table is created automatically on API startup — **no DB migration needed.**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Verify the containers
|
||||||
|
|
||||||
|
- Confirm `wp_api` and the webserver container are both **running**.
|
||||||
|
- If `wp_api` fails to start, check its **Logs**. (A missing `AUTH_SECRET_KEY` only logs a
|
||||||
|
warning — it won't crash — but please confirm it's set.)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Create the first admin account
|
||||||
|
|
||||||
|
The login system needs one admin user in the production (Postgres) database. Open the
|
||||||
|
**`wp_api`** container's **Console** (`/bin/sh`) and run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python -m server.manage_users create-admin <username> --name "<Full Name>"
|
||||||
|
```
|
||||||
|
|
||||||
|
It prompts for a password (minimum 8 characters) and prints `Created admin: <username>`.
|
||||||
|
|
||||||
|
Non-interactive alternative:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python -m server.manage_users create-admin <username> --name "<Full Name>" --password "<password>"
|
||||||
|
```
|
||||||
|
|
||||||
|
Other CLI commands (run the same way): `list`, `create <user> --role user`,
|
||||||
|
`reset-password <user>`, `disable <user>`, `enable <user>`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Confirm it works
|
||||||
|
|
||||||
|
1. Load the site's normal URL — it should redirect to a **login page**.
|
||||||
|
2. Sign in with the admin account from step 4.
|
||||||
|
3. That admin can then add all other users from the in-app **Admin → User
|
||||||
|
administration** page (top-right **Admin** link), so no further shell access is needed.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Reference — what's in this release
|
||||||
|
|
||||||
|
- `server/auth.py` — bcrypt password hashing, JWT session cookie, the request gate.
|
||||||
|
- `server/app.py` — `/api/auth/*` endpoints + middleware that refuses every `/api` data
|
||||||
|
route without a valid session.
|
||||||
|
- `server/manage_users.py` — the CLI used in step 4.
|
||||||
|
- `html/login.html`, `html/auth-guard.js` — login page and per-page guard.
|
||||||
|
- `html/admin.html` / `admin.js` — Admin Console gated on the admin role, with the user
|
||||||
|
administration UI.
|
||||||
|
- Sessions are stateless: a signed JWT in an **HttpOnly, SameSite=Lax** cookie, marked
|
||||||
|
**Secure** automatically when served over HTTPS (via `X-Forwarded-Proto` from nginx).
|
||||||
Reference in New Issue
Block a user