b455b2fd151531a315bc585198a4ae3daf173739
Previous implementation fetched connected client IPs via API (which was returning empty data). The filter now checks the AP's own management IP directly from the data already in the table — no network request, instant. An AP is shown when its IP last octet is between 150 and 155 inclusive. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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
- In Authentik, go to Admin → Providers → Create.
- Choose OAuth2/OpenID Provider.
- 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(orhashed user ID)
- Name:
- Save.
1.2 Create an Application
- Go to Admin → Applications → Create.
- Fill in:
- Name:
Omada AP Manager - Slug:
qwe-salus - Provider: select the provider created above
- Name:
- Save.
1.3 Note the Issuer URL
The issuer URL follows the pattern:
https://<your-authentik-domain>/application/o/<application-slug>/
Example: https://auth.stranto.com/application/o/qwe-salus/
2. Omada Controller: Create an API User
- In Omada Controller, go to Settings → Administrators.
- 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.
- Username:
- 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)
git clone <this-repo> 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
- In Portainer, go to Stacks → Add stack.
- Paste the contents of
docker-compose.yml. - Fill in all environment variable values (see table below).
- 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
openssl rand -hex 32
4. Nginx Proxy Manager Setup
- 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)
- Domain Names:
- Under SSL, issue/select a Let's Encrypt certificate.
- Important: The app uses
--proxy-headersin uvicorn so it correctly handlesX-Forwarded-ForandX-Forwarded-Protofrom 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 |
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
# 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
Description
Languages
HTML
61.2%
Python
37.7%
Dockerfile
1.1%