···53| Guide | Best For |
54|-------|----------|
55| [Debian](docs/install-debian.md) | Debian 13+ with systemd |
56-| [Alpine](docs/install-alpine.md) | Alpine 3.23+ with OpenRC |
57-| [OpenBSD](docs/install-openbsd.md) | OpenBSD 7.8+ with rc.d |
58| [Containers](docs/install-containers.md) | Podman with quadlets or OpenRC |
59| [Kubernetes](docs/install-kubernetes.md) | You know what you're doing |
60
···53| Guide | Best For |
54|-------|----------|
55| [Debian](docs/install-debian.md) | Debian 13+ with systemd |
0056| [Containers](docs/install-containers.md) | Podman with quadlets or OpenRC |
57| [Kubernetes](docs/install-kubernetes.md) | You know what you're doing |
58
-265
docs/install-alpine.md
···1-# Tranquil PDS Production Installation on Alpine Linux
2-> **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.
3-4-This guide covers installing Tranquil PDS on Alpine Linux 3.23.
5-6-## Prerequisites
7-- A VPS with at least 2GB RAM and 20GB disk
8-- A domain name pointing to your server's IP
9-- A **wildcard TLS certificate** for `*.pds.example.com` (user handles are served as subdomains)
10-- Root access
11-## 1. System Setup
12-```sh
13-apk update && apk upgrade
14-apk add curl git build-base openssl-dev pkgconf
15-```
16-## 2. Install Rust
17-```sh
18-apk add rustup
19-rustup-init -y
20-source ~/.cargo/env
21-rustup default stable
22-```
23-This installs the latest stable Rust. Alpine also ships Rust via `apk add rust cargo` if you prefer system packages.
24-## 3. Install postgres
25-```sh
26-apk add postgresql postgresql-contrib
27-rc-update add postgresql
28-/etc/init.d/postgresql setup
29-rc-service postgresql start
30-psql -U postgres -c "CREATE USER tranquil_pds WITH PASSWORD 'your-secure-password';"
31-psql -U postgres -c "CREATE DATABASE pds OWNER tranquil_pds;"
32-psql -U postgres -c "GRANT ALL PRIVILEGES ON DATABASE pds TO tranquil_pds;"
33-```
34-## 4. Install minio
35-```sh
36-curl -O https://dl.min.io/server/minio/release/linux-amd64/minio
37-chmod +x minio
38-mv minio /usr/local/bin/
39-mkdir -p /var/lib/minio/data
40-adduser -D -H -s /sbin/nologin minio-user
41-chown -R minio-user:minio-user /var/lib/minio
42-cat > /etc/conf.d/minio << 'EOF'
43-MINIO_ROOT_USER="minioadmin"
44-MINIO_ROOT_PASSWORD="your-minio-password"
45-MINIO_VOLUMES="/var/lib/minio/data"
46-MINIO_OPTS="--console-address :9001"
47-EOF
48-cat > /etc/init.d/minio << 'EOF'
49-#!/sbin/openrc-run
50-name="minio"
51-description="MinIO Object Storage"
52-command="/usr/local/bin/minio"
53-command_args="server ${MINIO_VOLUMES} ${MINIO_OPTS}"
54-command_user="minio-user"
55-command_background=true
56-pidfile="/run/${RC_SVCNAME}.pid"
57-output_log="/var/log/minio.log"
58-error_log="/var/log/minio.log"
59-depend() {
60- need net
61-}
62-start_pre() {
63- . /etc/conf.d/minio
64- export MINIO_ROOT_USER MINIO_ROOT_PASSWORD
65-}
66-EOF
67-chmod +x /etc/init.d/minio
68-rc-update add minio
69-rc-service minio start
70-```
71-Create the buckets (wait a few seconds for minio to start):
72-```sh
73-curl -O https://dl.min.io/client/mc/release/linux-amd64/mc
74-chmod +x mc
75-mv mc /usr/local/bin/
76-mc alias set local http://localhost:9000 minioadmin your-minio-password
77-mc mb local/pds-blobs
78-mc mb local/pds-backups
79-```
80-## 5. Install valkey
81-```sh
82-apk add valkey
83-rc-update add valkey
84-rc-service valkey start
85-```
86-## 6. Install deno (for frontend build)
87-```sh
88-curl -fsSL https://deno.land/install.sh | sh
89-export PATH="$HOME/.deno/bin:$PATH"
90-echo 'export PATH="$HOME/.deno/bin:$PATH"' >> ~/.profile
91-```
92-## 7. Clone and Build Tranquil PDS
93-```sh
94-mkdir -p /opt && cd /opt
95-git clone https://tangled.org/lewis.moe/bspds-sandbox tranquil-pds
96-cd tranquil-pds
97-cd frontend
98-deno task build
99-cd ..
100-cargo build --release
101-```
102-## 8. Install sqlx-cli and Run Migrations
103-```sh
104-cargo install sqlx-cli --no-default-features --features postgres
105-export DATABASE_URL="postgres://tranquil_pds:your-secure-password@localhost:5432/pds"
106-sqlx migrate run
107-```
108-## 9. Configure Tranquil PDS
109-```sh
110-mkdir -p /etc/tranquil-pds
111-cp /opt/tranquil-pds/.env.example /etc/tranquil-pds/tranquil-pds.env
112-chmod 600 /etc/tranquil-pds/tranquil-pds.env
113-```
114-Edit `/etc/tranquil-pds/tranquil-pds.env` and fill in your values. Generate secrets with:
115-```sh
116-openssl rand -base64 48
117-```
118-## 10. Create OpenRC Service
119-```sh
120-adduser -D -H -s /sbin/nologin tranquil-pds
121-cp /opt/tranquil-pds/target/release/tranquil-pds /usr/local/bin/
122-mkdir -p /var/lib/tranquil-pds
123-cp -r /opt/tranquil-pds/frontend/dist /var/lib/tranquil-pds/frontend
124-chown -R tranquil-pds:tranquil-pds /var/lib/tranquil-pds
125-cat > /etc/init.d/tranquil-pds << 'EOF'
126-#!/sbin/openrc-run
127-name="tranquil-pds"
128-description="Tranquil PDS - AT Protocol PDS"
129-command="/usr/local/bin/tranquil-pds"
130-command_user="tranquil-pds"
131-command_background=true
132-pidfile="/run/${RC_SVCNAME}.pid"
133-output_log="/var/log/tranquil-pds.log"
134-error_log="/var/log/tranquil-pds.log"
135-depend() {
136- need net postgresql minio
137-}
138-start_pre() {
139- export FRONTEND_DIR=/var/lib/tranquil-pds/frontend
140- . /etc/tranquil-pds/tranquil-pds.env
141- export SERVER_HOST SERVER_PORT PDS_HOSTNAME DATABASE_URL
142- export S3_ENDPOINT AWS_REGION S3_BUCKET AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY
143- export VALKEY_URL JWT_SECRET DPOP_SECRET MASTER_KEY CRAWLERS
144-}
145-EOF
146-chmod +x /etc/init.d/tranquil-pds
147-rc-update add tranquil-pds
148-rc-service tranquil-pds start
149-```
150-## 11. Install and Configure nginx
151-```sh
152-apk add nginx certbot certbot-nginx
153-cat > /etc/nginx/http.d/tranquil-pds.conf << 'EOF'
154-server {
155- listen 80;
156- listen [::]:80;
157- server_name pds.example.com;
158- location / {
159- proxy_pass http://127.0.0.1:3000;
160- proxy_http_version 1.1;
161- proxy_set_header Upgrade $http_upgrade;
162- proxy_set_header Connection "upgrade";
163- proxy_set_header Host $host;
164- proxy_set_header X-Real-IP $remote_addr;
165- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
166- proxy_set_header X-Forwarded-Proto $scheme;
167- proxy_read_timeout 86400;
168- }
169-}
170-EOF
171-rc-update add nginx
172-rc-service nginx start
173-```
174-## 12. Obtain Wildcard SSL Certificate
175-User handles are served as subdomains (e.g., `alice.pds.example.com`), so you need a wildcard certificate.
176-177-Wildcard certs require DNS-01 validation. For manual DNS validation (works with any provider):
178-```sh
179-certbot certonly --manual --preferred-challenges dns \
180- -d pds.example.com -d '*.pds.example.com'
181-```
182-Follow the prompts to add TXT records to your DNS.
183-184-If your DNS provider has a certbot plugin, you can use that for auto-renewal:
185-```sh
186-apk add certbot-dns-cloudflare
187-certbot certonly --dns-cloudflare \
188- --dns-cloudflare-credentials /etc/cloudflare.ini \
189- -d pds.example.com -d '*.pds.example.com'
190-```
191-192-After obtaining the cert, update nginx to use it, then set up auto-renewal:
193-```sh
194-echo "0 0 * * * certbot renew --quiet && rc-service nginx reload" | crontab -
195-```
196-## 13. Configure Firewall
197-```sh
198-apk add iptables ip6tables
199-iptables -A INPUT -p tcp --dport 22 -j ACCEPT
200-iptables -A INPUT -p tcp --dport 80 -j ACCEPT
201-iptables -A INPUT -p tcp --dport 443 -j ACCEPT
202-iptables -A INPUT -i lo -j ACCEPT
203-iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
204-iptables -P INPUT DROP
205-ip6tables -A INPUT -p tcp --dport 22 -j ACCEPT
206-ip6tables -A INPUT -p tcp --dport 80 -j ACCEPT
207-ip6tables -A INPUT -p tcp --dport 443 -j ACCEPT
208-ip6tables -A INPUT -i lo -j ACCEPT
209-ip6tables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
210-ip6tables -P INPUT DROP
211-rc-update add iptables
212-rc-update add ip6tables
213-/etc/init.d/iptables save
214-/etc/init.d/ip6tables save
215-```
216-## 14. Verify Installation
217-```sh
218-rc-service tranquil-pds status
219-curl -s https://pds.example.com/xrpc/_health
220-curl -s https://pds.example.com/.well-known/atproto-did
221-```
222-## Maintenance
223-View logs:
224-```sh
225-tail -f /var/log/tranquil-pds.log
226-```
227-Update Tranquil PDS:
228-```sh
229-cd /opt/tranquil-pds
230-git pull
231-cd frontend && deno task build && cd ..
232-cargo build --release
233-rc-service tranquil-pds stop
234-cp target/release/tranquil-pds /usr/local/bin/
235-cp -r frontend/dist /var/lib/tranquil-pds/frontend
236-DATABASE_URL="postgres://tranquil_pds:your-secure-password@localhost:5432/pds" sqlx migrate run
237-rc-service tranquil-pds start
238-```
239-Backup database:
240-```sh
241-pg_dump -U postgres pds > /var/backups/pds-$(date +%Y%m%d).sql
242-```
243-244-## Custom Homepage
245-246-Drop a `homepage.html` in `/var/lib/tranquil-pds/frontend/` and it becomes your landing page. Go nuts with it. Account dashboard is at `/app/` so you won't break anything.
247-248-```sh
249-cat > /var/lib/tranquil-pds/frontend/homepage.html << 'EOF'
250-<!DOCTYPE html>
251-<html>
252-<head>
253- <title>Welcome to my PDS</title>
254- <style>
255- body { font-family: system-ui; max-width: 600px; margin: 100px auto; padding: 20px; }
256- </style>
257-</head>
258-<body>
259- <h1>Welcome to my amazing zoo pen</h1>
260- <p>This is a <a href="https://atproto.com">AT Protocol</a> Personal Data Server.</p>
261- <p><a href="/app/">Sign in</a> or learn more at <a href="https://bsky.social">Bluesky</a>.</p>
262-</body>
263-</html>
264-EOF
265-```