Initial
This commit is contained in:
@@ -0,0 +1,161 @@
|
||||
# DJ7NTs QO100 Webconsole
|
||||
|
||||
> **Disclaimer:** This is a proof-of-concept project. Use at your own risk — no guarantees or warranties of any kind. The source code is not fully open-source at this time.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Docker (any recent version) and Docker Compose
|
||||
- **Analog Devices PlutoSDR** (original rev.B/C) — this image does **not** work with Pluto Plus, Hamgeek AD9363, LibreSDR, or other AD9363-based clones
|
||||
- **USB-to-Ethernet adapter** (100 Mbit) connected to the Pluto's USB OTG port — Gigabit adapters are not supported and may cause issues
|
||||
- LNB connected to the PlutoSDR
|
||||
- The Pluto and the host running Docker must be on the same network
|
||||
|
||||
The prebuilt image is available for **x86_64** (PCs/servers) and **arm64** (Raspberry Pi 4+, Rock 5 ITX). Docker automatically pulls the correct variant for your hardware.
|
||||
|
||||
## Quick Start with Docker Compose
|
||||
|
||||
Create a `docker-compose.yml`:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
sdrc:
|
||||
image: git.dj7nt.de/dj7nt/qo100wc:latest
|
||||
ports:
|
||||
- "3004:3000"
|
||||
volumes:
|
||||
- ./data:/app/data
|
||||
environment:
|
||||
SESSION_SECRET: ${SESSION_SECRET}
|
||||
DATABASE_PATH: /app/data/qo100.db
|
||||
PLUTO_CONNECTED: "1"
|
||||
restart: unless-stopped
|
||||
```
|
||||
|
||||
Generate a session secret and create a `.env` file:
|
||||
|
||||
```bash
|
||||
echo "SESSION_SECRET=$(openssl rand -base64 32 | tr -dc 'a-zA-Z0-9' | head -c 32)" > .env
|
||||
```
|
||||
|
||||
Create the data directory before starting (Docker would create it as root otherwise):
|
||||
|
||||
```bash
|
||||
mkdir -p data
|
||||
```
|
||||
|
||||
Start:
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
## First-Time Setup
|
||||
|
||||
1. Open `http://<your-host>:3004` in a browser
|
||||
2. Log in with **admin** / **admin** (you will be forced to change the password)
|
||||
3. Navigate to **Setup** (or go to `/setup`)
|
||||
4. Configure:
|
||||
- **PlutoSDR IP** — the IP address of your Pluto (default: `192.168.6.122`)
|
||||
- **LNB LO Frequency** — the actual local oscillator frequency of your LNB in Hz. This is *not* the nominal 9750 MHz — e.g. my Bullseye TCXO LNB runs at `9749971700` Hz (9750 MHz minus ~28.3 kHz offset). If you use a different LNB, measure or look up its exact LO frequency.
|
||||
5. Click **Save and Connect**
|
||||
|
||||
To change these later, go to **Setup** as admin.
|
||||
|
||||
## Networking: Reaching the Pluto
|
||||
|
||||
By default Docker uses bridge networking. If the Pluto is on a separate Ethernet interface the container can't route to, use host networking (Linux only):
|
||||
|
||||
```yaml
|
||||
services:
|
||||
sdrc:
|
||||
image: git.dj7nt.de/dj7nt/qo100wc:latest
|
||||
network_mode: host
|
||||
# no ports: block needed — app listens on 3000 directly
|
||||
volumes:
|
||||
- ./data:/app/data
|
||||
environment:
|
||||
SESSION_SECRET: ${SESSION_SECRET}
|
||||
DATABASE_PATH: /app/data/qo100.db
|
||||
PLUTO_CONNECTED: "1"
|
||||
restart: unless-stopped
|
||||
```
|
||||
|
||||
## HTTPS / Microphone Access
|
||||
|
||||
The browser's `getUserMedia()` API (used for TX microphone capture) requires a **secure context**. This means one of:
|
||||
|
||||
- Access via `http://localhost` (works for local testing only)
|
||||
- Access via **HTTPS** (required for remote access)
|
||||
|
||||
The Docker image does **not** include HTTPS. You need a reverse proxy.
|
||||
|
||||
### HAProxy Example
|
||||
|
||||
Put HAProxy in front to terminate TLS (e.g. with Let's Encrypt via certbot):
|
||||
|
||||
```yaml
|
||||
services:
|
||||
sdrc:
|
||||
image: git.dj7nt.de/dj7nt/qo100wc:latest
|
||||
# no ports exposed publicly — only haproxy talks to it
|
||||
volumes:
|
||||
- ./data:/app/data
|
||||
environment:
|
||||
SESSION_SECRET: ${SESSION_SECRET}
|
||||
DATABASE_PATH: /app/data/qo100.db
|
||||
PLUTO_CONNECTED: "1"
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- internal
|
||||
|
||||
haproxy:
|
||||
image: haproxy:3
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
volumes:
|
||||
- ./haproxy/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro
|
||||
- ./certs:/usr/local/etc/haproxy/certs:ro
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- internal
|
||||
|
||||
networks:
|
||||
internal:
|
||||
```
|
||||
|
||||
`haproxy/haproxy.cfg`:
|
||||
|
||||
```
|
||||
frontend http
|
||||
bind *:80
|
||||
http-request redirect scheme https unless { ssl_fc }
|
||||
|
||||
frontend https
|
||||
bind *:443 ssl crt /usr/local/etc/haproxy/certs/sdrc.pem
|
||||
|
||||
default_backend sdrc
|
||||
|
||||
backend sdrc
|
||||
server sdrc sdrc:3000
|
||||
```
|
||||
|
||||
Place your fullchain + privkey as `certs/sdrc.pem` (concatenated PEM). With Let's Encrypt:
|
||||
|
||||
```bash
|
||||
certbot certonly --standalone -d sdrc.example.com
|
||||
cat /etc/letsencrypt/live/sdrc.example.com/fullchain.pem \
|
||||
/etc/letsencrypt/live/sdrc.example.com/privkey.pem > certs/sdrc.pem
|
||||
```
|
||||
|
||||
After this setup, open `https://sdrc.example.com` — the browser will allow microphone access for TX.
|
||||
|
||||
### Alternative: Chrome Flag (Not Recommended for Production)
|
||||
|
||||
For testing without HTTPS, launch Chrome with:
|
||||
|
||||
```
|
||||
chrome --unsafely-treat-insecure-origin-as-secure=http://<host>:3004
|
||||
```
|
||||
|
||||
This grants media permissions on that HTTP origin. Only use for development.
|
||||
Reference in New Issue
Block a user