+54
local-infra/Caddyfile
+54
local-infra/Caddyfile
···
1
+
{
2
+
storage file_system /data/
3
+
debug
4
+
pki {
5
+
ca localtangled {
6
+
name "LocalTangledCA"
7
+
}
8
+
}
9
+
auto_https disable_redirects
10
+
}
11
+
12
+
plc.tngl.boltless.dev {
13
+
tls {
14
+
issuer internal {
15
+
ca localtangled
16
+
}
17
+
}
18
+
reverse_proxy http://plc:8080
19
+
}
20
+
21
+
*.pds.tngl.boltless.dev, pds.tngl.boltless.dev {
22
+
tls {
23
+
issuer internal {
24
+
ca localtangled
25
+
}
26
+
}
27
+
reverse_proxy http://pds:3000
28
+
}
29
+
30
+
jetstream.tngl.boltless.dev {
31
+
tls {
32
+
issuer internal {
33
+
ca localtangled
34
+
}
35
+
}
36
+
reverse_proxy http://jetstream:6008
37
+
}
38
+
39
+
http://knot.tngl.boltless.dev {
40
+
reverse_proxy http://host.docker.internal:6000
41
+
}
42
+
43
+
https://knot.tngl.boltless.dev {
44
+
tls {
45
+
issuer internal {
46
+
ca localtangled
47
+
}
48
+
}
49
+
reverse_proxy http://host.docker.internal:6000
50
+
}
51
+
52
+
http://spindle.tngl.boltless.dev {
53
+
reverse_proxy http://host.docker.internal:6555
54
+
}
+12
local-infra/cert/localtangled/intermediate.crt
+12
local-infra/cert/localtangled/intermediate.crt
···
1
+
-----BEGIN CERTIFICATE-----
2
+
MIIBuTCCAV+gAwIBAgIQR5mkZ/TBSWtRFqrMyeVrNDAKBggqhkjOPQQDAjApMScw
3
+
JQYDVQQDEx5Mb2NhbFRhbmdsZWRDQSAtIDIwMjUgRUNDIFJvb3QwHhcNMjUxMTAz
4
+
MTAyMDA0WhcNMjUxMTEwMTAyMDA0WjAsMSowKAYDVQQDEyFMb2NhbFRhbmdsZWRD
5
+
QSAtIEVDQyBJbnRlcm1lZGlhdGUwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARm
6
+
892T608pFY+dmgkEMFdvq9hj+PlR7o7Vogc+Ca5LeHB846PrZJmxdvHW8Up67hP3
7
+
ZpmNjnZQvgOEEjLmquvio2YwZDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgw
8
+
BgEB/wIBADAdBgNVHQ4EFgQUn8d4TdPCYP0r1Jc09QF4/GKkSSowHwYDVR0jBBgw
9
+
FoAUKSXx08/YgAxM+u7pYQcs/WHJIRAwCgYIKoZIzj0EAwIDSAAwRQIgTZeKVo6k
10
+
ZBZwx2sx+T46LyjYc5xK/DCQJbLWsgoc/lECIQDNtduyds5J/BfBvnVzO/oK9+0H
11
+
oRvV+fcWRAQHGKF4Ew==
12
+
-----END CERTIFICATE-----
+5
local-infra/cert/localtangled/intermediate.key
+5
local-infra/cert/localtangled/intermediate.key
+11
local-infra/cert/localtangled/root.crt
+11
local-infra/cert/localtangled/root.crt
···
1
+
-----BEGIN CERTIFICATE-----
2
+
MIIBlTCCATygAwIBAgIRAMDTcwNxYDMgtUNC5LkCeEQwCgYIKoZIzj0EAwIwKTEn
3
+
MCUGA1UEAxMeTG9jYWxUYW5nbGVkQ0EgLSAyMDI1IEVDQyBSb290MB4XDTI1MTAx
4
+
NzE2MTE0NVoXDTM1MDgyNjE2MTE0NVowKTEnMCUGA1UEAxMeTG9jYWxUYW5nbGVk
5
+
Q0EgLSAyMDI1IEVDQyBSb290MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE7rFM
6
+
4oNfT0UMqMuc3L60TCLeTd58WFSUYnKl7R1HOHDWeWZhhoNdWguXJSHhFPiWmQ5E
7
+
+fiI7KvDAVQGHzfUAqNFMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYB
8
+
Af8CAQEwHQYDVR0OBBYEFCkl8dPP2IAMTPru6WEHLP1hySEQMAoGCCqGSM49BAMC
9
+
A0cAMEQCIFjSGjvie1gO/JuNtP2HqeUHQNEh82K1fXdks54up3KEAiBWQDaOYeZ2
10
+
zVTiKe8ZQHpH3glXsIS0USsxeKaohMp0zA==
11
+
-----END CERTIFICATE-----
+5
local-infra/cert/localtangled/root.key
+5
local-infra/cert/localtangled/root.key
+75
local-infra/docker-compose.yml
+75
local-infra/docker-compose.yml
···
1
+
name: tangled-local-infra
2
+
services:
3
+
caddy:
4
+
container_name: caddy
5
+
image: caddy:2
6
+
depends_on:
7
+
- pds
8
+
restart: unless-stopped
9
+
cap_add:
10
+
- NET_ADMIN
11
+
ports:
12
+
- "80:80"
13
+
- "443:443"
14
+
- "443:443/udp"
15
+
volumes:
16
+
- ./Caddyfile:/etc/caddy/Caddyfile
17
+
- ./cert/localtangled:/data/pki/authorities/localtangled
18
+
- caddy_data:/data
19
+
- caddy_config:/config
20
+
21
+
plc:
22
+
image: ghcr.io/bluesky-social/did-method-plc:plc-f2ab7516bac5bc0f3f86842fa94e996bd1b3815b
23
+
# did-method-plc only provides linux/amd64
24
+
platform: linux/amd64
25
+
container_name: plc
26
+
restart: unless-stopped
27
+
depends_on:
28
+
- plc_db
29
+
environment:
30
+
DEBUG_MODE: 1
31
+
LOG_ENABLED: "true"
32
+
LOG_LEVEL: "debug"
33
+
LOG_DESTINATION: 1
34
+
DB_CREDS_JSON: &DB_CREDS_JSON '{"username":"pg","password":"password","host":"plc_db","port":5432}'
35
+
DB_MIGRATE_CREDS_JSON: *DB_CREDS_JSON
36
+
PLC_VERSION: 0.0.1
37
+
PORT: 8080
38
+
39
+
plc_db:
40
+
image: postgres:14.4-alpine
41
+
container_name: plc_db
42
+
environment:
43
+
- POSTGRES_USER=pg
44
+
- POSTGRES_PASSWORD=password
45
+
- PGPORT=5432
46
+
volumes:
47
+
- plc:/var/lib/postgresql/data
48
+
49
+
pds:
50
+
container_name: pds
51
+
image: ghcr.io/bluesky-social/pds:0.4
52
+
restart: unless-stopped
53
+
volumes:
54
+
- pds:/pds
55
+
env_file:
56
+
- ./pds.env
57
+
58
+
jetstream:
59
+
container_name: jetstream
60
+
image: ghcr.io/bluesky-social/jetstream:sha-0ab10bd
61
+
restart: unless-stopped
62
+
volumes:
63
+
- jetstream:/data
64
+
environment:
65
+
- JETSTREAM_DATA_DIR=/data
66
+
# livness check interval to restart when no events are received (default: 15sec)
67
+
- JETSTREAM_LIVENESS_TTL=300s
68
+
- JETSTREAM_WS_URL=ws://pds:3000/xrpc/com.atproto.sync.subscribeRepos
69
+
70
+
volumes:
71
+
caddy_config:
72
+
caddy_data:
73
+
plc:
74
+
pds:
75
+
jetstream:
+17
local-infra/pds.env
+17
local-infra/pds.env
···
1
+
PDS_JWT_SECRET=8cae8bffcc73d9932819650791e4e89a
2
+
PDS_ADMIN_PASSWORD=d6a902588cd93bee1af83f924f60cfd3
3
+
PDS_PLC_ROTATION_KEY_K256_PRIVATE_KEY_HEX=2e92e336a50a618458e1097d94a1db86ec3fd8829d7735020cbae80625c761d7
4
+
5
+
LOG_ENABLED=true
6
+
7
+
# PDS_BSKY_APP_VIEW_DID=did:web:api.bsky.app
8
+
# PDS_BSKY_APP_VIEW_URL=https://api.bsky.app
9
+
10
+
PDS_DATA_DIRECTORY=/pds
11
+
PDS_BLOBSTORE_DISK_LOCATION=/pds/blocks
12
+
13
+
PDS_DID_PLC_URL=http://plc:8080
14
+
PDS_HOSTNAME=pds.tngl.boltless.dev
15
+
16
+
# PDS_REPORT_SERVICE_DID=did:plc:ar7c4by46qjdydhdevvrndac
17
+
# PDS_REPORT_SERVICE_URL=https://mod.bsky.app
+9
local-infra/readme.md
+9
local-infra/readme.md
+63
local-infra/scripts/create-test-account.sh
+63
local-infra/scripts/create-test-account.sh
···
1
+
#!/bin/bash
2
+
set -o errexit
3
+
set -o nounset
4
+
set -o pipefail
5
+
6
+
source "$(dirname "$0")/../pds.env"
7
+
8
+
# curl a URL and fail if the request fails.
9
+
function curl_cmd_get {
10
+
curl --fail --silent --show-error "$@"
11
+
}
12
+
13
+
# curl a URL and fail if the request fails.
14
+
function curl_cmd_post {
15
+
curl --fail --silent --show-error --request POST --header "Content-Type: application/json" "$@"
16
+
}
17
+
18
+
# curl a URL but do not fail if the request fails.
19
+
function curl_cmd_post_nofail {
20
+
curl --silent --show-error --request POST --header "Content-Type: application/json" "$@"
21
+
}
22
+
23
+
USERNAME="${1:-}"
24
+
25
+
if [[ "${USERNAME}" == "" ]]; then
26
+
read -p "Enter a username: " USERNAME
27
+
fi
28
+
29
+
if [[ "${USERNAME}" == "" ]]; then
30
+
echo "ERROR: missing USERNAME parameter." >/dev/stderr
31
+
echo "Usage: $0 ${SUBCOMMAND} <USERNAME>" >/dev/stderr
32
+
exit 1
33
+
fi
34
+
35
+
PASSWORD="password"
36
+
INVITE_CODE="$(curl_cmd_post \
37
+
--user "admin:${PDS_ADMIN_PASSWORD}" \
38
+
--data '{"useCount": 1}' \
39
+
"https://${PDS_HOSTNAME}/xrpc/com.atproto.server.createInviteCode" | jq --raw-output '.code'
40
+
)"
41
+
RESULT="$(curl_cmd_post_nofail \
42
+
--data "{\"email\":\"${USERNAME}@${PDS_HOSTNAME}\", \"handle\":\"${USERNAME}.${PDS_HOSTNAME}\", \"password\":\"${PASSWORD}\", \"inviteCode\":\"${INVITE_CODE}\"}" \
43
+
"https://${PDS_HOSTNAME}/xrpc/com.atproto.server.createAccount"
44
+
)"
45
+
46
+
DID="$(echo $RESULT | jq --raw-output '.did')"
47
+
if [[ "${DID}" != did:* ]]; then
48
+
ERR="$(echo ${RESULT} | jq --raw-output '.message')"
49
+
echo "ERROR: ${ERR}" >/dev/stderr
50
+
echo "Usage: $0 <EMAIL> <HANDLE>" >/dev/stderr
51
+
exit 1
52
+
fi
53
+
54
+
echo
55
+
echo "Account created successfully!"
56
+
echo "-----------------------------"
57
+
echo "Handle : ${USERNAME}.${PDS_HOSTNAME}"
58
+
echo "DID : ${DID}"
59
+
echo "Password : ${PASSWORD}"
60
+
echo "-----------------------------"
61
+
echo "This is a test account with an insecure password."
62
+
echo "Make sure it's only used for development."
63
+
echo
+5
nix/vm.nix
+5
nix/vm.nix
···
79
79
};
80
80
# This is fine because any and all ports that are forwarded to host are explicitly marked above, we don't need a separate guest firewall
81
81
networking.firewall.enable = false;
82
+
services.dnsmasq.enable = true;
83
+
services.dnsmasq.settings.address = "/tngl.boltless.dev/10.0.2.2";
84
+
security.pki.certificates = [
85
+
(builtins.readFile ../local-infra/cert/localtangled/root.crt)
86
+
];
82
87
time.timeZone = "Europe/London";
83
88
services.getty.autologinUser = "root";
84
89
environment.systemPackages = with pkgs; [curl vim git sqlite litecli];