Files
x3 663f7c16cc
ci / backend (push) Canceled after 0s
ci / frontend (push) Canceled after 0s
feat: first-run web installer with admin account creation
- Backend: app_settings table + users.is_admin flag (schema + migrate)
- POST /api/setup creates admin user, first workspace and marks installed
  (transactional, single-use, rate-limited); GET /api/setup/status
- Guard middleware: API answers 503 { setupRequired: true } until installed
- Frontend: /setup wizard (welcome, admin account, workspace), router guard
  redirects to installer when uninstalled, API interceptor handles 503
- Docs: installer covered in README, SETUP, HOSTING and ROADMAP
2026-09-22 13:39:33 +02:00

4.2 KiB

Hosting

Two supported ways to host: A) bare-metal (systemd + Nginx) and B) Docker Compose. Both need PostgreSQL and a JWT_SECRET.

Option A — Bare-metal (Node.js + Nginx + PostgreSQL)

1. Provision

  • Server with Ubuntu 22.04+/Debian 12+, Node.js 20, PostgreSQL 14+, Nginx, Certbot.
  • DNS openstack.example.com pointing at the server.
sudo apt update && sudo apt install -y nodejs npm postgresql nginx certbot python3-certbot-nginx

2. Database

sudo -u postgres psql -c "CREATE USER openstack WITH PASSWORD 'strong-password';"
sudo -u postgres psql -c "CREATE DATABASE openstack OWNER openstack;"
psql "postgres://openstack:strong-password@localhost:5432/openstack" < backend/src/db/schema.sql

3. Backend (systemd)

git clone https://git.sysdaemon.xyz/x3/openStack.git /opt/openStack
cd /opt/openStack/backend && npm ci --omit=dev
cat > /opt/openStack/backend/.env <<EOF
DATABASE_URL=postgres://openstack:openstackpw@localhost:5432/openstack
PORT=3000
JWT_SECRET=$(openssl rand -hex 32)
JWT_EXPIRES_IN=7d
CORS_ORIGIN=https://openstack.example.com
EOF
npm run migrate

/etc/systemd/system/openstack-backend.service:

[Unit]
Description=openStack Backend
After=network.target postgresql.service

[Service]
WorkingDirectory=/opt/openStack/backend
EnvironmentFile=/opt/openStack/backend/.env
ExecStart=/usr/bin/node src/index.js
Restart=always
User=www-data

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now openstack-backend
curl http://localhost:3000/api/health

4. Frontend (static build via Nginx)

cd /opt/openStack/frontend
npm ci && VITE_API_URL=https://openstack.example.com/api VITE_SOCKET_URL=https://openstack.example.com npm run build
sudo mkdir -p /var/www/openstack && sudo cp -r dist/* /var/www/openstack/

/etc/nginx/sites-available/notes:

server {
  listen 80;
  server_name openstack.example.com;
  root /var/www/openstack;
  index index.html;

  location / { try_files $uri $uri/ /index.html; }

  location /api/ { proxy_pass http://127.0.0.1:3000; }
  location /socket.io/ {
    proxy_pass http://127.0.0.1:3000;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
  }
}
sudo ln -s /etc/nginx/sites-available/notes /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
sudo certbot --nginx -d openstack.example.com

5. Backups

pg_dump "postgres://openstack:...@localhost:5432/openstack" | gzip > backup-$(date +%F).sql.gz

Requirements: Docker Engine + Compose plugin.

git clone https://git.sysdaemon.xyz/x3/openStack.git
cd openStack
cp .env.example .env
# IMPORTANT: set POSTGRES_PASSWORD and JWT_SECRET to strong values
nano .env
docker compose up -d --build
docker compose logs -f backend
curl http://localhost:3000/api/health
  • Frontend: http://<host>:8080
  • Backend API: http://<host>:3000/api/health
  • Data persists in the pgdata volume.
  • On first start, open the frontend and complete the web installer (admin account + first workspace). Until then the API answers 503 { setupRequired: true } for all app routes.

Reverse proxy (TLS) in front of Compose

Point Nginx/Caddy at localhost:8080 (frontend) and let the frontend's relative /api calls work — the frontend image is built with VITE_API_URL=/api, so no CORS is needed when served behind one domain. Example Caddy:

openstack.example.com {
  reverse_proxy localhost:8080
}

But note: Socket.IO also needs websocket upgrade; the bundled nginx.conf serves only static files. For single-domain production, proxy /api + /socket.io to the backend (see Option A Nginx snippet) and serve the built frontend/dist statically, or extend frontend/nginx.conf with upstream proxy blocks.

Updates

git pull
docker compose up -d --build

Backup / restore (Compose)

docker compose exec postgres pg_dump -U openstack openstack | gzip > backup.sql.gz
gunzip -c backup.sql.gz | docker compose exec -T postgres psql -U openstack openstack