Self-Hosting the Dashboard (Static SPA)
The web dashboard described in Deployment runs as a Next.js process (the web PM2 app). There's also a separate, from-scratch rebuild of the same dashboard — same pages, same features, same look — that compiles down to a folder of plain static HTML/CSS/JS instead. This is what currently powers the official dashboard at arkenbot.app.
Next.js web (default) | Static SPA (this page) | |
|---|---|---|
| Repo | packages/web in the main monorepo | separate repo: t0xicVybez/Dashboard |
| Runtime | Node.js process, managed by PM2 | none — any static file host (nginx, Apache, a CDN) |
| Build output | .next/ (needs next start to serve) | dist/ (plain files, served by anything) |
| Good for | running everything on one box | hosting the dashboard separately/cheaper, or not wanting a 4th Node process |
Pick whichever fits your setup — both talk to the same ArkenBot API, so you can switch later without touching the bot or API at all.
It doesn't include or replace the bot or the API — you still need those running and reachable over HTTPS first (see the rest of this Self-Hosting section). This page only covers the dashboard piece.
1. Install the build tools
Only needed to build the site, not to run it afterward:
node -v # need 20+; see Prerequisites if you need to install it
pnpm -v # need 9+
2. Get the code and configure it
git clone https://github.com/t0xicVybez/Dashboard.git
cd Dashboard
cp .env.example .env
Fill in .env — these three values get baked into the build, so there's nothing to configure at runtime:
VITE_API_URL=https://api.yourdomain.com
VITE_WS_URL=wss://api.yourdomain.com
VITE_DISCORD_CLIENT_ID=123456789012345678 # your Discord application's ID — not a secret
3. Build and deploy
pnpm install
pnpm build
sudo mkdir -p /var/www/dashboard
sudo cp -r dist/* /var/www/dashboard/
dist/ is the entire site. There's no process to start — it's just files for a web server to hand out.
4. Configure nginx
sudo apt-get install -y nginx certbot python3-certbot-nginx
sudo certbot --nginx -d dashboard.yourdomain.com
Create /etc/nginx/sites-available/dashboard:
server {
listen 443 ssl;
server_name dashboard.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/dashboard.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/dashboard.yourdomain.com/privkey.pem;
root /var/www/dashboard;
index index.html;
# Vite's hashed asset filenames never change contents once built.
location /assets/ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# Single-page app: any URL that isn't a real file falls back to
# index.html so the client-side router can take over. Without this,
# refreshing on any route but / returns a 404.
location / {
try_files $uri $uri/ /index.html;
}
}
server {
listen 80;
server_name dashboard.yourdomain.com;
return 301 https://$host$request_uri;
}
sudo ln -s /etc/nginx/sites-available/dashboard /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
Many distros ship nginx with compression barely enabled, which makes every visitor's page load noticeably slower for no reason. In /etc/nginx/nginx.conf's http {} block, make sure gzip on; is set along with a gzip_types line covering at least text/css application/javascript application/json font/woff2 — this single setting can cut page weight by half or more. sudo nginx -t && sudo systemctl reload nginx after changing it. (An Apache config is in the repo's SETUP.md if you'd rather not use nginx.)
5. Point the API at this dashboard's origin
The API needs to allow this dashboard's domain, or the browser silently blocks every request after login:
CORS_ORIGIN=https://dashboard.yourdomain.com
If the dashboard's domain and the API's domain don't share a common root (e.g. dashboard.example.com talking to api.a-different-host.com — not two subdomains of the same domain), login will appear to succeed but every page after it will show you as logged out. Fix it on the API side:
SESSION_COOKIE_SAMESITE=none
NODE_ENV=production
Skip this if dashboard and API share a root domain (e.g. both under yourdomain.com) — it already works without it.
Updating
cd Dashboard
git pull
pnpm install
pnpm build
sudo cp -r dist/* /var/www/dashboard/
No process restart needed — the next page load serves the new files.
Troubleshooting
- Every route except
/404s, or refreshing any page breaks it — the SPA-fallbacklocation /block from step 4 is missing or wrong. - Login appears to work, then the dashboard acts logged out / shows 401s — the cross-origin cookie setup from step 5; double-check
CORS_ORIGINandSESSION_COOKIE_SAMESITE. - Blank page with a red error in the browser console — open DevTools (F12) → Console and read it; a
VITE_API_URL-related error usually means.envwasn't filled in correctly beforepnpm buildran (it's baked in at build time, not read at runtime). pnpm buildfails — almost always a.envtypo or Node.js older than 20.
The repo's own SETUP.md covers the same ground in more depth, written for people who've never set up a web server before, plus an Apache-specific walkthrough.