# PPI Benchmark Studio: server deployment guide

This package contains everything needed to run PPI Benchmark Studio on a Linux server, so that users can open it in a web browser. The app is a single Docker container. It serves the web interface and the API, and runs the analysis jobs. A reverse proxy (nginx, config included) adds HTTPS in front of it.

- App version 0.1.0 (analysis framework `ppi_benchmark_controls` 1.0.0)
- No database server, no user accounts and no external services. State is a SQLite file plus uploaded and result files, all stored in one Docker volume.

---

## 1. Requirements

| | Minimum | Recommended |
|---|---|---|
| OS | Any 64-bit Linux with Docker (Ubuntu 22.04/24.04, Debian 12, RHEL 9…) | |
| Docker | Docker Engine 24+ with the Compose plugin (`docker compose version`) | |
| CPU | 4 cores | 8+ cores (see sizing below) |
| RAM | 8 GB | 16 GB |
| Disk | 10 GB free | 30 GB+ if many users or long retention |
| Network (build) | Outbound HTTPS to Docker Hub, registry.npmjs.org and pypi.org | |
| Network (users) | Inbound 443 (and 80 for redirect / certificate renewal) | |

**Sizing.** Each running analysis uses `STUDIO_JOB_THREADS` CPU threads. Up to `STUDIO_MAX_CONCURRENT_JOBS` analyses run at once, and the rest wait in a queue. With the defaults (2 jobs × 4 threads), plan for about 8 cores. For reference, the bundled 64,000-pair example took about 10 minutes with the "standard" preset on 4 threads. Small datasets take seconds to minutes. The RAM figures above are estimates; watch `docker stats` during the first real jobs and adjust.

The built image is about 1.3 GB.

---

## 2. What is in this package

```
DEPLOYMENT.md                  this guide
README.md                      developer overview
Dockerfile, .dockerignore      image build (builds the web UI, then the Python app)
docker-compose.yml             for running on a single workstation (not the server)
deploy/docker-compose.server.yml   server deployment (use this)
deploy/server.env              server limits: upload size, queue, retention, presets
deploy/nginx.conf              reverse-proxy template (HTTPS, rate limit, live progress)
pyproject.toml, engine/, api/  the Python analysis engine and web API
frontend/                      web interface source (built inside Docker; includes the Help page)
examples/                      three worked examples with pre-computed results (shown in the app)
docs/PPI_Benchmark_Studio_Tutorial.docx   end-user tutorial (also available in the app under Help)
```

---

## 3. Install

### 3.1 Copy and unpack

```bash
# from your workstation
scp ppi-benchmark-studio-deploy.zip admin@SERVER:/tmp/

# on the server
sudo mkdir -p /opt/ppi-benchmark-studio
sudo unzip /tmp/ppi-benchmark-studio-deploy.zip -d /opt/
cd /opt/ppi-benchmark-studio
```

### 3.2 Review the limits

Edit `deploy/server.env` before the first start:

| Variable | Default | Meaning |
|---|---|---|
| `STUDIO_MAX_UPLOAD_MB` | 50 | Largest single uploaded file (MB) |
| `STUDIO_MAX_PAIRS` | 250000 | Largest pair file accepted |
| `STUDIO_MAX_CONCURRENT_JOBS` | 2 | Analyses running at the same time (worker processes) |
| `STUDIO_MAX_QUEUED_JOBS` | 20 | Queue length; further submissions are refused (HTTP 429) |
| `STUDIO_JOB_THREADS` | 4 | CPU threads per analysis |
| `STUDIO_RETENTION_DAYS` | 7 | Uploads and results are deleted automatically after this many days |
| `STUDIO_PRESETS` | quick,standard,full | Analysis presets offered to users ("full" is the slowest) |

If you raise `STUDIO_MAX_UPLOAD_MB`, also raise `client_max_body_size` in the nginx config (about 3 × the upload limit, plus headroom).

> **Retention note.** The user tutorial and the Help page were written on a test machine where files were kept for 30 days, so they say "30 days". The Evaluate page always shows the real value from `STUDIO_RETENTION_DAYS`. Set it to 30 if you want the documentation to match exactly.

### 3.3 Build and start

```bash
cd /opt/ppi-benchmark-studio
sudo docker compose -f deploy/docker-compose.server.yml up -d --build
```

The first build takes a few minutes. Check that it is running:

```bash
sudo docker compose -f deploy/docker-compose.server.yml ps        # STATUS should become "healthy"
curl -s http://127.0.0.1:8000/api/health
# {"status":"ok","engine_version":"0.1.0","framework_version":"1.0.0"}
```

The container listens on **127.0.0.1:8000 only**, so it cannot be reached from outside the machine directly. Users reach it through nginx (next step). It restarts automatically after a crash or a reboot (`restart: unless-stopped`), provided the Docker service is enabled (`sudo systemctl enable docker`).

> If port 8000 is already used on the server, change the first `8000` in `ports: ["127.0.0.1:8000:8000"]` in `deploy/docker-compose.server.yml`, and the `proxy_pass` lines in the nginx config to match.

---

## 4. Put nginx with HTTPS in front

1. Install nginx (`sudo apt install nginx`) and obtain a certificate, for example with certbot (`sudo apt install certbot python3-certbot-nginx`).
2. Add the rate-limit zone inside the `http { }` block of `/etc/nginx/nginx.conf`:
   ```nginx
   limit_req_zone $binary_remote_addr zone=studio:10m rate=10r/s;
   ```
