Skip to content

Commit 53d0031

Browse files
authored
Merge branch 'main' into chore/replace-semantic-release-with-changesets
2 parents ffcd7cd + 3543d6c commit 53d0031

12 files changed

Lines changed: 154 additions & 6 deletions

.env.example

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,8 @@ WORKER_COUNT=2 # Defaults to CPU count. Use 1 or 2 for local testing.
6767
# TOR_CONTROL_PORT=9051
6868
# TOR_PASSWORD=
6969
# HIDDEN_SERVICE_PORT=80
70+
71+
# --- I2P (Optional) ---
72+
# To enable I2P, use: ./scripts/start_with_i2p
73+
# I2P tunnel configuration lives in i2p/tunnels.conf and i2p/i2pd.conf.
74+
# No application-level env vars are needed; the i2pd sidecar handles everything.

CONFIGURATION.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,24 @@ The following environment variables can be set:
5858
| DEBUG | Debugging filter | |
5959
| ZEBEDEE_API_KEY | Zebedee Project API Key | |
6060

61+
## I2P
62+
63+
I2P support is provided as a sidecar container (i2pd) via `docker-compose.i2p.yml`, mirroring the Tor setup. No application-level environment variables are needed — the i2pd container creates an I2P server tunnel that forwards traffic to nostream's WebSocket port.
64+
65+
Configuration files live in the `i2p/` directory:
66+
67+
| File | Description |
68+
|------|-------------|
69+
| `i2p/tunnels.conf` | Defines the I2P server tunnel pointing at nostream (port 8008). |
70+
| `i2p/i2pd.conf` | Minimal i2pd daemon configuration. |
71+
72+
Tunnel keys are persisted at `.nostr/i2p/data/` so the `.b32.i2p` address survives container restarts.
73+
74+
The i2pd web console (tunnel status, `.b32.i2p` destinations) is published to the host on **`127.0.0.1:7070`** only. Remove the `ports:` mapping in `docker-compose.i2p.yml` to disable host-side access.
75+
76+
- Start with I2P: `./scripts/start_with_i2p`
77+
- Print hostname hints: `./scripts/print_i2p_hostname`
78+
6179
If you've set READ_REPLICAS to 4, you should configure RR0_ through RR3_.
6280

6381
# Settings

