# Alpine 5G Router – Web GUI

Web interface with login and role-based access (admin and support). **One HTML page per function** (Status, Logs, Restart 5G, Config, Firewall, Routes, Users) with shared navigation.

**As of Rev 2, the Web GUI includes integrated 5G connection management.** It now handles:
- Modem AT commands via native Python (pyserial)
- 5G connection lifecycle (connect, disconnect, reconnect)
- Watchdog for automatic reconnection
- NAT/firewall configuration

The standalone `5g-router` service is no longer needed; `5g-webgui` is the recommended single service.

## Access

- **URL:** `http://<device-ip>:5000` (e.g. `http://10.130.60.121:5000`)
- **Default users:**  
  - **admin** / **admin** – full access (config, firewall, routes, users, logs, status, restart 5G)  
  - **support** / **support** – view status, view logs, restart 5G only (no config/firewall/users)

**Change default passwords** after first login (admin: Users tab → set password).

## Permissions

| Feature            | Admin | Support |
|--------------------|-------|--------|
| View status        | ✓     | ✓      |
| View logs          | ✓     | ✓      |
| Restart 5G         | ✓     | ✓      |
| Connect/Disconnect | ✓     | ✓      |
| Edit config        | ✓     | –      |
| Edit firewall      | ✓     | –      |
| View routes        | ✓     | –      |
| Manage users       | ✓     | –      |

## Install and run

### On the device (after main install)

```bash
# Install Python, Flask, and pyserial (Alpine)
apk add python3 py3-flask
pip install pyserial

# If you used scripts/install.sh, Web GUI is already under /usr/local/share/5g-webgui
# Enable and start the service:
rc-update add 5g-webgui default
service 5g-webgui start

# Or run manually (foreground)
cd /usr/local/share/5g-webgui && ./run.sh
```

### From repo (development)

```bash
cd web
pip install -r requirements.txt   # Flask and pyserial
python3 app.py
# Open http://localhost:5000
```

## API Endpoints for 5G Control

| Endpoint | Method | Description |
|----------|--------|-------------|
| `/api/status` | GET | Connection status + modem info |
| `/api/5g/status` | GET | Detailed connection status |
| `/api/5g/connect` | POST | Manually connect 5G |
| `/api/5g/disconnect` | POST | Manually disconnect 5G |
| `/api/5g/restart` | POST | Disconnect then reconnect |

## Architecture

```
5g-webgui service
    ├── Flask App (port 5000)
    ├── ATClient (pyserial → /dev/ttyUSB1)
    └── ConnectionManager
        ├── connect() - APN, PDP, IP, NAT
        ├── disconnect()
        ├── check_health()
        └── watchdog_loop() (background thread)
```

The connection auto-starts when the service starts (on first web request). If `WATCHDOG_INTERVAL` is set in `/etc/5g-router.conf`, a background thread periodically checks connection health and reconnects if needed.

## Security

- Set **SECRET_KEY** in production: `export SECRET_KEY="your-random-secret"` before starting the app (or in the OpenRC service).
- Use HTTPS in production (put the app behind nginx/caddy with TLS).
- Change default admin and support passwords immediately.

## SQLite database

The Web GUI uses **SQLite** (`web/data/alpine5g.db`) for:

- **users** – login accounts (admin/support); migrated from `users.json` on first run if that file existed.
- **iptables_rules** – firewall rules (table, rule line, enabled, order). On first load, if the DB is empty, rules are imported from `/etc/iptables/rules.v4`.
- **static_routes** – static routes (destination, gateway, dev, metric). Apply runs `ip route add` for each enabled route.

Firewall and Routes pages in the GUI list/add/edit/delete from the DB and provide an **Apply** button to write iptables and run `iptables-restore`, or run `ip route add` for routes.

## Files

| Path (on device)              | Purpose                    |
|-------------------------------|----------------------------|
| `/usr/local/share/5g-webgui/` | App and static files       |
| `/usr/local/share/5g-webgui/data/alpine5g.db` | SQLite DB (users, rules, routes) |
| `/etc/init.d/5g-webgui`        | OpenRC service             |
| `/var/log/5g-webgui.log`      | Service log                |

## Troubleshooting: Modem not up

If the modem/WAN is not coming up (Status shows WAN state DOWN, no IP, or “No modem AT data”):

**On the device**, run:

```bash
/usr/local/bin/diag-modem-up.sh
```

(or `./scripts/diag-modem-up.sh` from the repo). It reports:

- **5g-router service** status
- **Config** (WAN_IF, AT_PORT, APN)
- **Modem USB** (lsusb Fibocom; Mode 40 vs 41)
- **WAN interface** (exists, state, IP)
- **Default route** (via 5G or other)
- **AT port** (exists, AT response OK?)
- **Last log lines** from `/var/log/5g-router.log`
- **Ping** test and suggested fixes

Use this to see why connect-5g.sh failed (e.g. AT port not ready, wrong USB mode, no modem IP).

## Troubleshooting: No modem AT data

If the Status page shows **“No modem AT data (check AT port)”**, run the diagnostic **on the device** (SSH or console):

```bash
/usr/local/bin/diag-at-port.sh
```

(or `./scripts/diag-at-port.sh` from the repo). It reports:

- User and groups (whether you’re in **dialout** for serial access)
- Serial devices (`/dev/ttyUSB*`, permissions)
- Modem in `lsusb` (Fibocom / 0e8d)
- Config `AT_PORT` and whether it exists
- Raw **AT** probe on each ttyUSB (which port returns **OK**)
- Result of `modem-status-at.sh`

**Typical fixes:** Add the web server user (e.g. the one running gunicorn) to group **dialout**; set `AT_PORT` in `/etc/5g-router.conf` to the port that responds (e.g. `/dev/ttyUSB0`); ensure modem is in USB mode 40 (RNDIS) so the AT port is present.

## Optional: run behind reverse proxy

Example with **nginx** (apk add nginx):

```nginx
server {
    listen 80;
    server_name router.local;
    location / {
        proxy_pass http://127.0.0.1:5000;
        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;
    }
}
```

Then access via `http://router.local` (port 80) instead of port 5000.
