tangled
alpha
login
or
join now
tranquil.farm
/
tranquil-pds
149
fork
atom
Our Personal Data Server from scratch!
tranquil.farm
oauth
atproto
pds
rust
postgresql
objectstorage
fun
149
fork
atom
overview
issues
19
pulls
2
pipelines
fix: container build should use all-in-one backend+frontend
lewis.moe
3 days ago
edc23ae6
4005041e
+110
-202
5 changed files
expand all
collapse all
unified
split
Dockerfile
docker-compose.prod.yaml
docs
install-containers.md
nginx.conf
nginx.frontend.conf
+6
Dockerfile
···
1
1
+
FROM denoland/deno:alpine AS frontend
2
2
+
WORKDIR /app
3
3
+
COPY frontend/ ./
4
4
+
RUN deno task build
5
5
+
1
6
FROM rust:1.92-alpine AS builder
2
7
RUN apk add --no-cache ca-certificates musl-dev pkgconfig openssl-dev openssl-libs-static
3
8
WORKDIR /app
···
18
23
FROM alpine:3.23
19
24
RUN apk add --no-cache msmtp ca-certificates && ln -sf /usr/bin/msmtp /usr/sbin/sendmail
20
25
COPY --from=builder /tmp/tranquil-pds /usr/local/bin/tranquil-pds
26
26
+
COPY --from=frontend /app/dist /var/lib/tranquil-pds/frontend
21
27
COPY migrations /app/migrations
22
28
WORKDIR /app
23
29
ENV SERVER_HOST=0.0.0.0
+1
-21
docker-compose.prod.yaml
···
27
27
reservations:
28
28
memory: 256M
29
29
30
30
-
frontend:
31
31
-
build:
32
32
-
context: ./frontend
33
33
-
dockerfile: Dockerfile
34
34
-
image: tranquil-pds-frontend:latest
35
35
-
restart: unless-stopped
36
36
-
healthcheck:
37
37
-
test: ["CMD", "wget", "-q", "--spider", "http://localhost:80/"]
38
38
-
interval: 30s
39
39
-
timeout: 10s
40
40
-
retries: 3
41
41
-
start_period: 5s
42
42
-
deploy:
43
43
-
resources:
44
44
-
limits:
45
45
-
memory: 128M
46
46
-
reservations:
47
47
-
memory: 32M
48
48
-
49
30
db:
50
31
image: postgres:18-alpine
51
32
restart: unless-stopped
···
76
57
- "80:80"
77
58
- "443:443"
78
59
volumes:
79
79
-
- ./nginx.frontend.conf:/etc/nginx/nginx.conf:ro
60
60
+
- ./nginx.conf:/etc/nginx/nginx.conf:ro
80
61
- ./certs:/etc/nginx/certs:ro
81
62
- acme_challenge:/var/www/acme:ro
82
63
depends_on:
83
64
- tranquil-pds
84
84
-
- frontend
85
65
healthcheck:
86
66
test: ["CMD", "nginx", "-t"]
87
67
interval: 30s
+2
-2
docs/install-containers.md
···
145
145
## Create nginx configuration
146
146
147
147
```bash
148
148
-
cp /opt/tranquil-pds/nginx.frontend.conf /srv/tranquil-pds/config/nginx.conf
148
148
+
cp /opt/tranquil-pds/nginx.conf /srv/tranquil-pds/config/nginx.conf
149
149
```
150
150
151
151
## Clone and build images
···
288
288
Copy the production compose and nginx configs:
289
289
```sh
290
290
cp /opt/tranquil-pds/docker-compose.prod.yaml /srv/tranquil-pds/docker-compose.yml
291
291
-
cp /opt/tranquil-pds/nginx.frontend.conf /srv/tranquil-pds/config/nginx.conf
291
291
+
cp /opt/tranquil-pds/nginx.conf /srv/tranquil-pds/config/nginx.conf
292
292
```
293
293
294
294
Edit `/srv/tranquil-pds/docker-compose.yml` to adjust paths if needed:
+101
nginx.conf
···
1
1
+
worker_processes auto;
2
2
+
error_log /var/log/nginx/error.log warn;
3
3
+
pid /var/run/nginx.pid;
4
4
+
5
5
+
events {
6
6
+
worker_connections 4096;
7
7
+
use epoll;
8
8
+
multi_accept on;
9
9
+
}
10
10
+
11
11
+
http {
12
12
+
include /etc/nginx/mime.types;
13
13
+
default_type application/octet-stream;
14
14
+
15
15
+
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
16
16
+
'$status $body_bytes_sent "$http_referer" '
17
17
+
'"$http_user_agent" "$http_x_forwarded_for" '
18
18
+
'rt=$request_time uct="$upstream_connect_time" '
19
19
+
'uht="$upstream_header_time" urt="$upstream_response_time"';
20
20
+
21
21
+
access_log /var/log/nginx/access.log main;
22
22
+
23
23
+
sendfile on;
24
24
+
tcp_nopush on;
25
25
+
tcp_nodelay on;
26
26
+
keepalive_timeout 65;
27
27
+
types_hash_max_size 2048;
28
28
+
29
29
+
gzip on;
30
30
+
gzip_vary on;
31
31
+
gzip_proxied any;
32
32
+
gzip_comp_level 6;
33
33
+
gzip_types text/plain text/css text/xml application/json application/javascript
34
34
+
application/xml application/xml+rss text/javascript application/activity+json;
35
35
+
36
36
+
ssl_protocols TLSv1.2 TLSv1.3;
37
37
+
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
38
38
+
ssl_prefer_server_ciphers off;
39
39
+
ssl_session_cache shared:SSL:10m;
40
40
+
ssl_session_timeout 1d;
41
41
+
ssl_session_tickets off;
42
42
+
ssl_stapling on;
43
43
+
ssl_stapling_verify on;
44
44
+
45
45
+
upstream pds {
46
46
+
server tranquil-pds:3000;
47
47
+
keepalive 32;
48
48
+
}
49
49
+
50
50
+
server {
51
51
+
listen 80;
52
52
+
listen [::]:80;
53
53
+
server_name _;
54
54
+
55
55
+
location /.well-known/acme-challenge/ {
56
56
+
root /var/www/acme;
57
57
+
}
58
58
+
59
59
+
location / {
60
60
+
return 301 https://$host$request_uri;
61
61
+
}
62
62
+
}
63
63
+
64
64
+
server {
65
65
+
listen 443 ssl;
66
66
+
listen [::]:443 ssl;
67
67
+
http2 on;
68
68
+
server_name _;
69
69
+
70
70
+
ssl_certificate /etc/nginx/certs/fullchain.pem;
71
71
+
ssl_certificate_key /etc/nginx/certs/privkey.pem;
72
72
+
73
73
+
client_max_body_size 10G;
74
74
+
75
75
+
proxy_http_version 1.1;
76
76
+
proxy_set_header Host $host;
77
77
+
proxy_set_header X-Real-IP $remote_addr;
78
78
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
79
79
+
proxy_set_header X-Forwarded-Proto $scheme;
80
80
+
81
81
+
location /xrpc/ {
82
82
+
proxy_pass http://pds;
83
83
+
proxy_set_header Upgrade $http_upgrade;
84
84
+
proxy_set_header Connection "upgrade";
85
85
+
proxy_read_timeout 86400;
86
86
+
proxy_send_timeout 86400;
87
87
+
proxy_buffering off;
88
88
+
proxy_request_buffering off;
89
89
+
}
90
90
+
91
91
+
location /oauth/ {
92
92
+
proxy_pass http://pds;
93
93
+
proxy_read_timeout 300;
94
94
+
proxy_send_timeout 300;
95
95
+
}
96
96
+
97
97
+
location / {
98
98
+
proxy_pass http://pds;
99
99
+
}
100
100
+
}
101
101
+
}
-179
nginx.frontend.conf
···
1
1
-
worker_processes auto;
2
2
-
error_log /var/log/nginx/error.log warn;
3
3
-
pid /var/run/nginx.pid;
4
4
-
5
5
-
events {
6
6
-
worker_connections 4096;
7
7
-
use epoll;
8
8
-
multi_accept on;
9
9
-
}
10
10
-
11
11
-
http {
12
12
-
include /etc/nginx/mime.types;
13
13
-
default_type application/octet-stream;
14
14
-
15
15
-
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
16
16
-
'$status $body_bytes_sent "$http_referer" '
17
17
-
'"$http_user_agent" "$http_x_forwarded_for" '
18
18
-
'rt=$request_time uct="$upstream_connect_time" '
19
19
-
'uht="$upstream_header_time" urt="$upstream_response_time"';
20
20
-
21
21
-
access_log /var/log/nginx/access.log main;
22
22
-
23
23
-
sendfile on;
24
24
-
tcp_nopush on;
25
25
-
tcp_nodelay on;
26
26
-
keepalive_timeout 65;
27
27
-
types_hash_max_size 2048;
28
28
-
29
29
-
gzip on;
30
30
-
gzip_vary on;
31
31
-
gzip_proxied any;
32
32
-
gzip_comp_level 6;
33
33
-
gzip_types text/plain text/css text/xml application/json application/javascript
34
34
-
application/xml application/xml+rss text/javascript application/activity+json;
35
35
-
36
36
-
ssl_protocols TLSv1.2 TLSv1.3;
37
37
-
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
38
38
-
ssl_prefer_server_ciphers off;
39
39
-
ssl_session_cache shared:SSL:10m;
40
40
-
ssl_session_timeout 1d;
41
41
-
ssl_session_tickets off;
42
42
-
ssl_stapling on;
43
43
-
ssl_stapling_verify on;
44
44
-
45
45
-
upstream backend {
46
46
-
server tranquil-pds:3000;
47
47
-
keepalive 32;
48
48
-
}
49
49
-
50
50
-
upstream frontend {
51
51
-
server frontend:80;
52
52
-
keepalive 16;
53
53
-
}
54
54
-
55
55
-
server {
56
56
-
listen 80;
57
57
-
listen [::]:80;
58
58
-
server_name _;
59
59
-
60
60
-
location /.well-known/acme-challenge/ {
61
61
-
root /var/www/acme;
62
62
-
}
63
63
-
64
64
-
location / {
65
65
-
return 301 https://$host$request_uri;
66
66
-
}
67
67
-
}
68
68
-
69
69
-
server {
70
70
-
listen 443 ssl;
71
71
-
listen [::]:443 ssl;
72
72
-
http2 on;
73
73
-
server_name _;
74
74
-
75
75
-
ssl_certificate /etc/nginx/certs/fullchain.pem;
76
76
-
ssl_certificate_key /etc/nginx/certs/privkey.pem;
77
77
-
78
78
-
client_max_body_size 10G;
79
79
-
80
80
-
location /xrpc/ {
81
81
-
proxy_pass http://backend;
82
82
-
proxy_http_version 1.1;
83
83
-
proxy_set_header Upgrade $http_upgrade;
84
84
-
proxy_set_header Connection "upgrade";
85
85
-
proxy_set_header Host $host;
86
86
-
proxy_set_header X-Real-IP $remote_addr;
87
87
-
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
88
88
-
proxy_set_header X-Forwarded-Proto $scheme;
89
89
-
proxy_read_timeout 86400;
90
90
-
proxy_send_timeout 86400;
91
91
-
proxy_buffering off;
92
92
-
proxy_request_buffering off;
93
93
-
}
94
94
-
95
95
-
location = /oauth-client-metadata.json {
96
96
-
proxy_pass http://frontend;
97
97
-
proxy_http_version 1.1;
98
98
-
proxy_set_header Host $host;
99
99
-
proxy_set_header Accept-Encoding "";
100
100
-
sub_filter_once off;
101
101
-
sub_filter_types application/json;
102
102
-
sub_filter '__FRONTEND_HOSTNAME__' $host;
103
103
-
}
104
104
-
105
105
-
location /oauth/ {
106
106
-
proxy_pass http://backend;
107
107
-
proxy_http_version 1.1;
108
108
-
proxy_set_header Host $host;
109
109
-
proxy_set_header X-Real-IP $remote_addr;
110
110
-
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
111
111
-
proxy_set_header X-Forwarded-Proto $scheme;
112
112
-
proxy_read_timeout 300;
113
113
-
proxy_send_timeout 300;
114
114
-
}
115
115
-
116
116
-
location /.well-known/ {
117
117
-
proxy_pass http://backend;
118
118
-
proxy_http_version 1.1;
119
119
-
proxy_set_header Host $host;
120
120
-
proxy_set_header X-Real-IP $remote_addr;
121
121
-
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
122
122
-
proxy_set_header X-Forwarded-Proto $scheme;
123
123
-
}
124
124
-
125
125
-
location /webhook/ {
126
126
-
proxy_pass http://backend;
127
127
-
proxy_http_version 1.1;
128
128
-
proxy_set_header Host $host;
129
129
-
proxy_set_header X-Real-IP $remote_addr;
130
130
-
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
131
131
-
proxy_set_header X-Forwarded-Proto $scheme;
132
132
-
}
133
133
-
134
134
-
location = /metrics {
135
135
-
proxy_pass http://backend;
136
136
-
proxy_http_version 1.1;
137
137
-
proxy_set_header Host $host;
138
138
-
proxy_set_header X-Real-IP $remote_addr;
139
139
-
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
140
140
-
proxy_set_header X-Forwarded-Proto $scheme;
141
141
-
}
142
142
-
143
143
-
location = /health {
144
144
-
proxy_pass http://backend;
145
145
-
proxy_http_version 1.1;
146
146
-
proxy_set_header Host $host;
147
147
-
}
148
148
-
149
149
-
location = /robots.txt {
150
150
-
proxy_pass http://backend;
151
151
-
proxy_http_version 1.1;
152
152
-
proxy_set_header Host $host;
153
153
-
}
154
154
-
155
155
-
location = /logo {
156
156
-
proxy_pass http://backend;
157
157
-
proxy_http_version 1.1;
158
158
-
proxy_set_header Host $host;
159
159
-
}
160
160
-
161
161
-
location ~ ^/u/[^/]+/did\.json$ {
162
162
-
proxy_pass http://backend;
163
163
-
proxy_http_version 1.1;
164
164
-
proxy_set_header Host $host;
165
165
-
proxy_set_header X-Real-IP $remote_addr;
166
166
-
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
167
167
-
proxy_set_header X-Forwarded-Proto $scheme;
168
168
-
}
169
169
-
170
170
-
location / {
171
171
-
proxy_pass http://frontend;
172
172
-
proxy_http_version 1.1;
173
173
-
proxy_set_header Host $host;
174
174
-
proxy_set_header X-Real-IP $remote_addr;
175
175
-
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
176
176
-
proxy_set_header X-Forwarded-Proto $scheme;
177
177
-
}
178
178
-
}
179
179
-
}