3. Copy the site config and set your host name:
   ```bash
   sudo cp deploy/nginx.conf /etc/nginx/sites-available/ppi-studio
   sudo sed -i 's/studio.example.org/YOUR.HOST.NAME/' /etc/nginx/sites-available/ppi-studio
   sudo ln -s /etc/nginx/sites-available/ppi-studio /etc/nginx/sites-enabled/
   sudo nginx -t && sudo systemctl reload nginx
   sudo certbot --nginx -d YOUR.HOST.NAME        # adds the HTTPS (443) server block and redirect
   ```
4. Open the firewall for web traffic only, for example `sudo ufw allow 'Nginx Full'`. Do **not** open port 8000.

Keep the special `location /api/jobs/` block. It turns off buffering so the progress page updates live. Without it, progress appears only at the end.

---

## 5. Check the installation (5 minutes)

Open `https://YOUR.HOST.NAME` in a browser and check:

1. The home page loads, and the menu shows **Framework · Format · Examples · Evaluate · Help**.
2. **Help** opens the searchable user guide. Type "upload" in the search box; matching passages appear with pictures.
3. **Examples ▸ Multi-species benchmark** shows complete results with charts.
4. **Evaluate ▸ Use synthetic data ▸ Validate ▸ Continue ▸ Run evaluation** (Quick preset). The progress page moves through its stages live, and results appear within about a minute.
5. On the results page, **Use the results ▸ Full bundle (.zip)** downloads a file.

If step 4 waits on "Waiting for a free worker" forever, or progress only jumps at the end, check the nginx `/api/jobs/` block (section 4).

---

## 6. Operating the service

All commands are run from `/opt/ppi-benchmark-studio`. `C="sudo docker compose -f deploy/docker-compose.server.yml"` shortens them.

| Task | Command |
|---|---|
| Status / health | `$C ps` |
| Live logs | `$C logs -f --tail 200` |
| Stop | `$C stop` |
| Start | `$C start` |
| Restart (for example after editing `server.env`) | `$C up -d` (recreates the container with the new settings) |
| Resource use | `sudo docker stats` |

**Data.** Uploads, results and the job database live in the Docker volume `ppi-studio_studio-data` (mounted at `/data` in the container). Expired data is deleted automatically every hour according to `STUDIO_RETENTION_DAYS`.

**Never run `$C down -v`.** The `-v` option deletes the data volume, including all users' results. Plain `$C down` is safe.

**Backup** (optional, since results are temporary by design):

```bash
sudo docker run --rm -v ppi-studio_studio-data:/data -v "$PWD":/backup alpine \
  tar czf /backup/studio-data-$(date +%F).tgz -C /data .
```

### Updating to a new version

```bash
cd /opt
sudo cp -a ppi-benchmark-studio/deploy/server.env /tmp/server.env.keep     # keep your settings
sudo unzip -o /tmp/ppi-benchmark-studio-deploy-NEW.zip -d /opt/
sudo cp /tmp/server.env.keep ppi-benchmark-studio/deploy/server.env
cd ppi-benchmark-studio && sudo docker compose -f deploy/docker-compose.server.yml up -d --build
```

The data volume is kept. Jobs that are running during the update are interrupted, so update when the queue is empty (check the logs).

---

## 7. Security and privacy (please read)

- **There are no user accounts.** Every dataset and result has a long random ID in its address (for example `/jobs/b2b8dd25…`). **Anyone who has a result link can open it.** The app tells users this on the Evaluate page.
- If people will upload unpublished or sensitive data, restrict who can reach the site at all. For example: only on the institutional network or VPN, an nginx `allow`/`deny` IP list, or nginx basic authentication (`auth_basic`) or your single sign-on proxy in front of it.
- Uploaded files are stored only for the retention period and are then deleted automatically.
- The container runs as an unprivileged user (uid 1000), and the app port is bound to localhost only.
- Rate limiting (10 requests/s per IP, burst 40) and the upload size limit are enforced in nginx. The queue limit is enforced by the app.

---

## 8. Troubleshooting

| Symptom | Check / fix |
|---|---|
| `bind: address already in use` on start | Something else uses port 8000. Stop it, or change the port (section 3.3). |
| Build fails while downloading | The server has no outbound internet. Use the offline install (section 9). |
| 502 Bad Gateway from nginx | The container is not running or not healthy: `$C ps`, `$C logs`. |
| "413 Request Entity Too Large" on upload | Raise `client_max_body_size` in nginx (and `STUDIO_MAX_UPLOAD_MB` if needed). |
| Users get "queue is full" (HTTP 429) | Raise `STUDIO_MAX_QUEUED_JOBS`, or add CPU and raise `STUDIO_MAX_CONCURRENT_JOBS`, then `$C up -d`. |
| Progress page does not update live | The nginx `/api/jobs/` block is missing or `proxy_buffering` is on. |
| Help page pictures missing | Make sure the image was rebuilt from this package (`$C up -d --build`). |
| Disk filling up | Lower `STUDIO_RETENTION_DAYS`, or `STUDIO_MAX_UPLOAD_MB`. |

---

## 9. Offline install (server without internet)

On a machine **with** internet and Docker, in the unpacked package folder:

```bash
docker compose -f deploy/docker-compose.server.yml build
docker save ppi-benchmark-studio:0.1.0 | gzip > ppi-benchmark-studio-0.1.0.tar.gz
```

Copy the `.tar.gz` and the unpacked package folder to the server, then:

```bash
sudo docker load < ppi-benchmark-studio-0.1.0.tar.gz
cd /opt/ppi-benchmark-studio
sudo docker compose -f deploy/docker-compose.server.yml up -d      # no --build
```

---

## 10. Where to send users

Give users the site address. Inside the app, the **Help** menu item contains the complete user guide, with search and pictures. The same guide is available as a Word file in `docs/PPI_Benchmark_Studio_Tutorial.docx`, and from the Help page.
