- Environment-based configuration (no hardcoded secrets) - OAuth authentication via Authentik - ElevenLabs TTS integration via SAG CLI - FCM push notification support - User preferences sync system - Multi-user support with per-user context files - No internal IPs or service accounts in tracked files
8.0 KiB
8.0 KiB
Alfred Mobile Proxy Deployment Guide
Overview
Your setup:
- Client ID:
QeSNaZPqZUz5pPClZMA2bakSsddkStiEhqbE4QZR - Authentik URL:
https://auth.dnspegasus.net - Gateway token:
9b87d15fee3922ecfbe77b0ea1744851757cda618beceeba - Mobile URL:
wss://alfred-app.dnspegasus.net
Architecture
Android App
↓ OAuth: auth.dnspegasus.net
↓ WebSocket: wss://alfred-app.dnspegasus.net
HAProxy (192.168.1.20)
↓ Proxy backend → 192.168.1.169:18790
Alfred Proxy (localhost:18790)
↓ Validates OAuth token
↓ Injects gateway token
OpenClaw (localhost:18789)
Step 1: Configure Proxy
cd ~/.openclaw/workspace/alfred-proxy
# Create .env file
cat > .env << 'EOF'
PROXY_PORT=18790
OPENCLAW_URL=ws://127.0.0.1:18789
OPENCLAW_TOKEN=9b87d15fee3922ecfbe77b0ea1744851757cda618beceeba
AUTHENTIK_URL=https://auth.dnspegasus.net
AUTHENTIK_CLIENT_ID=QeSNaZPqZUz5pPClZMA2bakSsddkStiEhqbE4QZR
REQUIRE_AUTH=true
EOF
# Install dependencies
npm install
# Test locally first
npm run dev
In another terminal:
# Test health
curl http://localhost:18790/health
# Should return: {"status":"ok","service":"alfred-proxy"}
Step 2: Switch OpenClaw to Localhost
# Check current setting
openclaw config get gateway.bind
# Switch to localhost only
cat >> ~/.openclaw/openclaw.json << 'EOF'
{
"gateway": {
"bind": "loopback"
}
}
EOF
# Restart OpenClaw
systemctl --user restart openclaw-gateway.service
# Verify
openclaw config get gateway.bind
# Should show: "loopback"
# Test local connection
wscat -c ws://127.0.0.1:18789
# Should see connect challenge
Step 3: Install Proxy as Service
cd ~/.openclaw/workspace/alfred-proxy
# Install systemd service
mkdir -p ~/.config/systemd/user
cp alfred-proxy.service ~/.config/systemd/user/
# Create override with your client ID
mkdir -p ~/.config/systemd/user/alfred-proxy.service.d
cat > ~/.config/systemd/user/alfred-proxy.service.d/override.conf << 'EOF'
[Service]
Environment="AUTHENTIK_CLIENT_ID=QeSNaZPqZUz5pPClZMA2bakSsddkStiEhqbE4QZR"
EOF
# Reload and start
systemctl --user daemon-reload
systemctl --user enable alfred-proxy.service
systemctl --user start alfred-proxy.service
# Check status
systemctl --user status alfred-proxy.service
# View logs
journalctl --user -u alfred-proxy.service -f
Step 4: Verify DNS (Already Done!)
You already have a wildcard DNS record pointing to HAProxy, so alfred-app.dnspegasus.net should already resolve!
Test DNS:
nslookup alfred-app.dnspegasus.net
# Should resolve to your HAProxy IP (via wildcard *.dnspegasus.net)
If it doesn't work, you may need to explicitly add:
Type: A
Host: alfred-app
Value: <your HAProxy IP>
TTL: 300
Step 5: Configure HAProxy
SSH to HAProxy:
ssh root@192.168.1.20
Edit HAProxy config:
docker exec -it haproxy-manager bash
nano /etc/haproxy/haproxy.cfg
Add this configuration (based on haproxy-alfred-app.cfg):
# In your frontend section (around line ~50):
frontend https_frontend
# ... existing config ...
# NEW: alfred-app subdomain ACL
acl alfred_app_acl hdr(host) -i alfred-app.dnspegasus.net
acl is_websocket hdr(Upgrade) -i WebSocket
acl is_websocket_connection hdr_beg(Connection) -i Upgrade
# Route alfred-app subdomain
use_backend alfred_mobile_proxy-backend if alfred_app_acl is_websocket is_websocket_connection
use_backend alfred_mobile_redirect-backend if alfred_app_acl
# At the end of the file, add new backends:
backend alfred_mobile_proxy-backend
mode http
option forwardfor
http-request add-header X-CLIENT-IP %[var(txn.real_ip)]
http-request set-header X-Real-IP %[var(txn.real_ip)]
http-request set-header X-Forwarded-For %[var(txn.real_ip)]
http-request set-header X-Forwarded-Proto https if { ssl_fc }
timeout tunnel 1h
timeout client 1h
timeout server 1h
# IMPORTANT: Your desktop IP where proxy runs
# IP: 192.168.1.169 Port: 18790
server alfred_proxy 192.168.1.169:18790 check
backend alfred_mobile_redirect-backend
mode http
http-request return status 200 content-type "text/html" string '<!DOCTYPE html><html><head><meta charset="utf-8"><meta http-equiv="refresh" content="0;url=https://alfred.dnspegasus.net"><title>Alfred Mobile</title><style>body{font-family:system-ui;text-align:center;padding:50px;background:linear-gradient(135deg,#667eea,#764ba2);color:#fff}h1{font-size:2.5rem;margin-bottom:1rem}p{font-size:1.1rem;opacity:0.9}</style></head><body><h1>🤵 Alfred Mobile</h1><p>This endpoint is for the mobile app.</p><p>Redirecting to web interface...</p></body></html>'
Test HAProxy config:
haproxy -c -f /etc/haproxy/haproxy.cfg
# Should show: Configuration file is valid
Reload HAProxy:
# If using Docker container:
docker exec haproxy-manager kill -HUP 1
# Or restart:
docker restart haproxy-manager
Step 6: Open Firewall (if needed)
On your desktop (where proxy runs):
# PowerShell (Admin)
New-NetFirewallRule -DisplayName "Alfred Proxy" -Direction Inbound -LocalPort 18790 -Protocol TCP -Action Allow
Or use your existing scripts:
.\open-openclaw-port.ps1
# Then modify for port 18790
Step 7: Test End-to-End
From outside your network:
# Test DNS
nslookup alfred-app.dnspegasus.net
# Test HTTPS redirect (browser should redirect)
curl -I https://alfred-app.dnspegasus.net
# Test WebSocket (requires valid OAuth token)
# Get token from Authentik first, then:
wscat -c "wss://alfred-app.dnspegasus.net" -H "Authorization: Bearer YOUR_TOKEN"
Expected flow:
- Browser →
https://alfred-app.dnspegasus.net→ Redirects tohttps://alfred.dnspegasus.net✅ - Mobile app →
wss://alfred-app.dnspegasus.net→ Connects to proxy ✅
Step 8: Android App Configuration
Update your Android app:
// OAuthConfig.kt
object OAuthConfig {
const val AUTHENTIK_URL = "https://auth.dnspegasus.net"
const val CLIENT_ID = "QeSNaZPqZUz5pPClZMA2bakSsddkStiEhqbE4QZR"
const val REDIRECT_URI = "alfredmobile://oauth/callback"
const val SCOPE = "openid profile email"
const val AUTHORIZATION_ENDPOINT = "$AUTHENTIK_URL/application/o/authorize/"
const val TOKEN_ENDPOINT = "$AUTHENTIK_URL/application/o/token/"
}
// AlfredConfig.kt
object AlfredConfig {
const val GATEWAY_URL = "wss://alfred-app.dnspegasus.net"
}
Troubleshooting
Proxy won't start
# Check logs
journalctl --user -u alfred-proxy.service -n 50
# Test manually
cd ~/.openclaw/workspace/alfred-proxy
npm run dev
Can't connect from mobile
# Check proxy is listening
ss -tuln | grep 18790
# Check firewall
sudo iptables -L -n | grep 18790
# Check HAProxy backend
curl http://192.168.1.169:18790/health
"Invalid token" errors
# Verify Authentik config
curl https://auth.dnspegasus.net/.well-known/openid-configuration
# Test token validation
curl -H "Authorization: Bearer TOKEN" \
https://auth.dnspegasus.net/application/o/userinfo/
DNS not resolving
# Check DNS record exists (should work via wildcard)
nslookup alfred-app.dnspegasus.net
# Try public DNS
nslookup alfred-app.dnspegasus.net 8.8.8.8
Security Checklist
- OpenClaw bound to localhost only
- Proxy validates OAuth tokens
- Gateway token not exposed
- HTTPS/WSS for external access
- Firewall rules configured
- Monitoring set up
- Test token revocation
Monitoring
Watch proxy logs:
journalctl --user -u alfred-proxy.service -f
Watch OpenClaw logs:
journalctl --user -u openclaw-gateway.service -f
Watch HAProxy logs:
ssh root@192.168.1.20
docker logs -f haproxy-manager
Next Steps
- Test locally (proxy + OpenClaw)
- Configure HAProxy (add mobile subdomain)
- Add DNS record
- Test from outside (mobile network)
- Implement OAuth in Android app
- Test full flow