glam/docs/DEPLOYMENT_GUIDE.md
2025-12-01 16:06:34 +01:00

450 lines
9.9 KiB
Markdown

# GLAM Deployment Guide
Complete guide for deploying the GLAM (Galleries, Libraries, Archives, Museums) ontology project.
## Overview
This project uses a **local deployment model** - all deployments are executed from your local machine via SSH and rsync. There is **NO CI/CD pipeline** or GitHub Actions.
**Why Local Deployment?**
- Full control over what gets deployed
- No exposure of secrets to third-party CI systems
- Immediate feedback during deployment
- Easy debugging and rollback
## Infrastructure
### Server Details
| Property | Value |
|----------|-------|
| **Provider** | Hetzner Cloud |
| **Server Name** | `glam-sparql` |
| **IP Address** | `91.98.224.44` |
| **SSH User** | `root` |
| **Frontend Path** | `/var/www/glam-frontend/` |
| **Data Path** | `/mnt/data/` |
| **Oxigraph Data** | `/var/lib/oxigraph/` |
### Services Running on Server
| Service | Port | Description |
|---------|------|-------------|
| **Caddy** | 80, 443 | Reverse proxy with automatic HTTPS |
| **Oxigraph** | 7878 | SPARQL triplestore (internal only) |
| **Frontend** | - | Static files served by Caddy |
---
## Prerequisites
### 1. Environment Variables
Create a `.env` file in the project root:
```bash
# Required for deployment
HETZNER_HC_API_TOKEN=your_hetzner_cloud_api_token
# Optional - defaults shown
GLAM_DOMAIN=sparql.glam-ontology.org
ADMIN_EMAIL=admin@glam-ontology.org
```
**Getting your Hetzner API Token:**
1. Log in to [Hetzner Cloud Console](https://console.hetzner.cloud/)
2. Select your project
3. Go to Security > API Tokens
4. Create a new token with Read & Write permissions
5. Copy the token to your `.env` file
### 2. SSH Access
Ensure you can SSH to the server:
```bash
# Test SSH connection
ssh root@91.98.224.44 "echo 'Connection successful'"
```
If this fails:
- Check that your SSH key is added to the server's `~/.ssh/authorized_keys`
- Verify the server is running (`./infrastructure/deploy.sh --status`)
### 3. Local Dependencies
For frontend deployment:
```bash
# Ensure Node.js is installed (v18+)
node --version
# Ensure npm is installed
npm --version
```
For infrastructure changes:
```bash
# Ensure Terraform is installed
terraform --version
# Ensure jq is installed (for JSON parsing)
jq --version
```
---
## Deployment Script
All deployments use the script at `infrastructure/deploy.sh`.
### Command Options
| Option | Description |
|--------|-------------|
| `--frontend` | Build and deploy React frontend |
| `--data` | Deploy ontology/schema data files |
| `--infra` | Deploy infrastructure via Terraform |
| `--reload` | Reload data into Oxigraph triplestore |
| `--all` | Deploy everything |
| `--status` | Check server and service status |
### Quick Reference
```bash
# Most common - deploy frontend changes
./infrastructure/deploy.sh --frontend
# Deploy updated ontology/schema files
./infrastructure/deploy.sh --data
# Check what's running on the server
./infrastructure/deploy.sh --status
# Full deployment (rare)
./infrastructure/deploy.sh --all
```
---
## Deployment Scenarios
### Scenario 1: Frontend Changes (Most Common)
After making changes to `frontend/`:
```bash
# Option A: Use deploy script (recommended)
./infrastructure/deploy.sh --frontend
# Option B: Manual build + deploy
cd frontend
npm run build
cd ..
rsync -avz --delete frontend/dist/ root@91.98.224.44:/var/www/glam-frontend/
```
**What the script does:**
1. Runs `npm ci` to install exact dependencies
2. Runs `npm run build` to create production build
3. Syncs `frontend/dist/` to server via rsync
**Verification:**
```bash
# Check the server is serving updated content
curl -I https://91.98.224.44
```
### Scenario 2: Schema/Ontology Updates
After regenerating LinkML schemas or RDF files:
```bash
./infrastructure/deploy.sh --data
```
**What gets synced:**
- `data/ontology/*.{ttl,rdf,owl,jsonld}``/mnt/data/ontologies/`
- `schemas/20251121/rdf/``/mnt/data/rdf/`
- `schemas/20251121/linkml/*.yaml``/mnt/data/linkml/`
- `schemas/20251121/uml/mermaid/*.mmd``/mnt/data/uml/`
**To also reload into Oxigraph:**
```bash
./infrastructure/deploy.sh --data --reload
```
### Scenario 3: Infrastructure Changes
For changes to server configuration (rare):
```bash
./infrastructure/deploy.sh --infra
```
**Warning:** This will:
1. Run `terraform plan` to show changes
2. Ask for confirmation before applying
3. Potentially recreate the server (be careful!)
### Scenario 4: Check Server Status
```bash
./infrastructure/deploy.sh --status
```
**Output includes:**
- Server name, status, IP, type, location
- Oxigraph service status
- Caddy service status
- Triple count in SPARQL store
---
## Manual Deployment Steps
If the script fails or you need manual control:
### Frontend (Manual)
```bash
# 1. Build frontend
cd frontend
npm ci
npm run build
# 2. Sync schemas to frontend public directory (if needed)
mkdir -p public/schemas
cp -r ../schemas/20251121/linkml public/schemas/
cp -r ../schemas/20251121/uml public/schemas/
# 3. Deploy to server
rsync -avz --delete dist/ root@91.98.224.44:/var/www/glam-frontend/
# 4. Verify
ssh root@91.98.224.44 "ls -la /var/www/glam-frontend/"
```
### Data Files (Manual)
```bash
# Sync ontologies
rsync -avz data/ontology/*.ttl data/ontology/*.rdf data/ontology/*.owl \
root@91.98.224.44:/mnt/data/ontologies/
# Sync RDF schemas
rsync -avz schemas/20251121/rdf/ \
root@91.98.224.44:/mnt/data/rdf/
# Sync LinkML schemas
rsync -avz --include='*.yaml' --include='*/' --exclude='*' \
schemas/20251121/linkml/ \
root@91.98.224.44:/mnt/data/linkml/
```
### Reload Oxigraph (Manual)
```bash
ssh root@91.98.224.44 "/var/lib/glam/scripts/load-ontologies.sh"
```
---
## Server Management
### SSH Access
```bash
# Connect to server
ssh root@91.98.224.44
# Check disk usage
ssh root@91.98.224.44 "df -h"
# Check memory usage
ssh root@91.98.224.44 "free -h"
# View logs
ssh root@91.98.224.44 "journalctl -u caddy -n 50"
ssh root@91.98.224.44 "journalctl -u oxigraph -n 50"
```
### Service Management
```bash
# Restart Caddy (web server)
ssh root@91.98.224.44 "systemctl restart caddy"
# Restart Oxigraph (SPARQL store)
ssh root@91.98.224.44 "systemctl restart oxigraph"
# Check service status
ssh root@91.98.224.44 "systemctl status caddy"
ssh root@91.98.224.44 "systemctl status oxigraph"
```
### Caddy Configuration
Caddy config is at `/etc/caddy/Caddyfile` on the server:
```bash
# View current config
ssh root@91.98.224.44 "cat /etc/caddy/Caddyfile"
# Edit config (if needed)
ssh root@91.98.224.44 "nano /etc/caddy/Caddyfile"
# Reload after changes
ssh root@91.98.224.44 "systemctl reload caddy"
```
---
## Troubleshooting
### Common Issues
#### 1. "Permission denied" on SSH
```bash
# Check SSH key is loaded
ssh-add -l
# Add SSH key if not loaded
ssh-add ~/.ssh/id_ed25519 # or your key file
```
#### 2. "Server not found" error
```bash
# Check server exists in Hetzner
./infrastructure/deploy.sh --status
# If server doesn't exist, create with:
./infrastructure/deploy.sh --infra
```
#### 3. Frontend not updating
```bash
# Force cache clear on browser (Ctrl+Shift+R)
# Or check files were actually deployed
ssh root@91.98.224.44 "ls -la /var/www/glam-frontend/"
ssh root@91.98.224.44 "cat /var/www/glam-frontend/index.html | head -20"
```
#### 4. SPARQL queries failing
```bash
# Check Oxigraph is running
ssh root@91.98.224.44 "systemctl status oxigraph"
# Check triple count
ssh root@91.98.224.44 "curl -s -X POST \
-H 'Content-Type: application/sparql-query' \
-H 'Accept: application/sparql-results+json' \
--data 'SELECT (COUNT(*) AS ?count) WHERE { ?s ?p ?o }' \
http://localhost:7878/query | jq '.results.bindings[0].count.value'"
# Restart Oxigraph if needed
ssh root@91.98.224.44 "systemctl restart oxigraph"
```
#### 5. Hetzner API Token Invalid
```bash
# Test token manually
curl -s -H "Authorization: Bearer YOUR_TOKEN" \
"https://api.hetzner.cloud/v1/servers" | jq '.servers[].name'
```
### Log Files
```bash
# Caddy access logs
ssh root@91.98.224.44 "journalctl -u caddy --since '1 hour ago'"
# Oxigraph logs
ssh root@91.98.224.44 "journalctl -u oxigraph --since '1 hour ago'"
# System logs
ssh root@91.98.224.44 "journalctl --since '1 hour ago'"
```
---
## Security Notes
### What's Protected
- HTTPS enabled via Caddy with automatic Let's Encrypt certificates
- SSH access restricted to key-based authentication
- Oxigraph only accessible from localhost (not exposed to internet)
- Caddy reverse proxies SPARQL queries to Oxigraph
### Sensitive Files
**NEVER commit these to git:**
- `.env` - Contains Hetzner API token
- `infrastructure/terraform/terraform.tfvars` - Contains secrets
- `infrastructure/terraform/*.tfstate*` - Contains infrastructure state
These are already in `.gitignore`.
---
## Deployment Checklist
Before deploying:
- [ ] Changes tested locally
- [ ] `.env` file exists with valid `HETZNER_HC_API_TOKEN`
- [ ] SSH access verified (`ssh root@91.98.224.44`)
- [ ] For frontend: `npm run build` succeeds locally
- [ ] For schemas: LinkML validation passes
After deploying:
- [ ] `./infrastructure/deploy.sh --status` shows services running
- [ ] Frontend loads in browser
- [ ] SPARQL queries return results (if data deployed)
- [ ] No errors in server logs
---
## Quick Commands Reference
```bash
# Deploy frontend
./infrastructure/deploy.sh --frontend
# Deploy data
./infrastructure/deploy.sh --data
# Check status
./infrastructure/deploy.sh --status
# SSH to server
ssh root@91.98.224.44
# View Caddy logs
ssh root@91.98.224.44 "journalctl -u caddy -f"
# Restart services
ssh root@91.98.224.44 "systemctl restart caddy"
ssh root@91.98.224.44 "systemctl restart oxigraph"
```
---
## Related Documentation
- `.opencode/DEPLOYMENT_RULES.md` - Rules for AI agents performing deployments
- `AGENTS.md` - Rule 7 covers deployment guidelines
- `infrastructure/deploy.sh` - The deployment script source code
- `infrastructure/terraform/` - Terraform configuration for server provisioning
---
**Last Updated**: 2025-12-01
**Maintainer**: GLAM Project Team