This directory contains the active OPAQUE web application.
Stack:
- Next.js 15 and React 19
- Postgres
- Drizzle ORM and migrations
- Auth.js
- Tailwind CSS
cp .env.example .env.local
docker compose up -d postgres
npm install
npm run db:ensure
npm run db:migrate
npm run db:upgrade
npm run devOpen http://localhost:3000.
Required local env:
DATABASE_URL=postgres://opaque:change-me@localhost:5432/opaque
AUTH_SECRET=<generate-with-openssl-rand-base64-32>
AUTH_URL=http://localhost:3000Generate a secret:
openssl rand -base64 32Create and edit the deploy env file:
cp .env.example .envSet production values:
POSTGRES_DB=opaque
POSTGRES_USER=opaque
POSTGRES_PASSWORD=<generate-a-strong-password>
AUTH_SECRET=<generate-with-openssl-rand-base64-32>
AUTH_URL=https://opaque.example.com
METRICS_RETENTION_DAYS=7Optional GitHub OAuth:
AUTH_GITHUB_ID=
AUTH_GITHUB_SECRET=Start the stack:
docker compose up -d --buildInspect logs:
docker compose logs -f webUpgrade:
git pull
docker compose up -d --buildStop:
docker compose downDelete all persisted database data:
docker compose down -vDATABASE_URL: local Postgres connection string used outside Docker.POSTGRES_DB: Docker Compose database name.POSTGRES_USER: Docker Compose database user.POSTGRES_PASSWORD: Docker Compose database password.AUTH_SECRET: Auth.js secret. Required.AUTH_URL: public application URL.AUTH_GITHUB_ID: optional GitHub OAuth client id.AUTH_GITHUB_SECRET: optional GitHub OAuth client secret.METRICS_RETENTION_DAYS: metric sample retention window, default7.
Do not commit .env or .env.local.
The dashboard loads module data through authenticated server routes. Configure a module in edit mode, save, then exit edit mode.
- Weather: Open-Meteo, no API key required.
- Calendar: local month view.
- Markets: Yahoo Finance chart data with compact sparklines.
- Plex: libraries, active streams, and recently added items with posters.
- Jellyfin / Emby: media folders, active streams, and recent items with posters.
- Radarr / Sonarr: collection status, missing queue, and recent posters.
- RSS: RSS or Atom feeds.
- Reddit: subreddit Atom feeds.
- Hacker News: public Firebase API.
Media images are loaded through /api/modules/image so service credentials do
not appear in browser image URLs.
OPAQUE uses an agent push model. The app does not SSH into your machines; each monitored Linux server runs a lightweight agent that POSTs metrics to OPAQUE with a per-server token.
- Add a server card in edit mode.
- Save the dashboard.
- Re-open the server editor and rotate an agent token.
- Copy the
Agent idand generated token. - Configure the remote server agent.
The Linux agent reports CPU, memory, root disk usage, aggregate non-loopback network throughput, load average, uptime, cores, and temperature when readable thermal sensors are available.
Run the mock agent locally:
SERVER_ID=copied-agent-id \
SERVER_AGENT_TOKEN=copied-agent-token \
OPAQUE_URL=http://localhost:3000 \
npm run mock:server-agentInstall the Linux agent:
sudo cp scripts/opaque-agent.sh /usr/local/bin/opaque-agent
sudo chmod +x /usr/local/bin/opaque-agentCreate /etc/opaque-agent.env:
OPAQUE_URL=https://opaque.example.com
SERVER_ID=copied-agent-id
SERVER_AGENT_TOKEN=copied-agent-token
OPAQUE_INTERVAL_SECONDS=5Create /etc/systemd/system/opaque-agent.service:
[Unit]
Description=Push OPAQUE server metrics
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
EnvironmentFile=/etc/opaque-agent.env
ExecStart=/usr/local/bin/opaque-agent
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.targetEnable it:
sudo systemctl daemon-reload
sudo systemctl enable --now opaque-agent.service
sudo systemctl status opaque-agent.service
journalctl -u opaque-agent.service -fnpm run dev
npm run build
npm run check
npm run start
npm run lint
npm run test:contract
npm run db:ensure
npm run db:migrate
npm run db:upgrade
npm run db:validate
npm run metrics:retention
npm run mock:server-agentRun contract tests with the app running:
CONTRACT_BASE_URL=http://localhost:3000 npm run test:contractset POSTGRES_PASSWORD in .env: createweb/.envand setPOSTGRES_PASSWORD.set AUTH_SECRET in .env: set a generatedAUTH_SECRET.401 unauthorized: sign in again, or check the server agent token.404 server not found: save the dashboard after creating a server card, then rotate a token.- Server card shows stale: the agent has not posted in the last 30 seconds.
- Temperature stays
0: the host may not expose readable thermal sensors. - Media service cannot connect: confirm the URL is reachable from the app container.