@le-space/rootfs 0.1.52 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -1
- package/index.d.ts +6 -1
- package/index.js +71 -31
- package/package.json +1 -1
- package/reference/orbitdb-relay-pinner/contract.json +70 -0
- package/reference/orbitdb-relay-pinner/rootfs/Dockerfile.rootfs +19 -0
- package/reference/orbitdb-relay-pinner/rootfs/build-rootfs-image.sh +335 -0
- package/reference/orbitdb-relay-pinner/rootfs/build-rootfs.sh +521 -0
- package/reference/orbitdb-relay-pinner/rootfs/orbitdb-relay-pinner-autotls-refresh.py +224 -0
- package/reference/orbitdb-relay-pinner/rootfs/orbitdb-relay-pinner-autotls-refresh.service +24 -0
- package/reference/orbitdb-relay-pinner/rootfs/orbitdb-relay-pinner-bootstrap.conf +2 -0
- package/reference/orbitdb-relay-pinner/rootfs/orbitdb-relay-pinner-bootstrap.service +21 -0
- package/reference/orbitdb-relay-pinner/rootfs/orbitdb-relay-pinner-bootstrap.sh +121 -0
- package/reference/orbitdb-relay-pinner/rootfs/orbitdb-relay-pinner-configure.sh +240 -0
- package/reference/orbitdb-relay-pinner/rootfs/orbitdb-relay-pinner-describe.py +165 -0
- package/reference/orbitdb-relay-pinner/rootfs/orbitdb-relay-pinner-setup-server.py +237 -0
- package/reference/orbitdb-relay-pinner/rootfs/read-rootfs-contract.py +72 -0
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
import json
|
|
3
|
+
import os
|
|
4
|
+
import subprocess
|
|
5
|
+
import time
|
|
6
|
+
import urllib.error
|
|
7
|
+
import urllib.request
|
|
8
|
+
from typing import Iterable
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
ENV_FILE = os.environ.get("ENV_FILE", "/etc/default/orbitdb-relay-pinner")
|
|
12
|
+
READY_FILE = os.environ.get("READY_FILE", "/etc/default/orbitdb-relay-pinner.ready")
|
|
13
|
+
AUTOTLS_READY_FILE = os.environ.get(
|
|
14
|
+
"AUTOTLS_READY_FILE", "/etc/default/orbitdb-relay-pinner.autotls-ready"
|
|
15
|
+
)
|
|
16
|
+
AUTOTLS_ZONE_FILE = os.environ.get("AUTOTLS_ZONE_FILE", "/etc/default/orbitdb-relay-pinner.autotls-zone")
|
|
17
|
+
AUTOTLS_HOSTS_FILE = os.environ.get("AUTOTLS_HOSTS_FILE", "/etc/default/orbitdb-relay-pinner.autotls-hosts")
|
|
18
|
+
AUTOTLS_CADDY_READY_FILE = os.environ.get(
|
|
19
|
+
"AUTOTLS_CADDY_READY_FILE", "/etc/default/orbitdb-relay-pinner.caddy-ready"
|
|
20
|
+
)
|
|
21
|
+
SERVICE_NAME = os.environ.get("SERVICE_NAME", "orbitdb-relay-pinner.service")
|
|
22
|
+
CADDY_SERVICE = os.environ.get("CADDY_SERVICE", "caddy.service")
|
|
23
|
+
CADDYFILE = os.environ.get("CADDYFILE", "/etc/caddy/Caddyfile")
|
|
24
|
+
METRICS_PORT = int(os.environ.get("METRICS_PORT", "9090"))
|
|
25
|
+
WAIT_TIMEOUT_SECONDS = int(os.environ.get("AUTOTLS_WAIT_TIMEOUT_SECONDS", "900"))
|
|
26
|
+
WAIT_INTERVAL_SECONDS = float(os.environ.get("AUTOTLS_WAIT_INTERVAL_SECONDS", "5"))
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def fetch_json(path: str) -> dict:
|
|
30
|
+
url = f"http://127.0.0.1:{METRICS_PORT}{path}"
|
|
31
|
+
with urllib.request.urlopen(url, timeout=5) as response:
|
|
32
|
+
return json.loads(response.read().decode("utf-8"))
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def parse_env_file(path: str) -> dict[str, str]:
|
|
36
|
+
values: dict[str, str] = {}
|
|
37
|
+
if not os.path.exists(path):
|
|
38
|
+
return values
|
|
39
|
+
|
|
40
|
+
with open(path, encoding="utf-8") as handle:
|
|
41
|
+
for line in handle:
|
|
42
|
+
stripped = line.strip()
|
|
43
|
+
if not stripped or stripped.startswith("#") or "=" not in stripped:
|
|
44
|
+
continue
|
|
45
|
+
key, value = stripped.split("=", 1)
|
|
46
|
+
values[key.strip()] = value.strip()
|
|
47
|
+
return values
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def write_env_var(path: str, key: str, value: str) -> None:
|
|
51
|
+
lines: list[str] = []
|
|
52
|
+
replaced = False
|
|
53
|
+
|
|
54
|
+
if os.path.exists(path):
|
|
55
|
+
with open(path, encoding="utf-8") as handle:
|
|
56
|
+
lines = handle.readlines()
|
|
57
|
+
|
|
58
|
+
with open(path, "w", encoding="utf-8") as handle:
|
|
59
|
+
for line in lines:
|
|
60
|
+
stripped = line.lstrip()
|
|
61
|
+
if stripped.startswith(f"{key}=") or stripped.startswith(f"#{key}="):
|
|
62
|
+
handle.write(f"{key}={value}\n")
|
|
63
|
+
replaced = True
|
|
64
|
+
else:
|
|
65
|
+
handle.write(line)
|
|
66
|
+
|
|
67
|
+
if not replaced:
|
|
68
|
+
handle.write(f"{key}={value}\n")
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def normalize_addr(addr: str) -> str:
|
|
72
|
+
parts = addr.strip().split("/")
|
|
73
|
+
if len(parts) >= 3 and parts[-2] == "p2p":
|
|
74
|
+
return "/".join(parts[:-2])
|
|
75
|
+
return addr.strip()
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def dedupe(sequence: Iterable[str]) -> list[str]:
|
|
79
|
+
seen: set[str] = set()
|
|
80
|
+
values: list[str] = []
|
|
81
|
+
for item in sequence:
|
|
82
|
+
if item and item not in seen:
|
|
83
|
+
seen.add(item)
|
|
84
|
+
values.append(item)
|
|
85
|
+
return values
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def ipv4_domain(ipv4: str, zone: str) -> str:
|
|
89
|
+
return f"{ipv4.replace('.', '-')}.{zone}"
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def ipv6_domain(ipv6: str, zone: str) -> str:
|
|
93
|
+
subdomain = ipv6.replace(":", "-")
|
|
94
|
+
if subdomain.startswith("-"):
|
|
95
|
+
subdomain = f"0{subdomain}"
|
|
96
|
+
if subdomain.endswith("-"):
|
|
97
|
+
subdomain = f"{subdomain}0"
|
|
98
|
+
return f"{subdomain}.{zone}"
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def wait_for_autotls_zone() -> str:
|
|
102
|
+
deadline = time.monotonic() + WAIT_TIMEOUT_SECONDS
|
|
103
|
+
last_error = "metrics endpoint never became ready"
|
|
104
|
+
|
|
105
|
+
while time.monotonic() < deadline:
|
|
106
|
+
try:
|
|
107
|
+
health = fetch_json("/health")
|
|
108
|
+
payload = fetch_json("/multiaddrs")
|
|
109
|
+
zone = health.get("autoTlsServingZone")
|
|
110
|
+
all_addrs = payload.get("all")
|
|
111
|
+
if (
|
|
112
|
+
isinstance(zone, str)
|
|
113
|
+
and zone
|
|
114
|
+
and isinstance(all_addrs, list)
|
|
115
|
+
and any(isinstance(addr, str) and "/tls/ws" in addr for addr in all_addrs)
|
|
116
|
+
):
|
|
117
|
+
return zone
|
|
118
|
+
last_error = "AutoTLS secure websocket multiaddrs not advertised yet"
|
|
119
|
+
except (urllib.error.URLError, TimeoutError, json.JSONDecodeError) as error:
|
|
120
|
+
last_error = str(error)
|
|
121
|
+
|
|
122
|
+
time.sleep(WAIT_INTERVAL_SECONDS)
|
|
123
|
+
|
|
124
|
+
raise RuntimeError(last_error)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def build_secure_addrs(env_values: dict[str, str], zone: str) -> list[str]:
|
|
128
|
+
ws_port = env_values.get("EXTERNAL_RELAY_WS_PORT", "").strip()
|
|
129
|
+
if not ws_port:
|
|
130
|
+
raise RuntimeError("missing EXTERNAL_RELAY_WS_PORT in environment file")
|
|
131
|
+
|
|
132
|
+
addrs: list[str] = []
|
|
133
|
+
|
|
134
|
+
public_ipv4 = env_values.get("PUBLIC_IPV4", "").strip()
|
|
135
|
+
if public_ipv4:
|
|
136
|
+
host4 = ipv4_domain(public_ipv4, zone)
|
|
137
|
+
addrs.append(f"/ip4/{public_ipv4}/tcp/{ws_port}/tls/sni/{host4}/ws")
|
|
138
|
+
addrs.append(f"/dns4/{host4}/tcp/{ws_port}/tls/ws")
|
|
139
|
+
|
|
140
|
+
public_ipv6 = env_values.get("PUBLIC_IPV6", "").strip()
|
|
141
|
+
if public_ipv6:
|
|
142
|
+
host6 = ipv6_domain(public_ipv6, zone)
|
|
143
|
+
addrs.append(f"/ip6/{public_ipv6}/tcp/{ws_port}/tls/sni/{host6}/ws")
|
|
144
|
+
addrs.append(f"/dns6/{host6}/tcp/{ws_port}/tls/ws")
|
|
145
|
+
|
|
146
|
+
if not addrs:
|
|
147
|
+
raise RuntimeError("missing PUBLIC_IPV4/PUBLIC_IPV6 in environment file")
|
|
148
|
+
|
|
149
|
+
return addrs
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def secure_hosts(env_values: dict[str, str], zone: str) -> list[str]:
|
|
153
|
+
hosts: list[str] = []
|
|
154
|
+
public_ipv4 = env_values.get("PUBLIC_IPV4", "").strip()
|
|
155
|
+
if public_ipv4:
|
|
156
|
+
hosts.append(ipv4_domain(public_ipv4, zone))
|
|
157
|
+
|
|
158
|
+
public_ipv6 = env_values.get("PUBLIC_IPV6", "").strip()
|
|
159
|
+
if public_ipv6:
|
|
160
|
+
hosts.append(ipv6_domain(public_ipv6, zone))
|
|
161
|
+
|
|
162
|
+
return dedupe(hosts)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def metrics_https_public_host(env_values: dict[str, str], zone: str) -> str | None:
|
|
166
|
+
public_ipv4 = env_values.get("PUBLIC_IPV4", "").strip()
|
|
167
|
+
if public_ipv4:
|
|
168
|
+
return ipv4_domain(public_ipv4, zone)
|
|
169
|
+
|
|
170
|
+
public_ipv6 = env_values.get("PUBLIC_IPV6", "").strip()
|
|
171
|
+
if public_ipv6:
|
|
172
|
+
return ipv6_domain(public_ipv6, zone)
|
|
173
|
+
|
|
174
|
+
return None
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def main() -> None:
|
|
178
|
+
if not os.path.exists(READY_FILE):
|
|
179
|
+
raise SystemExit(f"missing ready file: {READY_FILE}")
|
|
180
|
+
|
|
181
|
+
env_values = parse_env_file(ENV_FILE)
|
|
182
|
+
zone = wait_for_autotls_zone()
|
|
183
|
+
secure_addrs = build_secure_addrs(env_values, zone)
|
|
184
|
+
exact_hosts = secure_hosts(env_values, zone)
|
|
185
|
+
metrics_host = metrics_https_public_host(env_values, zone)
|
|
186
|
+
current_value = env_values.get("VITE_APPEND_ANNOUNCE", "")
|
|
187
|
+
current_metrics_host = env_values.get("METRICS_HTTPS_PUBLIC_HOST", "").strip()
|
|
188
|
+
merged = dedupe(
|
|
189
|
+
[normalize_addr(addr) for addr in current_value.split(",") if addr.strip()] + secure_addrs
|
|
190
|
+
)
|
|
191
|
+
announce_changed = current_value.split(",") != merged
|
|
192
|
+
metrics_host_changed = bool(metrics_host) and current_metrics_host != metrics_host
|
|
193
|
+
|
|
194
|
+
announce_value = ",".join(merged)
|
|
195
|
+
write_env_var(ENV_FILE, "VITE_APPEND_ANNOUNCE", announce_value)
|
|
196
|
+
write_env_var(ENV_FILE, "AUTOTLS_SERVING_ZONE", zone)
|
|
197
|
+
if metrics_host:
|
|
198
|
+
write_env_var(ENV_FILE, "METRICS_HTTPS_PUBLIC_HOST", metrics_host)
|
|
199
|
+
|
|
200
|
+
with open(AUTOTLS_HOSTS_FILE, "w", encoding="utf-8") as handle:
|
|
201
|
+
for host in exact_hosts:
|
|
202
|
+
handle.write(f"{host}\n")
|
|
203
|
+
with open(AUTOTLS_ZONE_FILE, "w", encoding="utf-8") as handle:
|
|
204
|
+
handle.write(f"{zone}\n")
|
|
205
|
+
|
|
206
|
+
if announce_changed or metrics_host_changed:
|
|
207
|
+
subprocess.run(["systemctl", "restart", SERVICE_NAME], check=True)
|
|
208
|
+
else:
|
|
209
|
+
print("AutoTLS secure external announce addresses already present")
|
|
210
|
+
|
|
211
|
+
if env_values.get("PROXY_HOSTNAME", "").strip():
|
|
212
|
+
open(AUTOTLS_CADDY_READY_FILE, "a", encoding="utf-8").close()
|
|
213
|
+
if os.path.exists(CADDYFILE):
|
|
214
|
+
subprocess.run(["systemctl", "enable", CADDY_SERVICE], check=False)
|
|
215
|
+
subprocess.run(["systemctl", "restart", CADDY_SERVICE], check=False)
|
|
216
|
+
elif os.path.exists(AUTOTLS_CADDY_READY_FILE):
|
|
217
|
+
os.remove(AUTOTLS_CADDY_READY_FILE)
|
|
218
|
+
|
|
219
|
+
open(AUTOTLS_READY_FILE, "a", encoding="utf-8").close()
|
|
220
|
+
print(f"Updated VITE_APPEND_ANNOUNCE={announce_value}")
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
if __name__ == "__main__":
|
|
224
|
+
main()
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
[Unit]
|
|
2
|
+
Description=Persist AutoTLS secure announce addresses for orbitdb-relay-pinner
|
|
3
|
+
After=orbitdb-relay-pinner.service
|
|
4
|
+
Wants=orbitdb-relay-pinner.service
|
|
5
|
+
ConditionPathExists=/etc/default/orbitdb-relay-pinner.ready
|
|
6
|
+
ConditionPathExists=!/etc/default/orbitdb-relay-pinner.autotls-ready
|
|
7
|
+
|
|
8
|
+
[Service]
|
|
9
|
+
Type=oneshot
|
|
10
|
+
Environment=ENV_FILE=/etc/default/orbitdb-relay-pinner
|
|
11
|
+
Environment=READY_FILE=/etc/default/orbitdb-relay-pinner.ready
|
|
12
|
+
Environment=AUTOTLS_READY_FILE=/etc/default/orbitdb-relay-pinner.autotls-ready
|
|
13
|
+
Environment=AUTOTLS_ZONE_FILE=/etc/default/orbitdb-relay-pinner.autotls-zone
|
|
14
|
+
Environment=AUTOTLS_HOSTS_FILE=/etc/default/orbitdb-relay-pinner.autotls-hosts
|
|
15
|
+
Environment=AUTOTLS_CADDY_READY_FILE=/etc/default/orbitdb-relay-pinner.caddy-ready
|
|
16
|
+
Environment=SERVICE_NAME=orbitdb-relay-pinner.service
|
|
17
|
+
Environment=CADDY_SERVICE=caddy.service
|
|
18
|
+
Environment=CADDYFILE=/etc/caddy/Caddyfile
|
|
19
|
+
ExecStart=/usr/bin/python3 /usr/local/sbin/orbitdb-relay-pinner-autotls-refresh.py
|
|
20
|
+
StandardOutput=journal
|
|
21
|
+
StandardError=journal
|
|
22
|
+
|
|
23
|
+
[Install]
|
|
24
|
+
WantedBy=multi-user.target
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
[Unit]
|
|
2
|
+
Description=Temporary orbitdb-relay-pinner setup endpoint
|
|
3
|
+
Wants=network-online.target
|
|
4
|
+
After=network-online.target
|
|
5
|
+
ConditionPathExists=!/etc/default/orbitdb-relay-pinner.ready
|
|
6
|
+
|
|
7
|
+
[Service]
|
|
8
|
+
Environment=ENV_FILE=/etc/default/orbitdb-relay-pinner
|
|
9
|
+
Environment=READY_FILE=/etc/default/orbitdb-relay-pinner.ready
|
|
10
|
+
Environment=SERVICE_NAME=orbitdb-relay-pinner.service
|
|
11
|
+
Environment=BOOTSTRAP_SERVICE=orbitdb-relay-pinner-bootstrap.service
|
|
12
|
+
Environment=METADATA_FILE=/run/orbitdb-relay-pinner-setup-metadata.json
|
|
13
|
+
Environment=METADATA_ERROR_FILE=/run/orbitdb-relay-pinner-setup-metadata.error
|
|
14
|
+
ExecStart=/usr/bin/python3 /usr/local/sbin/orbitdb-relay-pinner-setup-server.py
|
|
15
|
+
StandardOutput=journal
|
|
16
|
+
StandardError=journal
|
|
17
|
+
Restart=on-failure
|
|
18
|
+
RestartSec=2s
|
|
19
|
+
|
|
20
|
+
[Install]
|
|
21
|
+
WantedBy=multi-user.target
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
INSTALL_DIR="${INSTALL_DIR:-/opt/orbitdb-relay-pinner}"
|
|
5
|
+
SERVICE_USER="${SERVICE_USER:-orbitdb-relay}"
|
|
6
|
+
DATA_DIR="${DATA_DIR:-/var/lib/orbitdb-relay-pinner}"
|
|
7
|
+
ENV_FILE="${ENV_FILE:-/etc/default/orbitdb-relay-pinner}"
|
|
8
|
+
NODE_MIN_MAJOR="${NODE_MIN_MAJOR:-22}"
|
|
9
|
+
CADDY_READY_FILE="${CADDY_READY_FILE:-/etc/default/orbitdb-relay-pinner.caddy-ready}"
|
|
10
|
+
|
|
11
|
+
if [ ! -d "${INSTALL_DIR}" ]; then
|
|
12
|
+
echo "Missing ${INSTALL_DIR}; the rootfs build did not copy orbitdb-relay-pinner."
|
|
13
|
+
exit 1
|
|
14
|
+
fi
|
|
15
|
+
|
|
16
|
+
export DEBIAN_FRONTEND=noninteractive
|
|
17
|
+
apt-get update
|
|
18
|
+
apt-get install -y ca-certificates curl gnupg python3 build-essential caddy
|
|
19
|
+
|
|
20
|
+
if ! command -v node >/dev/null 2>&1 || [ "$(node -p "process.versions.node.split('.')[0]" 2>/dev/null || echo 0)" -lt "${NODE_MIN_MAJOR}" ]; then
|
|
21
|
+
curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
|
|
22
|
+
apt-get install -y nodejs
|
|
23
|
+
fi
|
|
24
|
+
|
|
25
|
+
rm -rf /var/lib/apt/lists/*
|
|
26
|
+
|
|
27
|
+
if ! command -v node >/dev/null 2>&1; then
|
|
28
|
+
echo "Node.js ${NODE_MIN_MAJOR}+ installation failed." >&2
|
|
29
|
+
exit 1
|
|
30
|
+
fi
|
|
31
|
+
|
|
32
|
+
if ! command -v npm >/dev/null 2>&1; then
|
|
33
|
+
echo "npm is unavailable after installing Node.js." >&2
|
|
34
|
+
exit 1
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
mkdir -p "${DATA_DIR}" "$(dirname "${ENV_FILE}")"
|
|
38
|
+
|
|
39
|
+
if ! id "${SERVICE_USER}" >/dev/null 2>&1; then
|
|
40
|
+
useradd --system --home "${DATA_DIR}" --create-home --shell /usr/sbin/nologin "${SERVICE_USER}"
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
chown -R "${SERVICE_USER}:${SERVICE_USER}" "${DATA_DIR}" "${INSTALL_DIR}"
|
|
44
|
+
|
|
45
|
+
install_command="cd '${INSTALL_DIR}' && npm install --omit=dev"
|
|
46
|
+
if [ -f "${INSTALL_DIR}/pnpm-lock.yaml" ] && command -v corepack >/dev/null 2>&1; then
|
|
47
|
+
package_manager="$(
|
|
48
|
+
node -e "const fs=require('fs'); const pkg=JSON.parse(fs.readFileSync(process.argv[1], 'utf8')); process.stdout.write(pkg.packageManager || '')" \
|
|
49
|
+
"${INSTALL_DIR}/package.json" 2>/dev/null || true
|
|
50
|
+
)"
|
|
51
|
+
if [ -n "${package_manager}" ]; then
|
|
52
|
+
install_command="cd '${INSTALL_DIR}' && export COREPACK_HOME='${DATA_DIR}/.cache/corepack' && mkdir -p \"\$COREPACK_HOME\" && corepack prepare '${package_manager}' --activate && corepack pnpm install --prod --frozen-lockfile"
|
|
53
|
+
fi
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
if command -v runuser >/dev/null 2>&1; then
|
|
57
|
+
runuser -u "${SERVICE_USER}" -- env HOME="${DATA_DIR}" bash -lc "${install_command}"
|
|
58
|
+
elif command -v sudo >/dev/null 2>&1; then
|
|
59
|
+
sudo -u "${SERVICE_USER}" env HOME="${DATA_DIR}" bash -lc "${install_command}"
|
|
60
|
+
else
|
|
61
|
+
echo "Need runuser or sudo to install dependencies as ${SERVICE_USER}." >&2
|
|
62
|
+
exit 1
|
|
63
|
+
fi
|
|
64
|
+
|
|
65
|
+
# Drop toolchains and caches after dependency installation so the prebaked
|
|
66
|
+
# qcow2 reflects the runtime footprint rather than the build footprint.
|
|
67
|
+
apt-get purge -y build-essential
|
|
68
|
+
apt-get autoremove -y
|
|
69
|
+
apt-get clean
|
|
70
|
+
rm -rf /var/lib/apt/lists/*
|
|
71
|
+
rm -rf "${DATA_DIR}/.cache/corepack" "${DATA_DIR}/.npm" "${DATA_DIR}/.cache/npm"
|
|
72
|
+
rm -rf "${INSTALL_DIR}/node_modules/.cache"
|
|
73
|
+
|
|
74
|
+
mkdir -p "${INSTALL_DIR}/node_modules"
|
|
75
|
+
ln -sfn "${INSTALL_DIR}" "${INSTALL_DIR}/node_modules/orbitdb-relay-pinner"
|
|
76
|
+
|
|
77
|
+
cat > /usr/local/bin/orbitdb-relay-pinner <<'EOF'
|
|
78
|
+
#!/usr/bin/env bash
|
|
79
|
+
set -euo pipefail
|
|
80
|
+
exec /usr/bin/node /opt/orbitdb-relay-pinner/dist/cli.js "$@"
|
|
81
|
+
EOF
|
|
82
|
+
chmod 0755 /usr/local/bin/orbitdb-relay-pinner
|
|
83
|
+
|
|
84
|
+
if [ -f "${INSTALL_DIR}/deploy/orbitdb-relay-pinner.env.example" ] && [ ! -f "${ENV_FILE}" ]; then
|
|
85
|
+
cp "${INSTALL_DIR}/deploy/orbitdb-relay-pinner.env.example" "${ENV_FILE}"
|
|
86
|
+
fi
|
|
87
|
+
|
|
88
|
+
touch "${ENV_FILE}"
|
|
89
|
+
chmod 0640 "${ENV_FILE}"
|
|
90
|
+
chown "root:${SERVICE_USER}" "${ENV_FILE}"
|
|
91
|
+
rm -f "${CADDY_READY_FILE}"
|
|
92
|
+
|
|
93
|
+
mkdir -p /etc/caddy /etc/systemd/system/caddy.service.d
|
|
94
|
+
cat > /etc/systemd/system/caddy.service.d/orbitdb-relay-pinner.conf <<EOF
|
|
95
|
+
[Unit]
|
|
96
|
+
ConditionPathExists=${CADDY_READY_FILE}
|
|
97
|
+
EOF
|
|
98
|
+
|
|
99
|
+
write_env_var() {
|
|
100
|
+
local key="$1"
|
|
101
|
+
local value="$2"
|
|
102
|
+
|
|
103
|
+
if grep -Eq "^[#[:space:]]*${key}=" "${ENV_FILE}"; then
|
|
104
|
+
sed -i "s|^[#[:space:]]*${key}=.*|${key}=${value}|" "${ENV_FILE}"
|
|
105
|
+
else
|
|
106
|
+
printf '%s=%s\n' "${key}" "${value}" >> "${ENV_FILE}"
|
|
107
|
+
fi
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
write_env_var "DATASTORE_PATH" "${DATA_DIR}"
|
|
111
|
+
write_env_var "METRICS_PORT" "9090"
|
|
112
|
+
write_env_var "METRICS_HTTPS_ENABLED" "0"
|
|
113
|
+
write_env_var "RELAY_TCP_PORT" "9091"
|
|
114
|
+
write_env_var "RELAY_WS_PORT" "9092"
|
|
115
|
+
write_env_var "RELAY_WEBRTC_PORT" "9093"
|
|
116
|
+
write_env_var "RELAY_QUIC_PORT" "9094"
|
|
117
|
+
write_env_var "RELAY_DISABLE_WEBRTC" "1"
|
|
118
|
+
write_env_var "RELAY_DISABLE_BOOTSTRAP" "1"
|
|
119
|
+
write_env_var "disableAutoTLS" "1"
|
|
120
|
+
write_env_var "ENABLE_GENERAL_LOGS" "1"
|
|
121
|
+
write_env_var "DEBUG" "'libp2p:websockets:listener'"
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
ENV_FILE="${ENV_FILE:-/etc/default/orbitdb-relay-pinner}"
|
|
5
|
+
READY_FILE="${READY_FILE:-/etc/default/orbitdb-relay-pinner.ready}"
|
|
6
|
+
AUTOTLS_READY_FILE="${AUTOTLS_READY_FILE:-/etc/default/orbitdb-relay-pinner.autotls-ready}"
|
|
7
|
+
AUTOTLS_ZONE_FILE="${AUTOTLS_ZONE_FILE:-/etc/default/orbitdb-relay-pinner.autotls-zone}"
|
|
8
|
+
AUTOTLS_HOSTS_FILE="${AUTOTLS_HOSTS_FILE:-/etc/default/orbitdb-relay-pinner.autotls-hosts}"
|
|
9
|
+
SERVICE_NAME="${SERVICE_NAME:-orbitdb-relay-pinner.service}"
|
|
10
|
+
CADDY_SERVICE="${CADDY_SERVICE:-caddy.service}"
|
|
11
|
+
CADDY_READY_FILE="${CADDY_READY_FILE:-/etc/default/orbitdb-relay-pinner.caddy-ready}"
|
|
12
|
+
CADDYFILE="${CADDYFILE:-/etc/caddy/Caddyfile}"
|
|
13
|
+
CADDY_UPSTREAM_WSS_PORT="${CADDY_UPSTREAM_WSS_PORT:-9092}"
|
|
14
|
+
CADDY_UPSTREAM_HOST="${CADDY_UPSTREAM_HOST:-127.0.0.1}"
|
|
15
|
+
CADDY_UPSTREAM_METRICS_PORT="${CADDY_UPSTREAM_METRICS_PORT:-9090}"
|
|
16
|
+
AUTOTLS_REFRESH_SERVICE="${AUTOTLS_REFRESH_SERVICE:-orbitdb-relay-pinner-autotls-refresh.service}"
|
|
17
|
+
PUBLIC_IPV4=""
|
|
18
|
+
PUBLIC_IPV6=""
|
|
19
|
+
TCP_PORT=""
|
|
20
|
+
WS_PORT=""
|
|
21
|
+
PROXY_HOSTNAME=""
|
|
22
|
+
METRICS_PORT=""
|
|
23
|
+
METRICS_HTTPS_PORT=""
|
|
24
|
+
WEBRTC_PORT=""
|
|
25
|
+
QUIC_PORT=""
|
|
26
|
+
START_SERVICE=1
|
|
27
|
+
|
|
28
|
+
usage() {
|
|
29
|
+
cat <<'EOF'
|
|
30
|
+
Usage:
|
|
31
|
+
orbitdb-relay-pinner-configure.sh \
|
|
32
|
+
--public-ipv4 <ip> \
|
|
33
|
+
[--public-ipv6 <ipv6>] \
|
|
34
|
+
--tcp-port <host-port> \
|
|
35
|
+
--ws-port <host-port> \
|
|
36
|
+
[--proxy-hostname <hostname>] \
|
|
37
|
+
[--metrics-port <host-port>] \
|
|
38
|
+
[--metrics-https-port <host-port>] \
|
|
39
|
+
[--webrtc-port <host-port>] \
|
|
40
|
+
[--quic-port <host-port>] \
|
|
41
|
+
[--no-start]
|
|
42
|
+
|
|
43
|
+
Writes VITE_APPEND_ANNOUNCE for the externally assigned Aleph host ports,
|
|
44
|
+
marks the relay as ready, and optionally starts the relay plus Caddy services.
|
|
45
|
+
EOF
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
write_env_var() {
|
|
49
|
+
local key="$1"
|
|
50
|
+
local value="$2"
|
|
51
|
+
|
|
52
|
+
if grep -Eq "^[#[:space:]]*${key}=" "${ENV_FILE}"; then
|
|
53
|
+
sed -i "s|^[#[:space:]]*${key}=.*|${key}=${value}|" "${ENV_FILE}"
|
|
54
|
+
else
|
|
55
|
+
printf '%s=%s\n' "${key}" "${value}" >> "${ENV_FILE}"
|
|
56
|
+
fi
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
write_caddyfile() {
|
|
60
|
+
local hostname="$1"
|
|
61
|
+
mkdir -p "$(dirname "${CADDYFILE}")"
|
|
62
|
+
cat > "${CADDYFILE}" <<EOF
|
|
63
|
+
{
|
|
64
|
+
auto_https disable_redirects
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
${hostname} {
|
|
68
|
+
# Proxy the full orbitdb-relay-pinner HTTP API surface to the metrics/HTTP port.
|
|
69
|
+
# Everything else falls through to the relay WebSocket backend for browser libp2p.
|
|
70
|
+
handle /health {
|
|
71
|
+
reverse_proxy 127.0.0.1:${CADDY_UPSTREAM_METRICS_PORT}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
handle /multiaddrs {
|
|
75
|
+
reverse_proxy 127.0.0.1:${CADDY_UPSTREAM_METRICS_PORT}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
handle /multiaddresses {
|
|
79
|
+
reverse_proxy 127.0.0.1:${CADDY_UPSTREAM_METRICS_PORT}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
handle /metrics {
|
|
83
|
+
reverse_proxy 127.0.0.1:${CADDY_UPSTREAM_METRICS_PORT}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
handle /pinning/* {
|
|
87
|
+
reverse_proxy 127.0.0.1:${CADDY_UPSTREAM_METRICS_PORT}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
handle /ipfs/* {
|
|
91
|
+
reverse_proxy 127.0.0.1:${CADDY_UPSTREAM_METRICS_PORT}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
reverse_proxy ${CADDY_UPSTREAM_HOST}:${CADDY_UPSTREAM_WSS_PORT}
|
|
95
|
+
}
|
|
96
|
+
EOF
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
while [ "$#" -gt 0 ]; do
|
|
100
|
+
case "$1" in
|
|
101
|
+
--public-ipv4)
|
|
102
|
+
PUBLIC_IPV4="${2:-}"
|
|
103
|
+
shift 2
|
|
104
|
+
;;
|
|
105
|
+
--public-ipv6)
|
|
106
|
+
PUBLIC_IPV6="${2:-}"
|
|
107
|
+
shift 2
|
|
108
|
+
;;
|
|
109
|
+
--tcp-port)
|
|
110
|
+
TCP_PORT="${2:-}"
|
|
111
|
+
shift 2
|
|
112
|
+
;;
|
|
113
|
+
--ws-port)
|
|
114
|
+
WS_PORT="${2:-}"
|
|
115
|
+
shift 2
|
|
116
|
+
;;
|
|
117
|
+
--proxy-hostname)
|
|
118
|
+
PROXY_HOSTNAME="${2:-}"
|
|
119
|
+
shift 2
|
|
120
|
+
;;
|
|
121
|
+
--metrics-port)
|
|
122
|
+
METRICS_PORT="${2:-}"
|
|
123
|
+
shift 2
|
|
124
|
+
;;
|
|
125
|
+
--metrics-https-port)
|
|
126
|
+
METRICS_HTTPS_PORT="${2:-}"
|
|
127
|
+
shift 2
|
|
128
|
+
;;
|
|
129
|
+
--webrtc-port)
|
|
130
|
+
WEBRTC_PORT="${2:-}"
|
|
131
|
+
shift 2
|
|
132
|
+
;;
|
|
133
|
+
--quic-port)
|
|
134
|
+
QUIC_PORT="${2:-}"
|
|
135
|
+
shift 2
|
|
136
|
+
;;
|
|
137
|
+
--no-start)
|
|
138
|
+
START_SERVICE=0
|
|
139
|
+
shift
|
|
140
|
+
;;
|
|
141
|
+
-h|--help)
|
|
142
|
+
usage
|
|
143
|
+
exit 0
|
|
144
|
+
;;
|
|
145
|
+
*)
|
|
146
|
+
echo "Unknown argument: $1" >&2
|
|
147
|
+
usage >&2
|
|
148
|
+
exit 1
|
|
149
|
+
;;
|
|
150
|
+
esac
|
|
151
|
+
done
|
|
152
|
+
|
|
153
|
+
if [ -z "${PUBLIC_IPV4}" ] || [ -z "${TCP_PORT}" ] || [ -z "${WS_PORT}" ]; then
|
|
154
|
+
usage >&2
|
|
155
|
+
exit 1
|
|
156
|
+
fi
|
|
157
|
+
|
|
158
|
+
touch "${ENV_FILE}"
|
|
159
|
+
rm -f "${AUTOTLS_READY_FILE}" "${AUTOTLS_ZONE_FILE}" "${AUTOTLS_HOSTS_FILE}"
|
|
160
|
+
|
|
161
|
+
announce=(
|
|
162
|
+
"/ip4/${PUBLIC_IPV4}/tcp/${TCP_PORT}"
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
if [ -n "${PUBLIC_IPV6}" ]; then
|
|
166
|
+
announce+=(
|
|
167
|
+
"/ip6/${PUBLIC_IPV6}/tcp/${TCP_PORT}"
|
|
168
|
+
)
|
|
169
|
+
fi
|
|
170
|
+
|
|
171
|
+
if [ -n "${PROXY_HOSTNAME}" ]; then
|
|
172
|
+
announce+=("/dns4/${PROXY_HOSTNAME}/tcp/443/tls/ws")
|
|
173
|
+
announce+=("/dns6/${PROXY_HOSTNAME}/tcp/443/tls/ws")
|
|
174
|
+
else
|
|
175
|
+
announce+=("/ip4/${PUBLIC_IPV4}/tcp/${WS_PORT}/ws")
|
|
176
|
+
if [ -n "${PUBLIC_IPV6}" ]; then
|
|
177
|
+
announce+=("/ip6/${PUBLIC_IPV6}/tcp/${WS_PORT}/ws")
|
|
178
|
+
fi
|
|
179
|
+
fi
|
|
180
|
+
|
|
181
|
+
if [ -n "${WEBRTC_PORT}" ]; then
|
|
182
|
+
announce+=("/ip4/${PUBLIC_IPV4}/udp/${WEBRTC_PORT}/webrtc-direct")
|
|
183
|
+
if [ -n "${PUBLIC_IPV6}" ]; then
|
|
184
|
+
announce+=("/ip6/${PUBLIC_IPV6}/udp/${WEBRTC_PORT}/webrtc-direct")
|
|
185
|
+
fi
|
|
186
|
+
fi
|
|
187
|
+
|
|
188
|
+
if [ -n "${QUIC_PORT}" ]; then
|
|
189
|
+
announce+=("/ip4/${PUBLIC_IPV4}/udp/${QUIC_PORT}/quic-v1")
|
|
190
|
+
if [ -n "${PUBLIC_IPV6}" ]; then
|
|
191
|
+
announce+=("/ip6/${PUBLIC_IPV6}/udp/${QUIC_PORT}/quic-v1")
|
|
192
|
+
fi
|
|
193
|
+
fi
|
|
194
|
+
|
|
195
|
+
announce_value="$(IFS=,; printf '%s' "${announce[*]}")"
|
|
196
|
+
write_env_var "VITE_APPEND_ANNOUNCE" "${announce_value}"
|
|
197
|
+
write_env_var "PUBLIC_IPV4" "${PUBLIC_IPV4}"
|
|
198
|
+
if [ -n "${PUBLIC_IPV6}" ]; then
|
|
199
|
+
write_env_var "PUBLIC_IPV6" "${PUBLIC_IPV6}"
|
|
200
|
+
fi
|
|
201
|
+
write_env_var "EXTERNAL_RELAY_TCP_PORT" "${TCP_PORT}"
|
|
202
|
+
write_env_var "EXTERNAL_RELAY_WS_PORT" "${WS_PORT}"
|
|
203
|
+
if [ -n "${PROXY_HOSTNAME}" ]; then
|
|
204
|
+
write_env_var "PROXY_HOSTNAME" "${PROXY_HOSTNAME}"
|
|
205
|
+
else
|
|
206
|
+
write_env_var "PROXY_HOSTNAME" ""
|
|
207
|
+
fi
|
|
208
|
+
if [ -n "${METRICS_PORT}" ]; then
|
|
209
|
+
write_env_var "EXTERNAL_METRICS_PORT" "${METRICS_PORT}"
|
|
210
|
+
fi
|
|
211
|
+
if [ -n "${METRICS_HTTPS_PORT}" ]; then
|
|
212
|
+
write_env_var "EXTERNAL_METRICS_HTTPS_PORT" "${METRICS_HTTPS_PORT}"
|
|
213
|
+
fi
|
|
214
|
+
if [ -n "${WEBRTC_PORT}" ]; then
|
|
215
|
+
write_env_var "EXTERNAL_RELAY_WEBRTC_PORT" "${WEBRTC_PORT}"
|
|
216
|
+
fi
|
|
217
|
+
if [ -n "${QUIC_PORT}" ]; then
|
|
218
|
+
write_env_var "EXTERNAL_RELAY_QUIC_PORT" "${QUIC_PORT}"
|
|
219
|
+
fi
|
|
220
|
+
touch "${READY_FILE}"
|
|
221
|
+
|
|
222
|
+
if [ "${START_SERVICE}" -eq 1 ]; then
|
|
223
|
+
systemctl daemon-reload
|
|
224
|
+
systemctl enable "${SERVICE_NAME}"
|
|
225
|
+
systemctl restart "${SERVICE_NAME}"
|
|
226
|
+
systemctl enable "${AUTOTLS_REFRESH_SERVICE}"
|
|
227
|
+
if [ -n "${PROXY_HOSTNAME}" ]; then
|
|
228
|
+
write_caddyfile "${PROXY_HOSTNAME}"
|
|
229
|
+
touch "${CADDY_READY_FILE}"
|
|
230
|
+
systemctl enable "${CADDY_SERVICE}"
|
|
231
|
+
systemctl restart "${CADDY_SERVICE}"
|
|
232
|
+
else
|
|
233
|
+
rm -f "${CADDY_READY_FILE}"
|
|
234
|
+
systemctl stop "${CADDY_SERVICE}" || true
|
|
235
|
+
fi
|
|
236
|
+
systemctl restart --no-block "${AUTOTLS_REFRESH_SERVICE}"
|
|
237
|
+
fi
|
|
238
|
+
|
|
239
|
+
printf 'Configured VITE_APPEND_ANNOUNCE=%s\n' "${announce_value}"
|
|
240
|
+
printf 'Ready file: %s\n' "${READY_FILE}"
|