From 490f3e7cee8cc07cfd7875517958a5a86d991db5 Mon Sep 17 00:00:00 2001 From: Seongmin Lee Date: Fri, 17 Oct 2025 02:13:44 +0900 Subject: [PATCH] local-infra: local, sandboxed atmosphere infra Change-Id: wotxqrqrxmzwtqzpxmsvpuzvlwkuyklz Signed-off-by: Seongmin Lee --- local-infra/Caddyfile | 54 +++++++++++++++ local-infra/docker-compose.yml | 78 ++++++++++++++++++++++ local-infra/pds.env | 17 +++++ local-infra/readme.md | 14 ++++ local-infra/scripts/create-test-account.sh | 63 +++++++++++++++++ 5 files changed, 226 insertions(+) create mode 100644 local-infra/Caddyfile create mode 100644 local-infra/docker-compose.yml create mode 100644 local-infra/pds.env create mode 100644 local-infra/readme.md create mode 100755 local-infra/scripts/create-test-account.sh diff --git a/local-infra/Caddyfile b/local-infra/Caddyfile new file mode 100644 index 00000000..19971802 --- /dev/null +++ b/local-infra/Caddyfile @@ -0,0 +1,54 @@ +{ + storage file_system /data/ + debug + pki { + ca localtangled { + name "LocalTangledCA" + } + } +} + +plc.tngl.boltless.dev { + tls { + issuer internal { + ca localtangled + } + } + reverse_proxy http://plc:8080 +} + +*.pds.tngl.boltless.dev, pds.tngl.boltless.dev { + tls { + issuer internal { + ca localtangled + } + } + reverse_proxy http://pds:3000 +} + +jetstream.tngl.boltless.dev { + tls { + issuer internal { + ca localtangled + } + } + reverse_proxy http://jetstream:6008 +} + +knot.tngl.boltless.dev { + tls { + issuer internal { + ca localtangled + } + } + reverse_proxy http://localhost:6000 +} + +spindle.tngl.boltless.dev { + tls { + issuer internal { + ca localtangled + } + } + reverse_proxy http://localhost:6555 +} diff --git a/local-infra/docker-compose.yml b/local-infra/docker-compose.yml new file mode 100644 index 00000000..ba59580b --- /dev/null +++ b/local-infra/docker-compose.yml @@ -0,0 +1,78 @@ +name: tangled-local-infra +services: + caddy: + container_name: caddy + image: caddy:2 + depends_on: + - pds + restart: unless-stopped + cap_add: + - NET_ADMIN + ports: + - "80:80" + - "443:443" + - "443:443/udp" + volumes: + - ./Caddyfile:/etc/caddy/Caddyfile + - caddy_data:/data + - caddy_config:/config + + plc: + image: ghcr.io/bluesky-social/did-method-plc:plc-f2ab7516bac5bc0f3f86842fa94e996bd1b3815b + # did-method-plc only provides linux/amd64 + platform: linux/amd64 + container_name: plc + restart: unless-stopped + ports: + - "4000:8080" + depends_on: + - plc_db + environment: + DEBUG_MODE: 1 + LOG_ENABLED: "true" + LOG_LEVEL: "debug" + LOG_DESTINATION: 1 + DB_CREDS_JSON: &DB_CREDS_JSON '{"username":"pg","password":"password","host":"plc_db","port":5432}' + DB_MIGRATE_CREDS_JSON: *DB_CREDS_JSON + PLC_VERSION: 0.0.1 + PORT: 8080 + + plc_db: + image: postgres:14.4-alpine + container_name: plc_db + environment: + - POSTGRES_USER=pg + - POSTGRES_PASSWORD=password + - PGPORT=5432 + volumes: + - plc:/var/lib/postgresql/data + + pds: + container_name: pds + image: ghcr.io/bluesky-social/pds:0.4 + restart: unless-stopped + ports: + - "4001:3000" + volumes: + - pds:/pds + env_file: + - ./pds.env + + jetstream: + container_name: jetstream + image: ghcr.io/bluesky-social/jetstream:sha-0ab10bd + restart: unless-stopped + volumes: + - jetstream:/data + environment: + - JETSTREAM_DATA_DIR=/data + # livness check interval to restart when no events are received (default: 15sec) + - JETSTREAM_LIVENESS_TTL=300s + - JETSTREAM_WS_URL=ws://pds:3000/xrpc/com.atproto.sync.subscribeRepos + +volumes: + caddy_config: + caddy_data: + plc: + pds: + jetstream: diff --git a/local-infra/pds.env b/local-infra/pds.env new file mode 100644 index 00000000..9e7078b9 --- /dev/null +++ b/local-infra/pds.env @@ -0,0 +1,17 @@ +PDS_JWT_SECRET=8cae8bffcc73d9932819650791e4e89a +PDS_ADMIN_PASSWORD=d6a902588cd93bee1af83f924f60cfd3 +PDS_PLC_ROTATION_KEY_K256_PRIVATE_KEY_HEX=2e92e336a50a618458e1097d94a1db86ec3fd8829d7735020cbae80625c761d7 + +LOG_ENABLED=true + +# PDS_BSKY_APP_VIEW_DID=did:web:api.bsky.app +# PDS_BSKY_APP_VIEW_URL=https://api.bsky.app + +PDS_DATA_DIRECTORY=/pds +PDS_BLOBSTORE_DISK_LOCATION=/pds/blocks + +# PDS_DID_PLC_URL=http://plc:8080 +PDS_HOSTNAME=pds.tngl.boltless.dev + +# PDS_REPORT_SERVICE_DID=did:plc:ar7c4by46qjdydhdevvrndac +# PDS_REPORT_SERVICE_URL=https://mod.bsky.app diff --git a/local-infra/readme.md b/local-infra/readme.md new file mode 100644 index 00000000..b8429f90 --- /dev/null +++ b/local-infra/readme.md @@ -0,0 +1,14 @@ +run compose +``` +docker compose up -d +``` + +copy the self-signed certificate to host machine +``` +docker cp caddy:/data/pki/authorities/localtangled/root.crt localtangled.crt +``` + +trust the cert (macOS) +``` +sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain ./localtangled.crt +``` diff --git a/local-infra/scripts/create-test-account.sh b/local-infra/scripts/create-test-account.sh new file mode 100755 index 00000000..d1a612a8 --- /dev/null +++ b/local-infra/scripts/create-test-account.sh @@ -0,0 +1,63 @@ +#!/bin/bash +set -o errexit +set -o nounset +set -o pipefail + +source "$(dirname "$0")/../pds.env" + +# curl a URL and fail if the request fails. +function curl_cmd_get { + curl --fail --silent --show-error "$@" +} + +# curl a URL and fail if the request fails. +function curl_cmd_post { + curl --fail --silent --show-error --request POST --header "Content-Type: application/json" "$@" +} + +# curl a URL but do not fail if the request fails. +function curl_cmd_post_nofail { + curl --silent --show-error --request POST --header "Content-Type: application/json" "$@" +} + +USERNAME="${1:-}" + +if [[ "${USERNAME}" == "" ]]; then + read -p "Enter a username: " USERNAME +fi + +if [[ "${USERNAME}" == "" ]]; then + echo "ERROR: missing USERNAME parameter." >/dev/stderr + echo "Usage: $0 ${SUBCOMMAND} " >/dev/stderr + exit 1 +fi + +PASSWORD="password" +INVITE_CODE="$(curl_cmd_post \ + --user "admin:${PDS_ADMIN_PASSWORD}" \ + --data '{"useCount": 1}' \ + "https://${PDS_HOSTNAME}/xrpc/com.atproto.server.createInviteCode" | jq --raw-output '.code' +)" +RESULT="$(curl_cmd_post_nofail \ + --data "{\"email\":\"${USERNAME}@${PDS_HOSTNAME}\", \"handle\":\"${USERNAME}.${PDS_HOSTNAME}\", \"password\":\"${PASSWORD}\", \"inviteCode\":\"${INVITE_CODE}\"}" \ + "https://${PDS_HOSTNAME}/xrpc/com.atproto.server.createAccount" +)" + +DID="$(echo $RESULT | jq --raw-output '.did')" +if [[ "${DID}" != did:* ]]; then + ERR="$(echo ${RESULT} | jq --raw-output '.message')" + echo "ERROR: ${ERR}" >/dev/stderr + echo "Usage: $0 " >/dev/stderr + exit 1 +fi + +echo +echo "Account created successfully!" +echo "-----------------------------" +echo "Handle : ${USERNAME}.${PDS_HOSTNAME}" +echo "DID : ${DID}" +echo "Password : ${PASSWORD}" +echo "-----------------------------" +echo "This is a test account with an insecure password." +echo "Make sure it's only used for development." +echo -- 2.43.0