- 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
159 lines
4.2 KiB
Markdown
159 lines
4.2 KiB
Markdown
# 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.
|
|
|
|
```bash
|
|
sudo apt update && sudo apt install -y nodejs npm postgresql nginx certbot python3-certbot-nginx
|
|
```
|
|
|
|
### 2. Database
|
|
|
|
```bash
|
|
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)
|
|
|
|
```bash
|
|
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`:
|
|
|
|
```ini
|
|
[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
|
|
```
|
|
|
|
```bash
|
|
sudo systemctl daemon-reload
|
|
sudo systemctl enable --now openstack-backend
|
|
curl http://localhost:3000/api/health
|
|
```
|
|
|
|
### 4. Frontend (static build via Nginx)
|
|
|
|
```bash
|
|
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`:
|
|
|
|
```nginx
|
|
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";
|
|
}
|
|
}
|
|
```
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
pg_dump "postgres://openstack:...@localhost:5432/openstack" | gzip > backup-$(date +%F).sql.gz
|
|
```
|
|
|
|
---
|
|
|
|
## Option B — Docker Compose (recommended for VPS / homelab)
|
|
|
|
Requirements: Docker Engine + Compose plugin.
|
|
|
|
```bash
|
|
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:
|
|
|
|
```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
|
|
|
|
```bash
|
|
git pull
|
|
docker compose up -d --build
|
|
```
|
|
|
|
### Backup / restore (Compose)
|
|
|
|
```bash
|
|
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
|
|
```
|