README.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,16 @@ Print the Tor hostname:
234234
./scripts/print_tor_hostname
235235
```
236236
237+
Start with I2P:
238+
```
239+
./scripts/start_with_i2p
240+
```
241+
242+
Print the I2P hostname:
243+
```
244+
./scripts/print_i2p_hostname
245+
```
246+
237247
### Importing events from JSON Lines
238248
239249
You can import NIP-01 events from a `.jsonl` file directly into the relay database.
@@ -626,7 +636,7 @@ To observe client and subscription counts in real-time during a test, you can in
626636
```bash
627637
docker compose logs -f nostream
628638
```
629-
=======
639+
630640
## Export Events
631641

632642
Export all stored events to a [JSON Lines](https://jsonlines.org/) (`.jsonl`) file. Each line is a valid NIP-01 Nostr event JSON object. The export streams rows from the database using cursors, so it works safely on relays with millions of events without loading them into memory.

docker-compose.i2p.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
services:
2+
i2pd:
3+
image: purplei2p/i2pd:release-2.59.0
4+
container_name: i2pd
5+
depends_on:
6+
- nostream
7+
volumes:
8+
- ${PWD}/.nostr/i2p/data:/home/i2pd/data
9+
- ${PWD}/i2p/i2pd.conf:/home/i2pd/data/i2pd.conf:ro
10+
- ${PWD}/i2p/tunnels.conf:/home/i2pd/data/tunnels.conf:ro
11+
ports:
12+
# i2pd web console — bound to 127.0.0.1 on the host so operators can
13+
# look up the .b32.i2p destination without exposing router state
14+
# to the LAN. Remove this mapping to disable host-side access.
15+
- 127.0.0.1:7070:7070
16+
restart: on-failure
17+
networks:
18+
default:
19+
ipv4_address: 10.10.10.252

docker-compose.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ services:
7575
restart: on-failure
7676
networks:
7777
default:
78+
ipv4_address: 10.10.10.2
7879

7980
nostream-db:
8081
image: postgres:15

i2p/i2pd.conf

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Minimal i2pd configuration for nostream.
2+
# Data and keys are persisted via the Docker volume mount at /home/i2pd/data.
3+
4+
[http]
5+
# Bind the web console on all container interfaces so Docker port forwarding
6+
# (127.0.0.1:7070 on the host) can reach it. Host binding is restricted in
7+
# docker-compose.i2p.yml.
8+
address = 0.0.0.0
9+
port = 7070
10+
# Accept requests whose Host header is 127.0.0.1 (port-forwarded) or the
11+
# container's IP. Without this, i2pd returns a "host mismatch" error.
12+
strictheaders = false
13+
14+
[limits]
15+
transittunnels = 256
16+
17+
[precomputation]
18+
elgamal = true

i2p/tunnels.conf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
[nostream]
2+
type = http
3+
host = 10.10.10.2
4+
port = 8008
5+
keys = nostream.dat

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@
5858
"tor:docker:compose:start": "./scripts/start_with_tor",
5959
"tor:hostname": "./scripts/print_tor_hostname",
6060
"tor:docker:compose:stop": "./scripts/stop",
61+
"i2p:docker:compose:start": "./scripts/start_with_i2p",
62+
"i2p:hostname": "./scripts/print_i2p_hostname",
63+
"i2p:docker:compose:stop": "./scripts/stop",
6164
"docker:integration:run": "docker compose -f ./test/integration/docker-compose.yml run --rm tests",
6265
"docker:test:integration": "npm run docker:integration:run -- npm run test:integration",
6366
"docker:cover:integration": "npm run docker:integration:run -- npm run cover:integration",

scripts/print_i2p_hostname

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#!/bin/bash
2+
set -euo pipefail
3+
4+
PROJECT_ROOT="$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")/.."
5+
KEYS_FILE="${PROJECT_ROOT}/.nostr/i2p/data/nostream.dat"
6+
7+
if [ ! -f "${KEYS_FILE}" ]; then
8+
echo "I2P destination keys not found. Is the i2pd container running?"
9+
echo "Expected: ${KEYS_FILE}"
10+
exit 1
11+
fi
12+
13+
# The .b32.i2p address is derived from a SHA-256 hash of the Destination
14+
# inside nostream.dat, so we cannot compute it portably from the host.
15+
# Query the running i2pd container instead.
16+
echo "I2P destination keys exist at: ${KEYS_FILE}"
17+
echo ""
18+
echo "To find your nostream .b32.i2p address, use one of these methods:"
19+
echo " 1. Open the i2pd web console: http://127.0.0.1:7070/?page=i2p_tunnels"
20+
echo " (published by docker-compose.i2p.yml, bound to 127.0.0.1 only)"
21+
echo " 2. Query the console from inside the container:"
22+
echo " docker exec i2pd wget -qO- 'http://127.0.0.1:7070/?page=i2p_tunnels' \\"
23+
echo " | grep -oE '[a-z2-7]{52}\\.b32\\.i2p' | sort -u"

scripts/start_with_i2p

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#!/bin/bash
2+
set -euo pipefail
3+
4+
PROJECT_ROOT="$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")/.."
5+
DOCKER_COMPOSE_FILE="${PROJECT_ROOT}/docker-compose.yml"
6+
DOCKER_COMPOSE_I2P_FILE="${PROJECT_ROOT}/docker-compose.i2p.yml"
7+
I2P_DATA_DIR="${PROJECT_ROOT}/.nostr/i2p/data"
8+
NOSTR_CONFIG_DIR="${PROJECT_ROOT}/.nostr"
9+
SETTINGS_FILE="${NOSTR_CONFIG_DIR}/settings.yaml"
10+
DEFAULT_SETTINGS_FILE="${PROJECT_ROOT}/resources/default-settings.yaml"
11+
CURRENT_DIR="$(pwd)"
12+
13+
if [[ ${CURRENT_DIR} =~ /scripts$ ]]; then
14+
echo "Please run this script from the Nostream root folder, not the scripts directory."
15+
echo "To do this, change up one directory, and then run the following command:"
16+
echo "./scripts/start_with_i2p"
17+
exit 1
18+
fi
19+
20+
if [ "$EUID" -eq 0 ]; then
21+
echo "Error: Nostream should not be run as root."
22+
exit 1
23+
fi
24+
25+
if [[ ! -d "${NOSTR_CONFIG_DIR}" ]]; then
26+
echo "Creating folder ${NOSTR_CONFIG_DIR}"
27+
mkdir -p "${NOSTR_CONFIG_DIR}"
28+
fi
29+
30+
if [[ ! -f "${SETTINGS_FILE}" ]]; then
31+
echo "Copying ${DEFAULT_SETTINGS_FILE} to ${SETTINGS_FILE}"
32+
cp "${DEFAULT_SETTINGS_FILE}" "${SETTINGS_FILE}"
33+
fi
34+
35+
mkdir -p "${I2P_DATA_DIR}"
36+
37+
docker compose \
38+
-f "${DOCKER_COMPOSE_FILE}" \
39+
-f "${DOCKER_COMPOSE_I2P_FILE}" \
40+
up --build --remove-orphans "$@"

0 commit comments

Comments
 (0)