# Omada AP Manager A web-based tool for viewing and rebooting TP-Link Omada access points. Secured via Authentik OIDC, with a full audit log exported as CSV. --- ## Features - Live AP list fetched from Omada Controller (status, uptime, model, IP, MAC) - Single and bulk reboot with confirmation modal - Full audit log (who rebooted which AP, when, and whether it succeeded) - CSV export of the entire audit log - Authentik OIDC login (Authorization Code Flow) - Deployable as a Docker container via Portainer --- ## Prerequisites | Component | Version | |-----------|---------| | Omada Controller | 5.x or later | | Authentik | Any recent self-hosted version | | Docker / Portainer | Docker 20+ | | Nginx Proxy Manager | Any recent version | --- ## 1. Authentik: Create an OAuth2 Provider + Application ### 1.1 Create an OAuth2 Provider 1. In Authentik, go to **Admin → Providers → Create**. 2. Choose **OAuth2/OpenID Provider**. 3. Fill in: - **Name**: `qwe-salus` - **Authorization flow**: your default authorization flow - **Client type**: `Confidential` - **Client ID**: auto-generated (copy it) - **Client Secret**: auto-generated (copy it) - **Redirect URIs**: `https://salus.qwe.stranto.com/auth/callback` - **Scopes**: `openid`, `profile`, `email` - **Subject mode**: `Based on the User's username` (or `hashed user ID`) 4. Save. ### 1.2 Create an Application 1. Go to **Admin → Applications → Create**. 2. Fill in: - **Name**: `Omada AP Manager` - **Slug**: `qwe-salus` - **Provider**: select the provider created above 3. Save. ### 1.3 Note the Issuer URL The issuer URL follows the pattern: ``` https:///application/o// ``` Example: `https://auth.stranto.com/application/o/qwe-salus/` --- ## 2. Omada Controller: Create an API User 1. In Omada Controller, go to **Settings → Administrators**. 2. Create a **local admin** account (not linked to OIDC): - Username: `api-user` - Password: a strong, unique password - Role: **Viewer** is enough for listing APs; needs **Administrator** role to send reboot commands. 3. Note the username and password — these go into `OMADA_USERNAME` / `OMADA_PASSWORD`. **Required permissions for the API user:** - Read access to site and AP data - Execute device commands (for reboot) > If self-signed certs are used, set `OMADA_VERIFY_SSL=false`. --- ## 3. Deploy via Portainer (Stack) ### 3.1 Build the image first (on the Docker host) ```bash git clone qwe-salus cd qwe-salus docker build -t qwe-salus:latest . ``` Or add a `build: .` section in the stack (Portainer will build it if the source is available). ### 3.2 Create a Portainer Stack 1. In Portainer, go to **Stacks → Add stack**. 2. Paste the contents of `docker-compose.yml`. 3. Fill in all environment variable values (see table below). 4. Click **Deploy the stack**. ### Environment Variables | Variable | Description | Example | |----------|-------------|---------| | `OMADA_BASE_URL` | Base URL of the Omada Controller | `https://192.168.1.1:8043` | | `OMADA_USERNAME` | Local Omada admin username | `api-user` | | `OMADA_PASSWORD` | Local Omada admin password | `s3cr3t` | | `OMADA_SITE_NAME` | Site name in Omada | `Default` | | `OMADA_VERIFY_SSL` | Set to `false` for self-signed certs | `false` | | `AUTHENTIK_ISSUER` | OIDC issuer URL from Authentik | `https://auth.example.com/application/o/slug/` | | `AUTHENTIK_CLIENT_ID` | OAuth2 client ID from Authentik | `abc123...` | | `AUTHENTIK_CLIENT_SECRET` | OAuth2 client secret from Authentik | `xyz789...` | | `AUTHENTIK_REDIRECT_URI` | Must match what Authentik has configured | `https://salus.example.com/auth/callback` | | `SESSION_SECRET_KEY` | Random secret for cookie signing — **change this!** | `openssl rand -hex 32` | | `DB_PATH` | Path to the SQLite database inside the container | `/data/audit.db` | ### Generating a SESSION_SECRET_KEY ```bash openssl rand -hex 32 ``` --- ## 4. Nginx Proxy Manager Setup 1. Add a **Proxy Host**: - **Domain Names**: `salus.qwe.stranto.com` - **Forward Hostname / IP**: the Docker host IP (or container name if on the same network) - **Forward Port**: `8098` - Enable **Websockets Support** (optional but harmless) 2. Under **SSL**, issue/select a Let's Encrypt certificate. 3. **Important**: The app uses `--proxy-headers` in uvicorn so it correctly handles `X-Forwarded-For` and `X-Forwarded-Proto` from NPM. --- ## 5. Accessing the Audit Log CSV Export Once logged in, navigate to **Audit Log** (top navigation) and click **Export CSV**. The file is named `audit_log_YYYY-MM-DD.csv` and contains: | Column | Description | |--------|-------------| | Timestamp (UTC) | ISO 8601 timestamp | | Username | OIDC `preferred_username` | | Email | OIDC `email` claim | | AP Name | Name as shown in Omada | | MAC | AP MAC address | | IP | AP IP address | | Result | `success` or `error` | | Error | Error message if result is `error` | --- ## Local Development ```bash # Create a .env file cp .env.example .env # edit with your values pip install -r requirements.txt # SQLite DB will be written to /data/audit.db by default # override for local dev: export DB_PATH=./audit.db uvicorn app.main:app --reload --port 8080 ``` --- ## Project Structure ``` qwe-salus/ ├── app/ │ ├── main.py # FastAPI routes │ ├── auth.py # Authentik OIDC logic │ ├── omada.py # Omada Controller API client │ ├── database.py # SQLAlchemy models + DB init │ ├── templates/ │ │ ├── base.html # Nav, toast system │ │ ├── login.html # Login landing page │ │ ├── index.html # AP list + reboot UI │ │ └── audit.html # Audit log + CSV export │ └── static/ ├── Dockerfile ├── docker-compose.yml └── requirements.txt ```