Services/Authentik
As of: 2026-07-05 — migrated from `services/AUTHENTIK.md`
Authentik — Identity & SSO Provider
Complete setup & operations guide for Authentik (identity provider, OAuth2/OIDC, LDAP directory service).
Criticality: CRITICAL — The lynchpin. Everything on Stronghold depends on Authentik for authentication. Without it, most other services are inaccessible or in an inconsistent state. Must be recovered first in any disaster scenario.
Overview
Authentik is a self-hosted identity provider that serves as the single source of truth for authentication across Stronghold. It provides:
- OAuth2 / OIDC providers for web apps (Immich, Memos, Linkwarden, Forgejo, Vaultwarden, Grafana, n8n, Matrix, Cloudflare Access)
- LDAP directory for apps that don't support OAuth (Nextcloud, Jellyfin, Stalwart mail server)
- Group membership for role-based access (authentik Admins, family-and-friends, email provisioning groups)
- User management — all users are defined here; other services sync from Authentik
- API tokens for programmatic access (n8n, CI/CD, automation)
Current Users:
marcus(primary admin user, member of authentik Admins)akadmin(backup admin user)- Service accounts:
stalwart-svc,nextcloud-svc(for LDAP directory access)
Current Version: 2025.10.3
Access: https://key.wilsoz.com/if/admin/
Service Information
| Property | Value |
|---|---|
| Compose file | /library/authentik-app/docker-compose.yml
|
| Containers | authentik-app_server_1, authentik-app_worker_1, authentik-app_postgresql_1
|
| Database | PostgreSQL 16 (in-container, persisted to Docker volume database)
|
| HTTP Port | 9000 (external via 9443 HTTPS via reverse proxy) |
| HTTPS Port | 9443 (internal, for direct connections) |
| LDAP Outpost Port | 389 (via LDAP Outpost container; internal only, reaches stronghold via http://172.17.0.1:9000)
|
| Data volumes | /library/authentik-app/media (custom templates, branding)
|
| Database volume | authentik-app_database (PostgreSQL data)
|
| Networks | authentik-app_default (internal Docker network, MTU 1280)
|
| Image versions | server/worker: ghcr.io/goauthentik/server:2025.10.3
|
| Restart policy | unless-stopped
|
Initial Setup from Scratch
Prerequisites
- Docker and docker-compose installed
- Network access to PostgreSQL (internal container or external)
- Cloudflare DNS configured for
key.wilsoz.com - VPS reverse proxy (nginx) configured to forward to stronghold:9000
1. Create Directory & Files
<syntaxhighlight lang="bash"> mkdir -p /library/authentik-app cd /library/authentik-app </syntaxhighlight>
2. Create docker-compose.yml
<syntaxhighlight lang="yaml"> version: "3.8"
services:
postgresql:
image: docker.io/library/postgres:16-alpine
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}"]
interval: 30s
timeout: 5s
retries: 5
start_period: 20s
volumes:
- database:/var/lib/postgresql/data
env_file:
- .env
environment:
POSTGRES_DB: ${PG_DB:-authentik}
POSTGRES_USER: ${PG_USER:-authentik}
POSTGRES_PASSWORD: ${PG_PASS:?database password required}
server:
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.10.3}
restart: unless-stopped
command: server
ports:
- "${COMPOSE_PORT_HTTP:-9000}:9000"
- "${COMPOSE_PORT_HTTPS:-9443}:9443"
env_file:
- .env
environment:
AUTHENTIK_POSTGRESQL__HOST: postgresql
AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik}
AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik}
AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY:?secret key required}
volumes:
- ./media:/media
- ./custom-templates:/templates
depends_on:
postgresql:
condition: service_healthy
worker:
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.10.3}
restart: unless-stopped
command: worker
user: root
env_file:
- .env
environment:
AUTHENTIK_POSTGRESQL__HOST: postgresql
AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik}
AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik}
AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY:?secret key required}
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./media:/media
- ./certs:/certs
- ./custom-templates:/templates
depends_on:
postgresql:
condition: service_healthy
volumes:
database:
</syntaxhighlight>
3. Create .env File
<syntaxhighlight lang="bash">
- PostgreSQL
PG_DB=authentik PG_USER=authentik PG_PASS=<generate-strong-password-32-chars>
- Authentik
AUTHENTIK_SECRET_KEY=<generate-strong-secret-key-50-chars> AUTHENTIK_IMAGE=ghcr.io/goauthentik/server AUTHENTIK_TAG=2025.10.3
- Ports
COMPOSE_PORT_HTTP=9000 COMPOSE_PORT_HTTPS=9443
- Bootstrap (initial admin)
AUTHENTIK_BOOTSTRAP_PASSWORD=<temporary-init-password> AUTHENTIK_BOOTSTRAP_TOKEN=<temporary-init-token> </syntaxhighlight>
Important: Generate secure random values for passwords and secrets: <syntaxhighlight lang="bash"> openssl rand -base64 32 # For PG_PASS and AUTHENTIK_SECRET_KEY openssl rand -hex 16 # For AUTHENTIK_BOOTSTRAP_TOKEN </syntaxhighlight>
4. Start Authentik
<syntaxhighlight lang="bash"> cd /library/authentik-app docker compose up -d </syntaxhighlight>
Wait for PostgreSQL to be healthy and server to start (~30-60 seconds):
<syntaxhighlight lang="bash"> docker compose logs -f server
- Watch for "Application startup complete"
</syntaxhighlight>
5. Initial Admin User
After startup, navigate to https://key.wilsoz.com/if/admin/:
- Username:
akadmin - Password: value of
AUTHENTIK_BOOTSTRAP_PASSWORD
First steps in Admin UI:
- Go to Directory → Users → Create
- Username:
marcus - Email:
[email protected] - Set password (or let user set on first login)
- Username:
Groups: Add to authentik Admins**
- Go to Directory → Groups → Create
authentik Admins** (if not already created) family-and-friends** (for app access) craniumslows-email** (for email provisioning) wilsoz-email** (for email provisioning) ldap-search** (for LDAP bind accounts)
- Add service users:
Directory → Users → Create**
- Username:
stalwart-svc, Email:stalwart-svc@internal
- Username:
Groups: Add to ldap-search**
- Username:
nextcloud-svc, Email:nextcloud-svc@internal
- Username:
Groups: Add to ldap-search**
6. Set Up LDAP Outpost
LDAP is required for Stalwart (mail server), Nextcloud (CalDAV/CardDAV), and Jellyfin (media server) to authenticate.
In Authentik Admin UI:
- Go to Infrastructure → Outposts → Create
- Name:
authentik-ldap - Type: LDAP
- Name:
- In Directory → LDAP → Configure LDAP
- Base DN:
dc=ldap,dc=goauthentik,dc=io - User base:
ou=users,dc=ldap,dc=goauthentik,dc=io
- Base DN:
- Assign the LDAP outpost to the LDAP provider
The LDAP server will be reachable at 172.17.0.1:389 from other containers.
7. Configure OAuth2 Providers
For each OAuth application (Immich, Memos, Linkwarden, etc.), create an OAuth2 provider in Authentik:
Immich example:
- Go to Applications → Providers → Create OAuth2/OpenID Provider
- Name:
immich-oauth - Authorization flow:
default-authentication-flow - Client type:
Confidential - Redirect URIs:
- Name:
```
https://photos.wilsoz.com/auth/login/oauth2/callback
https://photos.wilsoz.com/auth/login/oauth2/mobile-redirect
```
- Save — copy the generated Client ID and Client Secret
- Add property mappings:
authentik default OAuth Mapping: OpenID 'openid'authentik default OAuth Mapping: OpenID 'email'authentik default OAuth Mapping: OpenID 'profile'
- Enable:
include_claims_in_id_token - Assign a signing key (see Critical Gotchas section below)
Repeat for each app.
8. Configure VPS Reverse Proxy
On VPS, add nginx server block:
<syntaxhighlight lang="nginx"> server {
listen 443 ssl http2; server_name key.wilsoz.com;
ssl_certificate /etc/letsencrypt/live/key.wilsoz.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/key.wilsoz.com/privkey.pem;
location / {
proxy_pass http://100.64.207.155:9000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
} </syntaxhighlight>
Reload nginx: <syntaxhighlight lang="bash"> sudo systemctl reload nginx </syntaxhighlight>
Disaster Mode A: Configuration Corruption
Symptoms
- Can't log into admin interface
- OAuth providers missing or broken
- LDAP directory returning errors
- Groups or users deleted accidentally
- Provider credentials lost
Recovery Steps
⚠️ This mode resets Authentik to a fresh state. User data will be lost unless you have a PostgreSQL backup (see Disaster Mode B).
Option 1: Full Reset (if Disaster Mode B not available)
<syntaxhighlight lang="bash"> cd /library/authentik-app
- Stop all containers
docker compose down
- Remove the database volume (this deletes all Authentik data)
docker volume rm authentik-app_database
- Start from scratch
docker compose up -d
- Wait for startup
sleep 30 docker logs server | grep "Application startup complete"
- Follow "Initial Setup from Scratch" section above
</syntaxhighlight>
Option 2: Selective Reset (if you only need to fix one app)
<syntaxhighlight lang="bash">
- Access the Django shell
docker exec authentik-app_server_1 ak shell
- Example: Fix an OAuth provider's signing key
from authentik.providers.oauth2.models import OAuth2Provider from authentik.crypto.models import CertificateKeyPair
p = OAuth2Provider.objects.get(name='immich-oauth') jwt_key = CertificateKeyPair.objects.get(name='authentik Internal JWT Certificate') p.signing_key = jwt_key p.save() print(f'Updated {p.name} with JWT signing key') </syntaxhighlight>
Disaster Mode B: Drive Failure / Full Recovery
If Backups Accessible
Authentik data is backed up in two ways:
- PostgreSQL dump at Hetzner (in
/dumps/authentik-YYYYMMDD.sql.gz) - Media files at Hetzner (in
/data/authentik/)
Recovery procedure:
<syntaxhighlight lang="bash">
- 1. Set up fresh Authentik (follow "Initial Setup from Scratch" through step 4)
cd /library/authentik-app docker compose up -d
- 2. Wait for PostgreSQL to be ready
sleep 30
- 3. Drop the initial empty database
docker exec authentik-app_postgresql_1 psql -U authentik -d postgres -c "DROP DATABASE authentik;"
- 4. Create a fresh empty database
docker exec authentik-app_postgresql_1 psql -U authentik -d postgres -c "CREATE DATABASE authentik;"
- 5. Restore from backup dump (substitute actual date)
- First, extract the backup from Hetzner:
- (You'll need ssh-key access to u540853.your-storagebox.de port 23)
ssh -p 23 [email protected] "cat backups/authentik-20260512.sql.gz" | \
gunzip | docker exec -i authentik-app_postgresql_1 psql -U authentik -d authentik
- 6. Restore media files
rsync -av -e "ssh -p 23" [email protected]:backups/data/authentik/ /library/authentik-app/media/
- 7. Restart Authentik to pick up restored data
docker compose restart server worker
- 8. Verify
docker logs server | grep "Application startup complete" curl -s https://key.wilsoz.com/if/admin/ | grep -q "authentik" && echo "Admin UI responding" </syntaxhighlight>
If Backups NOT Accessible
Fall back to Mode A (full reset). Note: All user data, OAuth provider credentials, and LDAP settings will be lost.
After reset, you'll need to:
- Recreate all users and groups
- Recreate all OAuth2 providers and get new Client IDs/Secrets
- Update all dependent services (.env files) with new credentials
- Recreate LDAP configuration and outpost
Data Locations
Authentik Data on Host
<syntaxhighlight lang="text"> /library/authentik-app/ ├── docker-compose.yml (service definition) ├── .env (secrets: PG_PASS, AUTHENTIK_SECRET_KEY) ├── media/ (custom templates, branding, uploads) └── custom-templates/ (HTML templates for login pages, etc.) </syntaxhighlight>
PostgreSQL Database Volume
<syntaxhighlight lang="text"> authentik-app_database (Docker volume) ├── postgresql/ (database files) └── ... </syntaxhighlight>
Contains:
- All users, groups, group memberships
- All OAuth2 providers, applications, credentials
- All LDAP configuration
- All API tokens
- All authenticator devices (TOTP, WebAuthn)
- All event logs
Backup Locations
- PostgreSQL dump: Hetzner
/dumps/authentik-YYYYMMDD.sql.gz(daily at 03:00 CST) - Media files: Hetzner
/data/authentik/(daily Restic snapshot) - Filesystem snapshot: Timeshift snapshot on
/dev/md1(weekly)
What's NOT Backed Up
- Container images (re-downloadable from Docker Hub)
- node_modules and build artifacts (not present in Authentik)
Critical Gotchas
1. OAuth2 Signing Key Assignment — MANDATORY
⚠️ If you don't assign a signing key to an OAuth2 provider, the JWKS endpoint returns an empty object {}, and all clients trying to validate tokens will fail.
Every OAuth2 provider MUST have:
- A signing key assigned: Use
authentik Internal JWT Certificate(HS256 algorithm) - NOT
authentik Self-signed Certificate(RS256) — some apps like Mealie reject RS256
Assignment code: <syntaxhighlight lang="bash"> docker exec authentik-app_server_1 ak shell -c " from authentik.providers.oauth2.models import OAuth2Provider from authentik.crypto.models import CertificateKeyPair
p = OAuth2Provider.objects.get(name='immich-oauth') jwt_key = CertificateKeyPair.objects.get(name='authentik Internal JWT Certificate') p.signing_key = jwt_key p.save() print(f'Assigned signing key to {p.name}') " </syntaxhighlight>
2. Property Mappings for OAuth Scopes
OAuth providers need explicit property mappings for scopes like email, profile. Without them:
- OIDC discovery endpoint returns only
["openid"] - Apps can't get user email or name from token
Always add these three mappings to every OAuth provider:
authentik default OAuth Mapping: OpenID 'openid'authentik default OAuth Mapping: OpenID 'email'authentik default OAuth Mapping: OpenID 'profile'
Also enable: include_claims_in_id_token = True
3. LDAP Outpost Internal-Only
The LDAP outpost (port 389) is internal to Docker networking only. External apps can't reach it directly. Instead:
- Internal Docker containers reach it at
172.17.0.1:389 - Other hosts on LAN reach it via Stalwart LDAP passthrough (Stalwart exposes LDAP to port 389 externally)
4. Bootstrap Credentials Not Persisted
The AUTHENTIK_BOOTSTRAP_PASSWORD and AUTHENTIK_BOOTSTRAP_TOKEN in .env are only used on first startup. After that, they're ignored. If you lose them:
- You still have the
akadminuser created from bootstrap - If you lose the akadmin password, reset via Django shell:
<syntaxhighlight lang="bash"> docker exec authentik-app_server_1 ak shell -c " from authentik.core.models import User u = User.objects.get(username='akadmin') u.set_password('NewPassword123') u.save() print(f'Reset password for {u.username}') " </syntaxhighlight>
5. Secret Key Rotation (Rare but Important)
The AUTHENTIK_SECRET_KEY is used to encrypt stored secrets (OAuth credentials, etc.). If you change this .env value, all encrypted secrets become unreadable. Only change if:
- You're migrating to a new server
- You suspect key compromise
When rotating:
- Export all OAuth providers' client secrets before changing
- Update AUTHENTIK_SECRET_KEY
- Restart (secrets will need to be re-entered)
6. Group Membership Propagation Delay
Changes to group membership (e.g., adding a user to a group) are propagated asynchronously via the worker. If an app isn't seeing the new group:
- Wait 5-10 seconds
- Restart the worker:
docker compose restart worker - Check the worker logs:
docker logs worker | tail -20
7. API Token Expiry
API tokens can have an expiry. The current claude-api-token (created 2026-02-16) is set to never expire. Check token settings:
<syntaxhighlight lang="bash"> docker exec authentik-app_server_1 ak shell -c " from authentik.core.models import Token t = Token.objects.get(identifier='claude-api-token') print(f'Token: {t.identifier}') print(f'Expires: {t.expires}') " </syntaxhighlight>
If a token expires, create a new one in the Admin UI (User → Tokens) and update all scripts/services using it.
8. LDAP Bind Accounts Must Be in ldap-search Group
Any user/service that needs to query the LDAP directory must be a member of the ldap-search group. Currently:
stalwart-svc— for mail server LDAP lookupsnextcloud-svc— for CalDAV/CardDAV user sync
Without group membership, LDAP bind fails with "Access Denied".
Verification Checklist
After recovery, verify:
- [ ] Admin UI accessible:
https://key.wilsoz.com/if/admin/→ login as marcus - [ ] OAuth discovery endpoint working:
```bash curl -s https://key.wilsoz.com/application/o/immich/.well-known/openid-configuration | jq '.scopes_supported' # Should include: ["openid", "email", "profile"] ```
- [ ] JWKS endpoint has keys:
```bash curl -s https://key.wilsoz.com/application/o/immich/jwks/ | jq '.keys | length' # Should return a number > 0 ```
- [ ] LDAP directory responding:
```bash ldapsearch -H ldap://172.17.0.1:389 -D "cn=stalwart-svc,ou=users,dc=ldap,dc=goauthentik,dc=io" \ -w <stalwart-svc-password> -b "ou=users,dc=ldap,dc=goauthentik,dc=io" "uid=*" | grep "numResponses" # Should return matches (or at least show successful bind) ```
- [ ] Users present:
```bash
docker exec authentik-app_server_1 ak shell -c "from authentik.core.models import User; print('\n'.join([u.username for u in User.objects.all()]))"
# Should show: akadmin, marcus, stalwart-svc, nextcloud-svc
```
- [ ] Groups present:
```bash
docker exec authentik-app_server_1 ak shell -c "from authentik.core.models import Group; print('\n'.join([g.name for g in Group.objects.all()]))"
# Should show all configured groups
```
- [ ] OAuth providers have signing keys:
```bash
docker exec authentik-app_server_1 ak shell -c "
from authentik.providers.oauth2.models import OAuth2Provider
for p in OAuth2Provider.objects.all():
has_key = p.signing_key is not None
print(f'{p.name}: signing_key={has_key}')
"
# All should show: signing_key=True
```
- [ ] Dependent services can authenticate:
- [ ] Immich: Try OAuth login at https://photos.wilsoz.com
- [ ] Linkwarden: Try OAuth login at https://bookmarks.wilsoz.com
- [ ] Memos: Try OAuth login at https://notes.wilsoz.com
- [ ] Stalwart IMAP: Test LDAP lookup for mail routing
Dependencies
What Authentik Depends On
- PostgreSQL 16 — must be healthy before server/worker start
- Docker — for container runtime
- Network access to Cloudflare DNS — for DNS resolution of
key.wilsoz.com - VPS reverse proxy — nginx on VPS must forward
key.wilsoz.com:443tostronghold:9000
What Depends On Authentik
- All OAuth2 consumers: Immich, Memos, Linkwarden, Forgejo, Vaultwarden, Grafana, n8n, Matrix
- All LDAP consumers: Nextcloud, Jellyfin, Stalwart (mail server)
- Cloudflare Access: For gating n8n form URLs
- Email provisioning workflow (n8n): Watches Authentik groups for email user provisioning
- Nginx reverse proxy: Serves key.wilsoz.com → Authentik
Operations
Start/Stop/Restart
<syntaxhighlight lang="bash"> cd /library/authentik-app
- Start
docker compose up -d
- Stop
docker compose down
- Restart
docker compose restart server worker
- Full restart (clears caches)
docker compose down && sleep 2 && docker compose up -d </syntaxhighlight>
View Logs
<syntaxhighlight lang="bash">
- Server logs
docker logs -f server
- Worker logs (for background tasks)
docker logs -f worker
- PostgreSQL logs (for DB issues)
docker logs postgresql
- All together
docker compose logs -f </syntaxhighlight>
Access Django Shell (Advanced)
For one-off admin tasks:
<syntaxhighlight lang="bash"> docker exec authentik-app_server_1 ak shell
- Example: List all users
from authentik.core.models import User for u in User.objects.all():
print(f"{u.username}: {u.email}, groups: {list(u.groups.values_list('name', flat=True))}")
- Example: Create API token
from authentik.core.models import Token t = Token.objects.create(user=User.objects.get(username='marcus'), identifier='my-api-key') print(f"Token: {t.key}")
- Exit: Ctrl+D
</syntaxhighlight>
Backup PostgreSQL Manually
<syntaxhighlight lang="bash">
- Full database dump
docker exec authentik-app_postgresql_1 pg_dump -U authentik authentik | \
gzip > /home/mnw/backups/authentik-manual-$(date +%Y%m%d-%H%M%S).sql.gz
- Or via Restic (for Hetzner backup)
cd /library/backup-stack && docker compose exec restic-backup bash -c "
export RESTIC_REPOSITORY=\$HETZNER_REPO export RESTIC_PASSWORD=\$HETZNER_PASSWORD # Make dump available in /data docker exec authentik-app_postgresql_1 pg_dump -U authentik authentik | gzip > /data/dumps/authentik-manual.sql.gz restic backup /data/dumps/
" </syntaxhighlight>
Troubleshooting
Can't log into admin UI
Symptoms: 403 Forbidden, or password rejected
Fixes:
- Check if server is running:
docker ps | grep server - Reset akadmin password via Django shell (see Operations section)
- Check logs:
docker logs server | grep -i "error\|auth"
OAuth login fails with "invalid_grant"
Symptoms: Client authentication failed, or code exchange error
Causes & fixes:
- Client secret mismatch: Verify in Authentik provider matches app's .env
- Provider deleted: Recreate OAuth provider and update app config
- Redirect URI mismatch: Ensure app's callback URL matches provider's redirect URIs exactly
Debug: <syntaxhighlight lang="bash"> docker logs server | grep -i "oauth\|invalid_grant" </syntaxhighlight>
LDAP bind fails
Symptoms: Stalwart/Nextcloud can't authenticate users
Fixes:
- Verify LDAP outpost is running:
docker ps | grep outposts - Check user is in
ldap-searchgroup: Admin UI → Directory → Groups → ldap-search - Test bind from stronghold:
```bash
ldapsearch -H ldap://172.17.0.1:389 -D "cn=stalwart-svc,ou=users,dc=ldap,dc=goauthentik,dc=io" \
-w <password> -b "ou=users" "uid=marcus"
```
Worker not picking up changes
Symptoms: Group membership not reflected, or other background tasks stuck
Fix: <syntaxhighlight lang="bash"> docker compose restart worker docker logs worker --tail=50 </syntaxhighlight>
Database corruption
Symptoms: PostgreSQL won't start, or "ERROR: relation does not exist"
Fix:
- Try recovery from backup (Disaster Mode B)
- If no backup: full reset (Disaster Mode A) — all data lost
Links & References
- Authentik Docs: https://goauthentik.io/docs/
- Authentik Admin UI: https://key.wilsoz.com/if/admin/
- PostgreSQL Docs: https://www.postgresql.org/docs/16/
- OAuth 2.0 Spec: https://datatracker.ietf.org/doc/html/rfc6749
- OpenID Connect Spec: https://openid.net/connect/
Related Services
- OpenBao (secrets store):
/library/openbao-app/— stores API tokens - Stalwart (mail server): Uses LDAP for user lookups
- Nextcloud (file sync): Uses LDAP for CalDAV/CardDAV
- n8n (automation): Uses OAuth for form access control
- PostgreSQL (database): Internal to Authentik
- Nginx (reverse proxy): VPS nginx forwards key.wilsoz.com traffic here