Creating & posting records works. Also messed up newlines but will fix later.

This commit is contained in:
lewis
2025-12-14 23:55:04 +02:00
parent 86db6617af
commit c6f9062979
227 changed files with 2122 additions and 7842 deletions
-78
View File
@@ -1,85 +1,60 @@
# BSPDS Production Installation on Alpine Linux
> **Warning**: These instructions are untested and theoretical, written from the top of Lewis' head. They may contain errors or omissions. This warning will be removed once the guide has been verified.
This guide covers installing BSPDS on Alpine Linux 3.23 (current stable as of December 2025).
## Choose Your Installation Method
| Method | Best For |
|--------|----------|
| **Native (this guide)** | Maximum performance, minimal footprint, full control |
| **[Containerized](install-containers.md)** | Easier updates, isolation, reproducible deployments |
| **[Kubernetes](install-kubernetes.md)** | Multi-node, high availability, auto-scaling |
This guide covers native installation. For containerized deployment with podman and systemd quadlets, see the [container guide](install-containers.md).
---
## Prerequisites
- A VPS with at least 2GB RAM and 20GB disk
- A domain name pointing to your server's IP
- Root access
## 1. System Setup
```sh
apk update && apk upgrade
apk add curl git build-base openssl-dev pkgconf
```
## 2. Install Rust
```sh
apk add rustup
rustup-init -y
source ~/.cargo/env
rustup default stable
```
This installs the latest stable Rust (1.92+ as of December 2025). Alpine 3.23 also ships Rust 1.91 via `apk add rust cargo` if you prefer system packages.
## 3. Install postgres
Alpine 3.23 includes PostgreSQL 18:
```sh
apk add postgresql postgresql-contrib
rc-update add postgresql
/etc/init.d/postgresql setup
rc-service postgresql start
psql -U postgres -c "CREATE USER bspds WITH PASSWORD 'your-secure-password';"
psql -U postgres -c "CREATE DATABASE pds OWNER bspds;"
psql -U postgres -c "GRANT ALL PRIVILEGES ON DATABASE pds TO bspds;"
```
## 4. Install minio
```sh
curl -O https://dl.min.io/server/minio/release/linux-amd64/minio
chmod +x minio
mv minio /usr/local/bin/
mkdir -p /var/lib/minio/data
adduser -D -H -s /sbin/nologin minio-user
chown -R minio-user:minio-user /var/lib/minio
cat > /etc/conf.d/minio << 'EOF'
MINIO_ROOT_USER="minioadmin"
MINIO_ROOT_PASSWORD="your-minio-password"
MINIO_VOLUMES="/var/lib/minio/data"
MINIO_OPTS="--console-address :9001"
EOF
cat > /etc/init.d/minio << 'EOF'
#!/sbin/openrc-run
name="minio"
description="MinIO Object Storage"
command="/usr/local/bin/minio"
command_args="server ${MINIO_VOLUMES} ${MINIO_OPTS}"
command_user="minio-user"
@@ -87,116 +62,85 @@ command_background=true
pidfile="/run/${RC_SVCNAME}.pid"
output_log="/var/log/minio.log"
error_log="/var/log/minio.log"
depend() {
need net
}
start_pre() {
. /etc/conf.d/minio
export MINIO_ROOT_USER MINIO_ROOT_PASSWORD
}
EOF
chmod +x /etc/init.d/minio
rc-update add minio
rc-service minio start
```
Create the blob bucket (wait a few seconds for minio to start):
```sh
curl -O https://dl.min.io/client/mc/release/linux-amd64/mc
chmod +x mc
mv mc /usr/local/bin/
mc alias set local http://localhost:9000 minioadmin your-minio-password
mc mb local/pds-blobs
```
## 5. Install valkey
Alpine 3.23 includes Valkey 9:
```sh
apk add valkey
rc-update add valkey
rc-service valkey start
```
## 6. Install deno (for frontend build)
```sh
curl -fsSL https://deno.land/install.sh | sh
export PATH="$HOME/.deno/bin:$PATH"
echo 'export PATH="$HOME/.deno/bin:$PATH"' >> ~/.profile
```
## 7. Clone and Build BSPDS
```sh
mkdir -p /opt && cd /opt
git clone https://tangled.org/lewis.moe/bspds-sandbox bspds
cd bspds
cd frontend
deno task build
cd ..
cargo build --release
```
## 8. Install sqlx-cli and Run Migrations
```sh
cargo install sqlx-cli --no-default-features --features postgres
export DATABASE_URL="postgres://bspds:your-secure-password@localhost:5432/pds"
sqlx migrate run
```
## 9. Configure BSPDS
```sh
mkdir -p /etc/bspds
cp /opt/bspds/.env.example /etc/bspds/bspds.env
chmod 600 /etc/bspds/bspds.env
```
Edit `/etc/bspds/bspds.env` and fill in your values. Generate secrets with:
```sh
openssl rand -base64 48
```
## 10. Create OpenRC Service
```sh
adduser -D -H -s /sbin/nologin bspds
cp /opt/bspds/target/release/bspds /usr/local/bin/
mkdir -p /var/lib/bspds
cp -r /opt/bspds/frontend/dist /var/lib/bspds/frontend
chown -R bspds:bspds /var/lib/bspds
cat > /etc/init.d/bspds << 'EOF'
#!/sbin/openrc-run
name="bspds"
description="BSPDS - AT Protocol PDS"
command="/usr/local/bin/bspds"
command_user="bspds"
command_background=true
pidfile="/run/${RC_SVCNAME}.pid"
output_log="/var/log/bspds.log"
error_log="/var/log/bspds.log"
depend() {
need net postgresql minio
}
start_pre() {
export FRONTEND_DIR=/var/lib/bspds/frontend
. /etc/bspds/bspds.env
@@ -205,25 +149,19 @@ start_pre() {
export VALKEY_URL JWT_SECRET DPOP_SECRET MASTER_KEY APPVIEW_URL CRAWLERS
}
EOF
chmod +x /etc/init.d/bspds
rc-update add bspds
rc-service bspds start
```
## 11. Install and Configure nginx
Alpine 3.23 includes nginx 1.28:
```sh
apk add nginx certbot certbot-nginx
cat > /etc/nginx/http.d/bspds.conf << 'EOF'
server {
listen 80;
listen [::]:80;
server_name pds.example.com;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
@@ -237,63 +175,48 @@ server {
}
}
EOF
rc-update add nginx
rc-service nginx start
```
## 12. Obtain SSL Certificate
```sh
certbot --nginx -d pds.example.com
```
Set up auto-renewal:
```sh
echo "0 0 * * * certbot renew --quiet" | crontab -
```
## 13. Configure Firewall
```sh
apk add iptables ip6tables
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -P INPUT DROP
ip6tables -A INPUT -p tcp --dport 22 -j ACCEPT
ip6tables -A INPUT -p tcp --dport 80 -j ACCEPT
ip6tables -A INPUT -p tcp --dport 443 -j ACCEPT
ip6tables -A INPUT -i lo -j ACCEPT
ip6tables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
ip6tables -P INPUT DROP
rc-update add iptables
rc-update add ip6tables
/etc/init.d/iptables save
/etc/init.d/ip6tables save
```
## 14. Verify Installation
```sh
rc-service bspds status
curl -s https://pds.example.com/xrpc/_health
curl -s https://pds.example.com/.well-known/atproto-did
```
## Maintenance
View logs:
```sh
tail -f /var/log/bspds.log
```
Update BSPDS:
```sh
cd /opt/bspds
@@ -306,7 +229,6 @@ cp -r frontend/dist /var/lib/bspds/frontend
DATABASE_URL="postgres://bspds:your-secure-password@localhost:5432/pds" sqlx migrate run
rc-service bspds start
```
Backup database:
```sh
pg_dump -U postgres pds > /var/backups/pds-$(date +%Y%m%d).sql
-120
View File
@@ -1,164 +1,113 @@
# BSPDS Containerized Production Deployment
> **Warning**: These instructions are untested and theoretical, written from the top of Lewis' head. They may contain errors or omissions. This warning will be removed once the guide has been verified.
This guide covers deploying BSPDS using containers with podman.
- **Debian 13+**: Uses systemd quadlets (modern, declarative container management)
- **Alpine 3.23+**: Uses OpenRC service script with podman-compose
## Prerequisites
- A VPS with at least 2GB RAM and 20GB disk
- A domain name pointing to your server's IP
- Root or sudo access
## Quick Start (Docker/Podman Compose)
If you just want to get running quickly:
```sh
cp .env.example .env
# Edit .env with your values
# Generate secrets: openssl rand -base64 48
# Build and start
podman-compose -f docker-compose.prod.yml up -d
# Get initial certificate (after DNS is configured)
podman-compose -f docker-compose.prod.yml run --rm certbot certonly \
--webroot -w /var/www/acme -d pds.example.com
# Restart nginx to load certificate
podman-compose -f docker-compose.prod.yml restart nginx
```
For production setups with proper service management, continue to either the Debian or Alpine section below.
---
# Debian 13+ with Systemd Quadlets
Quadlets are the modern way to run podman containers under systemd.
## 1. Install Podman
```bash
apt update
apt install -y podman
```
## 2. Create Directory Structure
```bash
mkdir -p /etc/containers/systemd
mkdir -p /srv/bspds/{postgres,minio,valkey,certs,acme,config}
```
## 3. Create Environment File
```bash
cp /opt/bspds/.env.example /srv/bspds/config/bspds.env
chmod 600 /srv/bspds/config/bspds.env
```
Edit `/srv/bspds/config/bspds.env` and fill in your values. Generate secrets with:
```bash
openssl rand -base64 48
```
For quadlets, also add `DATABASE_URL` with the full connection string (systemd doesn't support variable expansion).
## 4. Install Quadlet Definitions
Copy the quadlet files from the repository:
```bash
cp /opt/bspds/deploy/quadlets/*.pod /etc/containers/systemd/
cp /opt/bspds/deploy/quadlets/*.container /etc/containers/systemd/
```
Note: Systemd doesn't support shell-style variable expansion in `Environment=` lines. The quadlet files expect DATABASE_URL to be set in the environment file.
## 5. Create nginx Configuration
```bash
cp /opt/bspds/deploy/nginx/nginx-quadlet.conf /srv/bspds/config/nginx.conf
```
## 6. Build BSPDS Image
```bash
cd /opt
git clone https://tangled.org/lewis.moe/bspds-sandbox bspds
cd bspds
podman build -t bspds:latest .
```
## 7. Create Podman Secrets
```bash
source /srv/bspds/config/bspds.env
echo "$DB_PASSWORD" | podman secret create bspds-db-password -
echo "$MINIO_ROOT_PASSWORD" | podman secret create bspds-minio-password -
```
## 8. Start Services and Initialize
```bash
systemctl daemon-reload
systemctl start bspds-db bspds-minio bspds-valkey
sleep 10
# Create MinIO bucket
podman run --rm --pod bspds \
-e MINIO_ROOT_USER=minioadmin \
-e MINIO_ROOT_PASSWORD=your-minio-password \
docker.io/minio/mc:RELEASE.2025-07-16T15-35-03Z \
sh -c "mc alias set local http://localhost:9000 \$MINIO_ROOT_USER \$MINIO_ROOT_PASSWORD && mc mb --ignore-existing local/pds-blobs"
# Run migrations
cargo install sqlx-cli --no-default-features --features postgres
DATABASE_URL="postgres://bspds:your-db-password@localhost:5432/pds" sqlx migrate run --source /opt/bspds/migrations
```
## 9. Obtain SSL Certificate
Create temporary self-signed cert:
```bash
openssl req -x509 -nodes -days 1 -newkey rsa:2048 \
-keyout /srv/bspds/certs/privkey.pem \
-out /srv/bspds/certs/fullchain.pem \
-subj "/CN=pds.example.com"
systemctl start bspds-app bspds-nginx
# Get real certificate
podman run --rm \
-v /srv/bspds/certs:/etc/letsencrypt:Z \
-v /srv/bspds/acme:/var/www/acme:Z \
docker.io/certbot/certbot:v5.2.2 certonly \
--webroot -w /var/www/acme -d pds.example.com --agree-tos --email you@example.com
# Link certificates
ln -sf /srv/bspds/certs/live/pds.example.com/fullchain.pem /srv/bspds/certs/fullchain.pem
ln -sf /srv/bspds/certs/live/pds.example.com/privkey.pem /srv/bspds/certs/privkey.pem
systemctl restart bspds-nginx
```
## 10. Enable All Services
```bash
systemctl enable bspds-db bspds-minio bspds-valkey bspds-app bspds-nginx
```
## 11. Configure Firewall
```bash
apt install -y ufw
ufw allow ssh
@@ -166,109 +115,78 @@ ufw allow 80/tcp
ufw allow 443/tcp
ufw enable
```
## 12. Certificate Renewal
Add to root's crontab (`crontab -e`):
```
0 0 * * * podman run --rm -v /srv/bspds/certs:/etc/letsencrypt:Z -v /srv/bspds/acme:/var/www/acme:Z docker.io/certbot/certbot:v5.2.2 renew --quiet && systemctl reload bspds-nginx
```
---
# Alpine 3.23+ with OpenRC
Alpine uses OpenRC, not systemd. We'll use podman-compose with an OpenRC service wrapper.
## 1. Install Podman
```sh
apk update
apk add podman podman-compose fuse-overlayfs cni-plugins
rc-update add cgroups
rc-service cgroups start
```
Enable podman socket for compose:
```sh
rc-update add podman
rc-service podman start
```
## 2. Create Directory Structure
```sh
mkdir -p /srv/bspds/{data,config}
mkdir -p /srv/bspds/data/{postgres,minio,valkey,certs,acme}
```
## 3. Clone Repository and Build
```sh
cd /opt
git clone https://tangled.org/lewis.moe/bspds-sandbox bspds
cd bspds
podman build -t bspds:latest .
```
## 4. Create Environment File
```sh
cp /opt/bspds/.env.example /srv/bspds/config/bspds.env
chmod 600 /srv/bspds/config/bspds.env
```
Edit `/srv/bspds/config/bspds.env` and fill in your values. Generate secrets with:
```sh
openssl rand -base64 48
```
## 5. Set Up Compose and nginx
Copy the production compose and nginx configs:
```sh
cp /opt/bspds/docker-compose.prod.yml /srv/bspds/docker-compose.yml
cp /opt/bspds/nginx.prod.conf /srv/bspds/config/nginx.conf
```
Edit `/srv/bspds/docker-compose.yml` to adjust paths if needed:
- Update volume mounts to use `/srv/bspds/data/` paths
- Update nginx cert paths to match `/srv/bspds/data/certs/`
Edit `/srv/bspds/config/nginx.conf` to update cert paths:
- Change `/etc/nginx/certs/live/${PDS_HOSTNAME}/` to `/etc/nginx/certs/`
## 6. Create OpenRC Service
```sh
cat > /etc/init.d/bspds << 'EOF'
#!/sbin/openrc-run
name="bspds"
description="BSPDS AT Protocol PDS (containerized)"
command="/usr/bin/podman-compose"
command_args="-f /srv/bspds/docker-compose.yml up"
command_background=true
pidfile="/run/${RC_SVCNAME}.pid"
directory="/srv/bspds"
depend() {
need net podman
after firewall
}
start_pre() {
set -a
. /srv/bspds/config/bspds.env
set +a
}
stop() {
ebegin "Stopping ${name}"
cd /srv/bspds
@@ -279,18 +197,13 @@ stop() {
eend $?
}
EOF
chmod +x /etc/init.d/bspds
```
## 7. Initialize Services
```sh
# Start services
rc-service bspds start
sleep 15
# Create MinIO bucket
source /srv/bspds/config/bspds.env
podman run --rm --network bspds_default \
@@ -298,30 +211,23 @@ podman run --rm --network bspds_default \
-e MINIO_ROOT_PASSWORD="$MINIO_ROOT_PASSWORD" \
docker.io/minio/mc:RELEASE.2025-07-16T15-35-03Z \
sh -c 'mc alias set local http://minio:9000 $MINIO_ROOT_USER $MINIO_ROOT_PASSWORD && mc mb --ignore-existing local/pds-blobs'
# Run migrations
apk add rustup
rustup-init -y
source ~/.cargo/env
cargo install sqlx-cli --no-default-features --features postgres
# Get database container IP
DB_IP=$(podman inspect bspds-db-1 --format '{{.NetworkSettings.Networks.bspds_default.IPAddress}}')
DATABASE_URL="postgres://bspds:$DB_PASSWORD@$DB_IP:5432/pds" sqlx migrate run --source /opt/bspds/migrations
```
## 8. Obtain SSL Certificate
Create temporary self-signed cert:
```sh
openssl req -x509 -nodes -days 1 -newkey rsa:2048 \
-keyout /srv/bspds/data/certs/privkey.pem \
-out /srv/bspds/data/certs/fullchain.pem \
-subj "/CN=pds.example.com"
rc-service bspds restart
# Get real certificate
podman run --rm \
-v /srv/bspds/data/certs:/etc/letsencrypt \
@@ -329,99 +235,73 @@ podman run --rm \
--network bspds_default \
docker.io/certbot/certbot:v5.2.2 certonly \
--webroot -w /var/www/acme -d pds.example.com --agree-tos --email you@example.com
# Link certificates
ln -sf /srv/bspds/data/certs/live/pds.example.com/fullchain.pem /srv/bspds/data/certs/fullchain.pem
ln -sf /srv/bspds/data/certs/live/pds.example.com/privkey.pem /srv/bspds/data/certs/privkey.pem
rc-service bspds restart
```
## 9. Enable Service at Boot
```sh
rc-update add bspds
```
## 10. Configure Firewall
```sh
apk add iptables ip6tables
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -P INPUT DROP
ip6tables -A INPUT -p tcp --dport 22 -j ACCEPT
ip6tables -A INPUT -p tcp --dport 80 -j ACCEPT
ip6tables -A INPUT -p tcp --dport 443 -j ACCEPT
ip6tables -A INPUT -i lo -j ACCEPT
ip6tables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
ip6tables -P INPUT DROP
rc-update add iptables
rc-update add ip6tables
/etc/init.d/iptables save
/etc/init.d/ip6tables save
```
## 11. Certificate Renewal
Add to root's crontab (`crontab -e`):
```
0 0 * * * podman run --rm -v /srv/bspds/data/certs:/etc/letsencrypt -v /srv/bspds/data/acme:/var/www/acme docker.io/certbot/certbot:v5.2.2 renew --quiet && rc-service bspds restart
```
---
# Verification and Maintenance
## Verify Installation
```sh
curl -s https://pds.example.com/xrpc/_health | jq
curl -s https://pds.example.com/.well-known/atproto-did
```
## View Logs
**Debian:**
```bash
journalctl -u bspds-app -f
podman logs -f bspds-app
```
**Alpine:**
```sh
podman-compose -f /srv/bspds/docker-compose.yml logs -f
podman logs -f bspds-bspds-1
```
## Update BSPDS
```sh
cd /opt/bspds
git pull
podman build -t bspds:latest .
# Debian:
systemctl restart bspds-app
# Alpine:
rc-service bspds restart
```
## Backup Database
**Debian:**
```bash
podman exec bspds-db pg_dump -U bspds pds > /var/backups/pds-$(date +%Y%m%d).sql
```
**Alpine:**
```sh
podman exec bspds-db-1 pg_dump -U bspds pds > /var/backups/pds-$(date +%Y%m%d).sql
-70
View File
@@ -1,82 +1,58 @@
# BSPDS Production Installation on Debian
> **Warning**: These instructions are untested and theoretical, written from the top of Lewis' head. They may contain errors or omissions. This warning will be removed once the guide has been verified.
This guide covers installing BSPDS on Debian 13 "Trixie" (current stable as of December 2025).
## Choose Your Installation Method
| Method | Best For |
|--------|----------|
| **Native (this guide)** | Maximum performance, full control, simpler debugging |
| **[Containerized](install-containers.md)** | Easier updates, isolation, reproducible deployments |
| **[Kubernetes](install-kubernetes.md)** | Multi-node, high availability, auto-scaling |
This guide covers native installation. For containerized deployment with podman and systemd quadlets, see the [container guide](install-containers.md).
---
## Prerequisites
- A VPS with at least 2GB RAM and 20GB disk
- A domain name pointing to your server's IP
- Root or sudo access
## 1. System Setup
```bash
apt update && apt upgrade -y
apt install -y curl git build-essential pkg-config libssl-dev
```
## 2. Install Rust
```bash
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
source ~/.cargo/env
rustup default stable
```
This installs the latest stable Rust (1.92+ as of December 2025).
## 3. Install postgres
Debian 13 includes PostgreSQL 17:
```bash
apt install -y postgresql postgresql-contrib
systemctl enable postgresql
systemctl start postgresql
sudo -u postgres psql -c "CREATE USER bspds WITH PASSWORD 'your-secure-password';"
sudo -u postgres psql -c "CREATE DATABASE pds OWNER bspds;"
sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE pds TO bspds;"
```
## 4. Install minio
```bash
curl -O https://dl.min.io/server/minio/release/linux-amd64/minio
chmod +x minio
mv minio /usr/local/bin/
mkdir -p /var/lib/minio/data
useradd -r -s /sbin/nologin minio-user
chown -R minio-user:minio-user /var/lib/minio
cat > /etc/default/minio << 'EOF'
MINIO_ROOT_USER=minioadmin
MINIO_ROOT_PASSWORD=your-minio-password
MINIO_VOLUMES="/var/lib/minio/data"
MINIO_OPTS="--console-address :9001"
EOF
cat > /etc/systemd/system/minio.service << 'EOF'
[Unit]
Description=MinIO Object Storage
After=network.target
[Service]
User=minio-user
Group=minio-user
@@ -84,98 +60,71 @@ EnvironmentFile=/etc/default/minio
ExecStart=/usr/local/bin/minio server $MINIO_VOLUMES $MINIO_OPTS
Restart=always
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable minio
systemctl start minio
```
Create the blob bucket (wait a few seconds for minio to start):
```bash
curl -O https://dl.min.io/client/mc/release/linux-amd64/mc
chmod +x mc
mv mc /usr/local/bin/
mc alias set local http://localhost:9000 minioadmin your-minio-password
mc mb local/pds-blobs
```
## 5. Install valkey
Debian 13 includes Valkey 8:
```bash
apt install -y valkey
systemctl enable valkey-server
systemctl start valkey-server
```
## 6. Install deno (for frontend build)
```bash
curl -fsSL https://deno.land/install.sh | sh
export PATH="$HOME/.deno/bin:$PATH"
echo 'export PATH="$HOME/.deno/bin:$PATH"' >> ~/.bashrc
```
## 7. Clone and Build BSPDS
```bash
cd /opt
git clone https://tangled.org/lewis.moe/bspds-sandbox bspds
cd bspds
cd frontend
deno task build
cd ..
cargo build --release
```
## 8. Install sqlx-cli and Run Migrations
```bash
cargo install sqlx-cli --no-default-features --features postgres
export DATABASE_URL="postgres://bspds:your-secure-password@localhost:5432/pds"
sqlx migrate run
```
## 9. Configure BSPDS
```bash
mkdir -p /etc/bspds
cp /opt/bspds/.env.example /etc/bspds/bspds.env
chmod 600 /etc/bspds/bspds.env
```
Edit `/etc/bspds/bspds.env` and fill in your values. Generate secrets with:
```bash
openssl rand -base64 48
```
## 10. Create Systemd Service
```bash
useradd -r -s /sbin/nologin bspds
cp /opt/bspds/target/release/bspds /usr/local/bin/
mkdir -p /var/lib/bspds
cp -r /opt/bspds/frontend/dist /var/lib/bspds/frontend
chown -R bspds:bspds /var/lib/bspds
cat > /etc/systemd/system/bspds.service << 'EOF'
[Unit]
Description=BSPDS - AT Protocol PDS
After=network.target postgresql.service minio.service
[Service]
Type=simple
User=bspds
@@ -185,29 +134,22 @@ Environment=FRONTEND_DIR=/var/lib/bspds/frontend
ExecStart=/usr/local/bin/bspds
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable bspds
systemctl start bspds
```
## 11. Install and Configure nginx
Debian 13 includes nginx 1.26:
```bash
apt install -y nginx certbot python3-certbot-nginx
cat > /etc/nginx/sites-available/bspds << 'EOF'
server {
listen 80;
listen [::]:80;
server_name pds.example.com;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
@@ -221,23 +163,17 @@ server {
}
}
EOF
ln -s /etc/nginx/sites-available/bspds /etc/nginx/sites-enabled/
rm -f /etc/nginx/sites-enabled/default
nginx -t
systemctl reload nginx
```
## 12. Obtain SSL Certificate
```bash
certbot --nginx -d pds.example.com
```
Certbot automatically configures nginx for HTTP/2 and sets up auto-renewal.
## 13. Configure Firewall
```bash
apt install -y ufw
ufw allow ssh
@@ -245,22 +181,17 @@ ufw allow 80/tcp
ufw allow 443/tcp
ufw enable
```
## 14. Verify Installation
```bash
systemctl status bspds
curl -s https://pds.example.com/xrpc/_health | jq
curl -s https://pds.example.com/.well-known/atproto-did
```
## Maintenance
View logs:
```bash
journalctl -u bspds -f
```
Update BSPDS:
```bash
cd /opt/bspds
@@ -273,7 +204,6 @@ cp -r frontend/dist /var/lib/bspds/frontend
DATABASE_URL="postgres://bspds:your-secure-password@localhost:5432/pds" sqlx migrate run
systemctl start bspds
```
Backup database:
```bash
sudo -u postgres pg_dump pds > /var/backups/pds-$(date +%Y%m%d).sql
-97
View File
@@ -1,11 +1,7 @@
# BSPDS Production Kubernetes Deployment
> **Warning**: These instructions are untested and theoretical, written from the top of Lewis' head. They may contain errors or omissions. This warning will be removed once the guide has been verified.
This guide covers deploying BSPDS on a production multi-node Kubernetes cluster with high availability, auto-scaling, and proper secrets management.
## Architecture Overview
```
┌─────────────────────────────────────────────────┐
│ Kubernetes Cluster │
@@ -30,20 +26,15 @@ This guide covers deploying BSPDS on a production multi-node Kubernetes cluster
│ └──────────────────────────────────────┘ │
└─────────────────────────────────────────────────┘
```
## Prerequisites
- Kubernetes cluster (1.30+) with at least 3 nodes (1.34 is current stable)
- `kubectl` configured to access your cluster
- `helm` 3.x installed
- Storage class that supports `ReadWriteOnce` (for databases)
- Ingress controller installed (nginx-ingress or traefik)
- cert-manager installed for TLS certificates
### Quick Prerequisites Setup
If you need to install prerequisites:
```bash
# Install nginx-ingress (chart v4.14.1 - December 2025)
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
@@ -51,7 +42,6 @@ helm repo update
helm install ingress-nginx ingress-nginx/ingress-nginx \
--namespace ingress-nginx --create-namespace \
--version 4.14.1
# Install cert-manager (v1.19.2 - December 2025)
helm repo add jetstack https://charts.jetstack.io
helm repo update
@@ -60,20 +50,14 @@ helm install cert-manager jetstack/cert-manager \
--version v1.19.2 \
--set installCRDs=true
```
---
## 1. Create Namespace
```bash
kubectl create namespace bspds
kubectl config set-context --current --namespace=bspds
```
## 2. Create Secrets
Generate secure passwords and secrets:
```bash
# Generate secrets
DB_PASSWORD=$(openssl rand -base64 32)
@@ -81,21 +65,17 @@ MINIO_PASSWORD=$(openssl rand -base64 32)
JWT_SECRET=$(openssl rand -base64 48)
DPOP_SECRET=$(openssl rand -base64 48)
MASTER_KEY=$(openssl rand -base64 48)
# Create Kubernetes secrets
kubectl create secret generic bspds-db-credentials \
--from-literal=username=bspds \
--from-literal=password="$DB_PASSWORD"
kubectl create secret generic bspds-minio-credentials \
--from-literal=root-user=minioadmin \
--from-literal=root-password="$MINIO_PASSWORD"
kubectl create secret generic bspds-secrets \
--from-literal=jwt-secret="$JWT_SECRET" \
--from-literal=dpop-secret="$DPOP_SECRET" \
--from-literal=master-key="$MASTER_KEY"
# Save secrets locally (KEEP SECURE!)
echo "DB_PASSWORD=$DB_PASSWORD" > secrets.txt
echo "MINIO_PASSWORD=$MINIO_PASSWORD" >> secrets.txt
@@ -104,21 +84,16 @@ echo "DPOP_SECRET=$DPOP_SECRET" >> secrets.txt
echo "MASTER_KEY=$MASTER_KEY" >> secrets.txt
chmod 600 secrets.txt
```
## 3. Deploy PostgreSQL
### Option A: CloudNativePG Operator (Recommended for HA)
```bash
# Install CloudNativePG operator (v1.28.0 - December 2025)
kubectl apply --server-side -f \
https://raw.githubusercontent.com/cloudnative-pg/cloudnative-pg/release-1.28/releases/cnpg-1.28.0.yaml
# Wait for operator
kubectl wait --for=condition=available --timeout=120s \
deployment/cnpg-controller-manager -n cnpg-system
```
```bash
cat <<EOF | kubectl apply -f -
apiVersion: postgresql.cnpg.io/v1
@@ -128,23 +103,19 @@ metadata:
namespace: bspds
spec:
instances: 3
postgresql:
parameters:
max_connections: "200"
shared_buffers: "256MB"
bootstrap:
initdb:
database: pds
owner: bspds
secret:
name: bspds-db-credentials
storage:
size: 20Gi
storageClass: standard # adjust for your cluster
resources:
requests:
memory: "512Mi"
@@ -152,14 +123,11 @@ spec:
limits:
memory: "1Gi"
cpu: "1000m"
affinity:
podAntiAffinityType: required
EOF
```
### Option B: Simple StatefulSet (Single Instance)
```bash
cat <<EOF | kubectl apply -f -
apiVersion: v1
@@ -248,9 +216,7 @@ spec:
targetPort: 5432
EOF
```
## 4. Deploy MinIO
```bash
cat <<EOF | kubectl apply -f -
apiVersion: v1
@@ -349,9 +315,7 @@ spec:
name: console
EOF
```
### Initialize MinIO Bucket
```bash
kubectl run minio-init --rm -it --restart=Never \
--image=minio/mc:RELEASE.2025-07-16T15-35-03Z \
@@ -362,9 +326,7 @@ kubectl run minio-init --rm -it --restart=Never \
mc mb --ignore-existing local/pds-blobs
"
```
## 5. Deploy Valkey
```bash
cat <<EOF | kubectl apply -f -
apiVersion: v1
@@ -446,18 +408,14 @@ spec:
targetPort: 6379
EOF
```
## 6. Build and Push BSPDS Image
```bash
# Build image
cd /path/to/bspds
docker build -t your-registry.com/bspds:latest .
docker push your-registry.com/bspds:latest
```
If using a private registry, create an image pull secret:
```bash
kubectl create secret docker-registry regcred \
--docker-server=your-registry.com \
@@ -465,11 +423,8 @@ kubectl create secret docker-registry regcred \
--docker-password=your-password \
--docker-email=your-email
```
## 7. Run Database Migrations
BSPDS runs migrations automatically on startup. However, if you want to run migrations separately (recommended for zero-downtime deployments), you can use a Job:
```bash
cat <<'EOF' | kubectl apply -f -
apiVersion: batch/v1
@@ -496,14 +451,10 @@ spec:
- name: DATABASE_URL
value: "postgres://bspds:$(DB_PASSWORD)@bspds-db-rw:5432/pds"
EOF
kubectl wait --for=condition=complete --timeout=120s job/bspds-migrate
```
> **Note**: If your BSPDS image doesn't have a `--migrate-only` flag, you can skip this step. The app will run migrations on first startup. Alternatively, build a separate migration image with `sqlx-cli` installed.
## 8. Deploy BSPDS Application
```bash
cat <<EOF | kubectl apply -f -
apiVersion: v1
@@ -631,9 +582,7 @@ spec:
name: http
EOF
```
## 9. Configure Horizontal Pod Autoscaler
```bash
cat <<EOF | kubectl apply -f -
apiVersion: autoscaling/v2
@@ -680,9 +629,7 @@ spec:
selectPolicy: Max
EOF
```
## 10. Configure Pod Disruption Budget
```bash
cat <<EOF | kubectl apply -f -
apiVersion: policy/v1
@@ -697,9 +644,7 @@ spec:
app: bspds
EOF
```
## 11. Configure TLS with cert-manager
```bash
cat <<EOF | kubectl apply -f -
apiVersion: cert-manager.io/v1
@@ -718,9 +663,7 @@ spec:
class: nginx
EOF
```
## 12. Configure Ingress
```bash
cat <<EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
@@ -754,9 +697,7 @@ spec:
number: 80
EOF
```
## 13. Configure Network Policies (Optional but Recommended)
```bash
cat <<EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
@@ -817,9 +758,7 @@ spec:
port: 443
EOF
```
## 14. Deploy Prometheus Monitoring (Optional)
```bash
cat <<EOF | kubectl apply -f -
apiVersion: monitoring.coreos.com/v1
@@ -839,117 +778,81 @@ spec:
interval: 30s
EOF
```
---
## Verification
```bash
# Check all pods are running
kubectl get pods -n bspds
# Check services
kubectl get svc -n bspds
# Check ingress
kubectl get ingress -n bspds
# Check certificate
kubectl get certificate -n bspds
# Test health endpoint
curl -s https://pds.example.com/xrpc/_health | jq
# Test DID endpoint
curl -s https://pds.example.com/.well-known/atproto-did
```
---
## Maintenance
### View Logs
```bash
# All BSPDS pods
kubectl logs -l app=bspds -n bspds -f
# Specific pod
kubectl logs -f deployment/bspds -n bspds
```
### Scale Manually
```bash
kubectl scale deployment bspds --replicas=5 -n bspds
```
### Update BSPDS
```bash
# Build and push new image
docker build -t your-registry.com/bspds:v1.2.3 .
docker push your-registry.com/bspds:v1.2.3
# Update deployment
kubectl set image deployment/bspds bspds=your-registry.com/bspds:v1.2.3 -n bspds
# Watch rollout
kubectl rollout status deployment/bspds -n bspds
```
### Backup Database
```bash
# For CloudNativePG
kubectl cnpg backup bspds-db -n bspds
# For StatefulSet
kubectl exec -it bspds-db-0 -n bspds -- pg_dump -U bspds pds > backup-$(date +%Y%m%d).sql
```
### Run Migrations
If you have a migration Job defined, you can re-run it:
```bash
# Delete old job first (if exists)
kubectl delete job bspds-migrate -n bspds --ignore-not-found
# Re-apply the migration job from step 7
# Or simply restart the deployment - BSPDS runs migrations on startup
kubectl rollout restart deployment/bspds -n bspds
```
---
## Troubleshooting
### Pod Won't Start
```bash
kubectl describe pod -l app=bspds -n bspds
kubectl logs -l app=bspds -n bspds --previous
```
### Database Connection Issues
```bash
# Test connectivity from a debug pod
kubectl run debug --rm -it --restart=Never --image=postgres:18-alpine -- \
psql "postgres://bspds:PASSWORD@bspds-db-rw:5432/pds" -c "SELECT 1"
```
### Certificate Issues
```bash
kubectl describe certificate bspds-tls -n bspds
kubectl describe certificaterequest -n bspds
kubectl logs -l app.kubernetes.io/name=cert-manager -n cert-manager
```
### View Resource Usage
```bash
kubectl top pods -n bspds
kubectl top nodes
-96
View File
@@ -1,196 +1,136 @@
# BSPDS Production Installation on OpenBSD
> **Warning**: These instructions are untested and theoretical, written from the top of Lewis' head. They may contain errors or omissions. This warning will be removed once the guide has been verified.
This guide covers installing BSPDS on OpenBSD 7.8 (current release as of December 2025).
## Prerequisites
- A VPS with at least 2GB RAM and 20GB disk
- A domain name pointing to your server's IP
- Root access (or doas configured)
## Why nginx over relayd?
OpenBSD's native `relayd` supports WebSockets but does **not** support HTTP/2. For a modern PDS deployment, we recommend nginx which provides HTTP/2, WebSocket support, and automatic OCSP stapling.
## 1. System Setup
```sh
pkg_add curl git
```
## 2. Install Rust
```sh
pkg_add rust
```
OpenBSD 7.8 ships Rust 1.82+. For the latest stable (1.92+), use rustup:
```sh
pkg_add rustup
rustup-init -y
source ~/.cargo/env
rustup default stable
```
## 3. Install postgres
OpenBSD 7.8 includes PostgreSQL 17 (PostgreSQL 18 may not yet be in ports):
```sh
pkg_add postgresql-server postgresql-client
mkdir -p /var/postgresql/data
chown _postgresql:_postgresql /var/postgresql/data
su - _postgresql -c "initdb -D /var/postgresql/data -U postgres -A scram-sha-256"
rcctl enable postgresql
rcctl start postgresql
psql -U postgres -c "CREATE USER bspds WITH PASSWORD 'your-secure-password';"
psql -U postgres -c "CREATE DATABASE pds OWNER bspds;"
psql -U postgres -c "GRANT ALL PRIVILEGES ON DATABASE pds TO bspds;"
```
## 4. Install minio
OpenBSD doesn't have a minio package. Options:
**Option A: Use an external S3-compatible service (recommended for production)**
aws s3, backblaze b2, or upcloud managed object storage. Skip to step 5 and configure the S3 credentials in step 9.
**Option B: Build minio from source**
```sh
pkg_add go
mkdir -p /tmp/minio-build && cd /tmp/minio-build
ftp -o minio.tar.gz https://github.com/minio/minio/archive/refs/tags/RELEASE.2025-10-15T17-29-55Z.tar.gz
tar xzf minio.tar.gz
cd minio-*
go build -o minio .
cp minio /usr/local/bin/
mkdir -p /var/minio/data
useradd -d /var/minio -s /sbin/nologin _minio
chown -R _minio:_minio /var/minio
cat > /etc/minio.conf << 'EOF'
MINIO_ROOT_USER=minioadmin
MINIO_ROOT_PASSWORD=your-minio-password
EOF
chmod 600 /etc/minio.conf
cat > /etc/rc.d/minio << 'EOF'
#!/bin/ksh
daemon="/usr/local/bin/minio"
daemon_user="_minio"
daemon_flags="server /var/minio/data --console-address :9001"
. /etc/rc.d/rc.subr
rc_pre() {
. /etc/minio.conf
export MINIO_ROOT_USER MINIO_ROOT_PASSWORD
}
rc_cmd $1
EOF
chmod +x /etc/rc.d/minio
rcctl enable minio
rcctl start minio
```
Create the blob bucket:
```sh
ftp -o /usr/local/bin/mc https://dl.min.io/client/mc/release/openbsd-amd64/mc
chmod +x /usr/local/bin/mc
mc alias set local http://localhost:9000 minioadmin your-minio-password
mc mb local/pds-blobs
```
## 5. Install redis
OpenBSD has redis in ports (valkey may not be available yet):
```sh
pkg_add redis
rcctl enable redis
rcctl start redis
```
## 6. Install deno (for frontend build)
```sh
curl -fsSL https://deno.land/install.sh | sh
export PATH="$HOME/.deno/bin:$PATH"
echo 'export PATH="$HOME/.deno/bin:$PATH"' >> ~/.profile
```
## 7. Clone and Build BSPDS
```sh
mkdir -p /opt && cd /opt
git clone https://tangled.org/lewis.moe/bspds-sandbox bspds
cd bspds
cd frontend
deno task build
cd ..
cargo build --release
```
## 8. Install sqlx-cli and Run Migrations
```sh
cargo install sqlx-cli --no-default-features --features postgres
export DATABASE_URL="postgres://bspds:your-secure-password@localhost:5432/pds"
sqlx migrate run
```
## 9. Configure BSPDS
```sh
mkdir -p /etc/bspds
cp /opt/bspds/.env.example /etc/bspds/bspds.conf
chmod 600 /etc/bspds/bspds.conf
```
Edit `/etc/bspds/bspds.conf` and fill in your values. Generate secrets with:
```sh
openssl rand -base64 48
```
## 10. Create rc.d Service
```sh
useradd -d /var/empty -s /sbin/nologin _bspds
cp /opt/bspds/target/release/bspds /usr/local/bin/
mkdir -p /var/bspds
cp -r /opt/bspds/frontend/dist /var/bspds/frontend
chown -R _bspds:_bspds /var/bspds
cat > /etc/rc.d/bspds << 'EOF'
#!/bin/ksh
daemon="/usr/local/bin/bspds"
daemon_user="_bspds"
daemon_logger="daemon.info"
. /etc/rc.d/rc.subr
rc_pre() {
export FRONTEND_DIR=/var/bspds/frontend
while IFS='=' read -r key value; do
@@ -200,56 +140,43 @@ rc_pre() {
export "$key=$value"
done < /etc/bspds/bspds.conf
}
rc_cmd $1
EOF
chmod +x /etc/rc.d/bspds
rcctl enable bspds
rcctl start bspds
```
## 11. Install and Configure nginx
```sh
pkg_add nginx
cat > /etc/nginx/nginx.conf << 'EOF'
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
server {
listen 80;
listen [::]:80;
server_name pds.example.com;
location /.well-known/acme-challenge/ {
root /var/www/acme;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name pds.example.com;
ssl_certificate /etc/ssl/pds.example.com.fullchain.pem;
ssl_certificate_key /etc/ssl/private/pds.example.com.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
@@ -264,77 +191,55 @@ http {
}
}
EOF
mkdir -p /var/www/acme
rcctl enable nginx
```
## 12. Obtain SSL Certificate with acme-client
OpenBSD's native acme-client works well:
```sh
cat >> /etc/acme-client.conf << 'EOF'
authority letsencrypt {
api url "https://acme-v02.api.letsencrypt.org/directory"
account key "/etc/acme/letsencrypt-privkey.pem"
}
domain pds.example.com {
domain key "/etc/ssl/private/pds.example.com.key"
domain full chain certificate "/etc/ssl/pds.example.com.fullchain.pem"
sign with letsencrypt
}
EOF
mkdir -p /etc/acme
rcctl start nginx
acme-client -v pds.example.com
rcctl restart nginx
```
Set up auto-renewal in root's crontab:
```sh
crontab -e
```
Add:
```
0 0 * * * acme-client pds.example.com && rcctl reload nginx
```
## 13. Configure Packet Filter (pf)
```sh
cat >> /etc/pf.conf << 'EOF'
# BSPDS rules
pass in on egress proto tcp from any to any port { 22, 80, 443 }
EOF
pfctl -f /etc/pf.conf
```
## 14. Verify Installation
```sh
rcctl check bspds
ftp -o - https://pds.example.com/xrpc/_health
ftp -o - https://pds.example.com/.well-known/atproto-did
```
## Maintenance
View logs:
```sh
tail -f /var/log/daemon
```
Update BSPDS:
```sh
cd /opt/bspds
@@ -347,7 +252,6 @@ cp -r frontend/dist /var/bspds/frontend
DATABASE_URL="postgres://bspds:your-secure-password@localhost:5432/pds" sqlx migrate run
rcctl start bspds
```
Backup database:
```sh
pg_dump -U postgres pds > /var/backups/pds-$(date +%Y%m%d).sql