diff --git a/.env.example b/.env.example index d3a7d8a..6e36280 100644 --- a/.env.example +++ b/.env.example @@ -33,6 +33,7 @@ INBOX_PULL_INTERVAL_SECONDS=600 IMPORT_START_DATE="2023-01-20" IMPORT_QUERY_INTERVAL_SECONDS=600 IMPORT_SEED_RELAYS="relay.damus.io,nos.lol,relay.nostr.band,relay.snort.social,nostr.land,nostr.mom,relay.nos.social,relay.primal.net,relay.nostr.bg,no.str.cr,nostr21.com,nostrue.com,relay.siamstr.com,wot.utxo.one,nostrelites.org,wot.nostr.party,wot.sovbit.host,wot.girino.org,relay.lnau.net,wot.siamstr.com,wot.sudocarlos.com,relay.otherstuff.fyi,relay.lexingtonbitcoin.org,wot.azzamo.net,wot.swarmstr.com,zap.watch,satsage.xyz,wons.calva.dev" +IMPORT_SEED_RELAYS_FILE="" ## Backup Settings BACKUP_PROVIDER="aws" @@ -46,3 +47,8 @@ AWS_BUCKET_NAME="utxo-relay-backups" ## Blastr Settings BLASTR_RELAYS="relay.damus.io,nos.lol,relay.nostr.band,relay.snort.social,nostr.land,nostr.mom,relay.nos.social,relay.primal.net,relay.nostr.bg,no.str.cr,nostr21.com,nostrue.com,relay.siamstr.com,wot.utxo.one,nostrelites.org,wot.nostr.party,wot.sovbit.host,wot.girino.org,relay.lnau.net,wot.siamstr.com,wot.sudocarlos.com,relay.otherstuff.fyi,relay.lexingtonbitcoin.org,wot.azzamo.net,wot.swarmstr.com,zap.watch,satsage.xyz,wons.calva.dev" +BLASTR_RELAYS_FILE="" + +## OPTIONAL: Docker UID and GID - should be the same as the user running the docker container +DOCKER_UID=1000 +DOCKER_GID=1000 diff --git a/.gitignore b/.gitignore index e168dc8..0a290f7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ .env -db/ -haven \ No newline at end of file +relays_import.json +relays_blastr.json diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..44de815 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,37 @@ +# Use Golang image based on Debian Bookworm +FROM golang:bookworm + +# Set the working directory within the container +WORKDIR /app + +# Copy go.mod and go.sum files +COPY go.mod go.sum ./ + +# Download dependencies +RUN go mod download + +# Copy the rest of the application source code +COPY . . + +# Build the Go application +RUN go build -o main . + +# Add environment variables for UID and GID +ARG DOCKER_UID=1000 +ARG DOCKER_GID=1000 + +# Create a new group and user +RUN groupadd -g ${DOCKER_GID} appgroup && \ + useradd -u ${DOCKER_UID} -g appgroup -m appuser + +# Change ownership of the working directory +RUN chown -R appuser:appgroup /app + +# Switch to the new user +USER appuser + +# Expose the port that the application will run on +EXPOSE 3334 + +# Set the command to run the executable +CMD ["./main"] diff --git a/README.md b/README.md index c543bee..5178538 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,31 @@ cp .env.example .env Open the `.env` file and set the necessary environment variables. +If you want to use custom relay files for import and blastr, you can specify IMPORT_SEED_RELAYS_FILE and BLASTR_RELAYS_FILE in the .env file. First, copy the example JSON files: + +```bash +cp relays_import.example.json relays_import.json +``` +```bash +cp blastr_relays.example.json blastr_relays.json +``` + +Then, set the paths to the files in the .env file: + +```bash +IMPORT_SEED_RELAYS_FILE=relays_import.json +BLASTR_RELAYS_FILE=blastr_relays.json +``` + +The JSON should contain an array of relay URLs (without ws:// or wss://): + +```json +[ + "relay.damus.io", + "nos.lol", +] +``` + ### 4. Build the project Run the following command to build the relay: @@ -170,6 +195,56 @@ Once everything is set up, the relay will be running on `localhost:3355` with th - `localhost:3355/chat` - `localhost:3355/inbox` +## Start the Project with Docker Compose + +To start the project using Docker Compose, follow these steps: + +1. Ensure Docker and Docker Compose are installed on your system. +2. Navigate to the project directory. +3. Ensure the `.env` file is present in the project directory and has the necessary environment variables set. +4. You can also change the paths of the `db` folder and `haven` folder in the `docker-compose.yml` file. + + ```yaml + volumes: + - "./db:/app/db" # only change the left side before the colon + - "./haven:/app/haven" # only change the left side before the colon + ``` + +5. Run the following command: + + ```sh + # in foreground + docker compose up --build + # in background + docker compose up --build -d + ``` + +6. For updating the relay, run the following command: + + ```sh + git pull + docker compose build --no-cache + # in foreground + docker compose up + # in background + docker compose up -d + ``` + +This will build the Docker image and start the `haven-relay` service as defined in the `docker-compose.yml` file. The application will be accessible on port 3335. + +### Hidden Service with Tor and Docker (optional) + +Same as the step 6, but with the following command: + +```sh +# in foreground +docker compose -f docker-compose.tor.yml up --build +# in background +docker compose -f docker-compose.tor.yml up --build -d +``` + +You can find the onion address here: `tor/data/haven/hostname` + ## Cloud Backups The relay automatically backs up your database to a cloud provider of your choice. diff --git a/config.go b/config.go index 61d6bec..38eb215 100644 --- a/config.go +++ b/config.go @@ -5,6 +5,8 @@ import ( "os" "strconv" "strings" + "encoding/json" + "io/ioutil" "github.com/joho/godotenv" ) @@ -49,6 +51,20 @@ type AwsConfig struct { Bucket string `json:"bucket"` } +func getRelayListFromEnvOrFile(envKey, fileKey string) []string { + envValue := getEnv(envKey) + if envValue != "" { + return getRelayList(envValue) + } + + filePath := getEnv(fileKey) + if filePath != "" { + return getRelayListFromFile(filePath) + } + + return []string{} +} + func loadConfig() Config { godotenv.Load(".env") @@ -79,10 +95,10 @@ func loadConfig() Config { InboxPullIntervalSeconds: getEnvInt("INBOX_PULL_INTERVAL_SECONDS", 3600), ImportStartDate: getEnv("IMPORT_START_DATE"), ImportQueryIntervalSeconds: getEnvInt("IMPORT_QUERY_INTERVAL_SECONDS", 360000), - ImportSeedRelays: getRelayList(getEnv("IMPORT_SEED_RELAYS")), + ImportSeedRelays: getRelayListFromEnvOrFile("IMPORT_SEED_RELAYS", "IMPORT_SEED_RELAYS_FILE"), BackupProvider: getEnv("BACKUP_PROVIDER"), BackupIntervalHours: getEnvInt("BACKUP_INTERVAL_HOURS", 24), - BlastrRelays: getRelayList(getEnv("BLASTR_RELAYS")), + BlastrRelays: getRelayListFromEnvOrFile("BLASTR_RELAYS", "BLASTR_RELAYS_FILE"), } } @@ -94,6 +110,23 @@ func getRelayList(commaList string) []string { return relayList } +func getRelayListFromFile(filePath string) []string { + file, err := ioutil.ReadFile(filePath) + if err != nil { + log.Fatalf("Failed to read file: %s", err) + } + + var relayList []string + if err := json.Unmarshal(file, &relayList); err != nil { + log.Fatalf("Failed to parse JSON: %s", err) + } + + for i, relay := range relayList { + relayList[i] = "wss://" + strings.TrimSpace(relay) + } + return relayList +} + func getEnv(key string) string { value, exists := os.LookupEnv(key) if !exists { diff --git a/db/.gitignore b/db/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/db/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/docker-compose.tor.yml b/docker-compose.tor.yml new file mode 100644 index 0000000..b014df6 --- /dev/null +++ b/docker-compose.tor.yml @@ -0,0 +1,25 @@ +services: + relay: + container_name: haven-relay + build: + context: . + dockerfile: Dockerfile + env_file: + - .env + volumes: + - "./db:/app/db" + - "./haven:/app/haven" + ports: + - "3335" + user: "${DOCKER_UID:-1000}:${DOCKER_GID:-1000}" + + tor: + image: lncm/tor:0.4.7.9@sha256:86c2fe9d9099e6376798979110b8b9a3ee5d8adec27289ac4a5ee892514ffe92 + container_name: haven-tor + depends_on: + - relay + volumes: + - ./tor/torrc:/etc/tor/torrc + - ./tor/data:/var/lib/tor + restart: on-failure + stop_grace_period: 10m30s diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..0c2ea58 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,14 @@ +services: + relay: + container_name: haven-relay + build: + context: . + dockerfile: Dockerfile + env_file: + - .env + volumes: + - "./db:/app/db" + - "./haven:/app/haven" + ports: + - "3335:3335" + user: "${DOCKER_UID:-1000}:${DOCKER_GID:-1000}" diff --git a/haven/.gitignore b/haven/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/haven/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/tor/data/.gitignore b/tor/data/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/tor/data/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/tor/torrc b/tor/torrc new file mode 100644 index 0000000..ce82803 --- /dev/null +++ b/tor/torrc @@ -0,0 +1,2 @@ +HiddenServiceDir /var/lib/tor/haven +HiddenServicePort 80 relay:3355