forked from Snipa22/nodejs-pool
-
Notifications
You must be signed in to change notification settings - Fork 76
Expand file tree
/
Copy pathdeploy.bash
More file actions
651 lines (598 loc) · 25.1 KB
/
deploy.bash
File metadata and controls
651 lines (598 loc) · 25.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
#!/bin/bash -ex
NODEJS_VERSION="${NODEJS_VERSION:-v24.15.0}"
WWW_DNS="${WWW_DNS:-moneroocean.stream}"
API_DNS="${API_DNS:-api.moneroocean.stream}"
CF_DNS_API_TOKEN="${CF_DNS_API_TOKEN:-n/a}"
CERTBOT_EMAIL="${CERTBOT_EMAIL:-support@moneroocean.stream}"
TARI_RELEASE_TAG="${TARI_RELEASE_TAG:-v5.3.0}"
TARI_NETWORK="${TARI_NETWORK:-mainnet}"
TARI_INSTALL_DIR="${TARI_INSTALL_DIR:-/usr/local/src/tari}"
TARI_USER="${TARI_USER:-taridaemon}"
TARI_HOME="${TARI_HOME:-/home/$TARI_USER}"
TARI_CONFIG_PATCH_URL="${TARI_CONFIG_PATCH_URL:-https://raw.githubusercontent.com/MoneroOcean/nodejs-pool/master/deployment/patch-tari-config.sh}"
TARI_WALLET_PAYMENT_ADDRESS="${TARI_WALLET_PAYMENT_ADDRESS:-12FrDe5cUauXdMeCiG1DU3XQZdShjFd9A4p9agxsddVyAwpmz73x4b2Qdy5cPYaGmKNZ6g1fbCASJpPxnjubqjvHDa5}"
if [ "$(id -u)" -ne 0 ]; then
echo "Please run this script as root"
exit 1
fi
if [ "$#" -gt 0 ]; then
echo "Please configure deploy.bash with environment variables: WWW_DNS, API_DNS, CF_DNS_API_TOKEN, CERTBOT_EMAIL"
exit 1
fi
if [ -n "${TARI_EXTERNAL_IP+x}" ]; then
echo "deploy.bash does not support TARI_EXTERNAL_IP; it is only for leaf.bash external base node gRPC"
exit 1
fi
export DEBIAN_FRONTEND=noninteractive
DEPLOY_SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
retry_command() { for i in 1 2 3 4 5; do "$@" && return 0; [ "$i" = 5 ] || sleep $((i * 5)); done; return 1; }
clone_repo_once() {
local repo="$1"
local dest="$2"
if [ -d "$dest/.git" ]; then
return 0
fi
retry_command git clone "$repo" "$dest"
}
configure_overcommit() {
install -d -m 755 /etc/sysctl.d
cat >/etc/sysctl.d/90-monero-overcommit.conf <<'EOF'
vm.overcommit_memory = 2
vm.overcommit_ratio = 150
EOF
if ! sysctl -p /etc/sysctl.d/90-monero-overcommit.conf; then
if [ "${POOL_DEPLOY_TEST_MODE:-0}" = "1" ]; then
echo "Skipping active overcommit sysctl apply in test mode"
return 0
fi
return 1
fi
}
configure_swap() {
if [ ! -f /swapfile ] || [ "$(stat -c %s /swapfile 2>/dev/null || echo 0)" -lt 1073741824 ]; then
rm -f /swapfile
fallocate -l 1G /swapfile || dd if=/dev/zero of=/swapfile bs=1M count=1024
fi
chmod 600 /swapfile
if ! awk 'NR > 1 && $1 == "/swapfile" {found = 1} END {exit found ? 0 : 1}' /proc/swaps; then
mkswap -f /swapfile
chmod 600 /swapfile
if [ "$(awk 'NR > 1 {total += $3} END {print total + 0}' /proc/swaps)" -eq 0 ]; then
if ! swapon /swapfile; then
if [ "${POOL_DEPLOY_TEST_MODE:-0}" = "1" ]; then
echo "Skipping active swap enable in test mode"
else
return 1
fi
fi
fi
fi
if ! grep -Eq '^[^#]*[[:space:]]/swapfile[[:space:]]' /etc/fstab; then
echo " /swapfile none swap sw 0 0" >>/etc/fstab
fi
}
default_tari_memory_high() {
local mem_kb
mem_kb="$(awk '/MemTotal:/ {print $2}' /proc/meminfo)"
if [ "$mem_kb" -ge $((30 * 1024 * 1024)) ]; then
echo 18G
else
echo 12G
fi
}
TARI_MEMORY_HIGH="${TARI_MEMORY_HIGH:-$(default_tari_memory_high)}"
TARI_MEMORY_SWAP_MAX="${TARI_MEMORY_SWAP_MAX:-768M}"
TARI_MM_MEMORY_HIGH="${TARI_MM_MEMORY_HIGH:-1200M}"
TARI_MM_MEMORY_SWAP_MAX="${TARI_MM_MEMORY_SWAP_MAX:-384M}"
HUGEPAGES_GROUP="${HUGEPAGES_GROUP:-hugepages}"
MONERO_RANDOMX_HUGEPAGES="${MONERO_RANDOMX_HUGEPAGES:-384}"
MONERO_LOG_CATEGORIES="${MONERO_LOG_CATEGORIES:-*:ERROR,cn:ERROR,blockchain:ERROR,verify:ERROR}"
MONERO_PATCH_STAGING_DIR="${MONERO_PATCH_STAGING_DIR:-/usr/local/src/monero-patches}"
MONERO_PATCH_SCRIPT_URL="${MONERO_PATCH_SCRIPT_URL:-https://raw.githubusercontent.com/MoneroOcean/nodejs-pool/master/deployment/apply-monero-patches.sh}"
MONERO_TARI_MM_RESERVE_PATCH="${MONERO_TARI_MM_RESERVE_PATCH:-monero-tari-mm-reserve.patch}"
MONERO_TARI_MM_RESERVE_PATCH_URL="${MONERO_TARI_MM_RESERVE_PATCH_URL:-https://raw.githubusercontent.com/MoneroOcean/nodejs-pool/master/deployment/patches/$MONERO_TARI_MM_RESERVE_PATCH}"
rpc_synced() {
local url="$1"
local method="$2"
local response
response="$(curl -fsS -H 'Content-Type: application/json' --data "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"$method\",\"params\":{}}" "$url")" || return 1
printf '%s' "$response" | python3 -c '
import json
import sys
method = sys.argv[1]
payload = json.load(sys.stdin)
result = payload.get("result") or {}
if method == "get_info":
sys.exit(0 if result.get("status") == "OK" and result.get("synchronized") is True and result.get("busy_syncing") is not True else 1)
if method == "GetTipInfo":
metadata = result.get("metadata") or {}
synced = result.get("initial_sync_achieved")
height = int(metadata.get("best_block_height") or 0)
sys.exit(0 if synced is True and height > 0 else 1)
sys.exit(1)
' "$method"
}
wait_for_monero_sync() {
echo "Please wait until Monero daemon is fully synced"
for _ in $(seq 1 360); do
if rpc_synced http://127.0.0.1:18083/json_rpc get_info; then
echo "Monero daemon is synced"
return 0
fi
sleep 10
done
echo "Timed out waiting for Monero daemon sync" >&2
return 1
}
wait_for_tari_sync() {
echo "Please wait until Tari daemon is fully synced"
for _ in $(seq 1 360); do
if rpc_synced http://127.0.0.1:18146/json_rpc GetTipInfo; then
echo "Tari daemon is synced"
return 0
fi
sleep 10
done
echo "Timed out waiting for Tari daemon sync" >&2
return 1
}
tari_release_arch() {
case "${TARI_RELEASE_ARCH:-$(uname -m)}" in
x86_64|amd64) echo x86_64 ;;
aarch64|arm64) echo arm64 ;;
*) echo "Unsupported Tari release architecture: ${TARI_RELEASE_ARCH:-$(uname -m)}" >&2; return 1 ;;
esac
}
tari_release_url() {
local arch version api_url
arch="$(tari_release_arch)"
version="${TARI_RELEASE_TAG#v}"
api_url="https://api.github.com/repos/tari-project/tari/releases/tags/$TARI_RELEASE_TAG"
python3 - "$api_url" "$version" "$TARI_NETWORK" "$arch" <<'PY'
import json
import re
import sys
import urllib.request
api_url, version, network, arch = sys.argv[1:]
with urllib.request.urlopen(api_url) as response:
release = json.load(response)
pattern = re.compile(rf"^tari_suite-{re.escape(version)}-{re.escape(network)}-[^-]+-linux-{re.escape(arch)}\.zip$")
matches = [asset for asset in release.get("assets", []) if pattern.match(asset.get("name", ""))]
if len(matches) != 1:
names = ", ".join(asset.get("name", "") for asset in release.get("assets", []))
raise SystemExit(f"Expected one Tari {network} linux-{arch} asset for {version}, found {len(matches)}. Assets: {names}")
print(matches[0]["browser_download_url"])
PY
}
install_tari_suite() {
local tmp_zip release_url
if [ -x "$TARI_INSTALL_DIR/minotari_node" ] && [ -x "$TARI_INSTALL_DIR/minotari_merge_mining_proxy" ]; then
if [ ! -f "$TARI_HOME/.tari/mainnet/config/config.toml" ]; then
sudo -u "$TARI_USER" env HOME="$TARI_HOME" "$TARI_INSTALL_DIR/minotari_node" --init --network mainnet --non-interactive-mode --disable-splash-screen
fi
return 0
fi
rm -rf "$TARI_INSTALL_DIR"
install -d "$TARI_INSTALL_DIR"
tmp_zip="$(mktemp)"
release_url="$(tari_release_url)"
retry_command curl -fsSL -o "$tmp_zip" "$release_url"
unzip -q "$tmp_zip" -d "$TARI_INSTALL_DIR"
rm -f "$tmp_zip"
chmod 755 "$TARI_INSTALL_DIR"/minotari_*
sudo -u "$TARI_USER" env HOME="$TARI_HOME" "$TARI_INSTALL_DIR/minotari_node" --init --network mainnet --non-interactive-mode --disable-splash-screen
}
patch_tari_config() {
local patcher="/usr/local/src/patch-tari-config.sh"
local config="$TARI_HOME/.tari/mainnet/config/config.toml"
local args=("$config" "--no-backup")
retry_command curl -fsSL -o "$patcher" "$TARI_CONFIG_PATCH_URL"
chmod 755 "$patcher"
args+=("--wallet-payment-address" "$TARI_WALLET_PAYMENT_ADDRESS")
"$patcher" "${args[@]}"
chown "$TARI_USER:$TARI_USER" "$config"
}
install_monero_patch_files() {
install -d -m 755 "$MONERO_PATCH_STAGING_DIR/patches"
if [ -f "$DEPLOY_SCRIPT_DIR/apply-monero-patches.sh" ]; then
install -m 755 "$DEPLOY_SCRIPT_DIR/apply-monero-patches.sh" "$MONERO_PATCH_STAGING_DIR/apply-monero-patches.sh"
else
retry_command curl -fsSL -o "$MONERO_PATCH_STAGING_DIR/apply-monero-patches.sh" "$MONERO_PATCH_SCRIPT_URL"
chmod 755 "$MONERO_PATCH_STAGING_DIR/apply-monero-patches.sh"
fi
if [ -f "$DEPLOY_SCRIPT_DIR/patches/$MONERO_TARI_MM_RESERVE_PATCH" ]; then
install -m 644 "$DEPLOY_SCRIPT_DIR/patches/$MONERO_TARI_MM_RESERVE_PATCH" "$MONERO_PATCH_STAGING_DIR/patches/$MONERO_TARI_MM_RESERVE_PATCH"
else
retry_command curl -fsSL -o "$MONERO_PATCH_STAGING_DIR/patches/$MONERO_TARI_MM_RESERVE_PATCH" "$MONERO_TARI_MM_RESERVE_PATCH_URL"
fi
}
apply_monero_patches() {
install_monero_patch_files
"$MONERO_PATCH_STAGING_DIR/apply-monero-patches.sh" /usr/local/src/monero
}
monero_patch_hash() {
sha256sum "$MONERO_PATCH_STAGING_DIR/patches/$MONERO_TARI_MM_RESERVE_PATCH" | awk '{print $1}'
}
monero_patch_stamp_file() {
echo /usr/local/src/monero/build/release/.moneroocean-tari-mm-reserve.patch.sha256
}
monero_patch_build_is_current() {
[ -x /usr/local/src/monero/build/release/bin/monerod ] &&
[ "$(cat "$(monero_patch_stamp_file)" 2>/dev/null || true)" = "$(monero_patch_hash)" ]
}
record_monero_patch_build() {
install -d -m 755 /usr/local/src/monero/build/release
monero_patch_hash >"$(monero_patch_stamp_file)"
}
build_monero_release() {
USE_SINGLE_BUILDDIR=1 make -j$(nproc) release || USE_SINGLE_BUILDDIR=1 make -j1 release
record_monero_patch_build
}
ensure_tari_user() {
id -u "$TARI_USER" >/dev/null 2>&1 || useradd -m -d "$TARI_HOME" -s /bin/sh "$TARI_USER"
install -d -m 755 -o "$TARI_USER" -g "$TARI_USER" "$TARI_HOME"
}
configure_monero_hugepages() {
local gid
groupadd --system "$HUGEPAGES_GROUP" 2>/dev/null || true
usermod -a -G "$HUGEPAGES_GROUP" monerodaemon
gid="$(getent group "$HUGEPAGES_GROUP" | cut -d: -f3)"
test -n "$gid"
install -d -m 755 /etc/sysctl.d
cat >/etc/sysctl.d/91-moneroocean-hugepages.conf <<EOF
vm.nr_hugepages = $MONERO_RANDOMX_HUGEPAGES
vm.hugetlb_shm_group = $gid
EOF
echo 1 >/proc/sys/vm/compact_memory 2>/dev/null || true
if ! sysctl -p /etc/sysctl.d/91-moneroocean-hugepages.conf; then
if [ "${POOL_DEPLOY_TEST_MODE:-0}" = "1" ]; then
echo "Skipping active hugepage sysctl apply in test mode"
return 0
fi
return 1
fi
if [ "$(sysctl -n vm.nr_hugepages)" -lt "$MONERO_RANDOMX_HUGEPAGES" ]; then
echo "Warning: requested $MONERO_RANDOMX_HUGEPAGES hugepages but only $(sysctl -n vm.nr_hugepages) are available until reboot or more memory compaction"
fi
}
install -d -m 755 /etc/needrestart/conf.d
cat >/etc/needrestart/conf.d/moneroocean-critical.conf <<'EOF'
# Keep unattended package maintenance from restarting pool-critical services.
# Operators should restart these deliberately during a maintenance window.
$nrconf{override_rc}->{qr(^mysql\.service$)} = 0;
$nrconf{override_rc}->{qr(^pm2-user\.service$)} = 0;
$nrconf{override_rc}->{qr(^monero\.service$)} = 0;
$nrconf{override_rc}->{qr(^xtm\.service$)} = 0;
$nrconf{override_rc}->{qr(^xtm_mm\.service$)} = 0;
EOF
configure_overcommit
configure_swap
retry_command apt-get -o Acquire::Retries=3 -o APT::Update::Error-Mode=any update
if [ "${POOL_DEPLOY_TEST_MODE:-0}" = "1" ]; then
echo "Skipping apt full-upgrade in test mode"
else
retry_command apt-get -o Acquire::Retries=3 full-upgrade -y
fi
retry_command apt-get -o Acquire::Retries=3 install -y ca-certificates curl wget openssl sudo ufw nginx git vim unzip python3 g++ make libc-dev cmake libssl-dev libunbound-dev libboost-filesystem-dev libboost-locale-dev libboost-program-options-dev libzmq3-dev mysql-server
timedatectl set-timezone Etc/UTC
id -u user >/dev/null 2>&1 || adduser --disabled-password --gecos "" user
grep -q "user ALL=(ALL) NOPASSWD:ALL" /etc/sudoers || echo "user ALL=(ALL) NOPASSWD:ALL" >>/etc/sudoers
install -d -m 700 -o user -g user /home/user/.ssh
if [ -f "/root/.ssh/authorized_keys" ]; then
mv /root/.ssh/authorized_keys /home/user/.ssh/authorized_keys
chown user:user /home/user/.ssh/authorized_keys
chmod 600 /home/user/.ssh/authorized_keys
sed -i 's/#\?PasswordAuthentication yes/PasswordAuthentication no/g' /etc/ssh/sshd_config
sed -i 's/#\?PermitRootLogin .\+/PermitRootLogin no/g' /etc/ssh/sshd_config
sed -i 's/#\?PermitEmptyPasswords .\+/PermitEmptyPasswords no/g' /etc/ssh/sshd_config
service ssh restart
fi
ufw default deny incoming
ufw default allow outgoing
for rule in ssh 443 18141 18189; do
ufw allow "$rule"
done
ufw --force enable
printf 'colorscheme desert\nset fo-=ro\n' >/root/.vimrc
install -m 644 -o user -g user /root/.vimrc /home/user/.vimrc
mkdir -p /etc/letsencrypt
if [ "${POOL_DEPLOY_TEST_MODE:-0}" = "1" ]; then
cat >/etc/letsencrypt/options-ssl-nginx.conf <<'EOF'
ssl_session_cache shared:le_nginx_SSL:10m;
ssl_session_timeout 1440m;
EOF
else
snap install --classic certbot
snap set certbot trust-plugin-with-root=ok
snap install certbot-dns-cloudflare
find /snap/certbot -name options-ssl-nginx.conf | xargs -I{} cp {} /etc/letsencrypt/options-ssl-nginx.conf
fi
echo "dns_cloudflare_api_token=$CF_DNS_API_TOKEN" >/root/dns_cloudflare_api_token.ini
chmod 600 /root/dns_cloudflare_api_token.ini
for dns in "$WWW_DNS" "$API_DNS"; do
if [ ! -f "/etc/letsencrypt/live/$dns/fullchain.pem" ]; then
certbot certonly --non-interactive --agree-tos --email "$CERTBOT_EMAIL" --dns-cloudflare --dns-cloudflare-propagation-seconds 30 --dns-cloudflare-credentials /root/dns_cloudflare_api_token.ini -d "$dns"
fi
done
cat >/etc/nginx/sites-enabled/default <<EOF
server {
listen 80;
location /leafApi {
proxy_pass http://localhost:8000;
proxy_redirect off;
}
gzip on;
}
limit_req_zone \$uri zone=big_api:32m rate=30r/m;
server {
listen 443 ssl;
server_name $API_DNS;
location /miner/ {
limit_req zone=big_api burst=4;
proxy_pass http://localhost:8001;
proxy_redirect off;
}
location / {
proxy_pass http://localhost:8001;
proxy_redirect off;
}
gzip on;
ssl_certificate /etc/letsencrypt/live/$API_DNS/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/$API_DNS/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
# Redirect non-https traffic to https
if (\$scheme != "https") {
return 301 https://\$host\$request_uri;
}
}
server {
listen 443 ssl;
server_name $WWW_DNS;
root /var/www/mo-pool-ui;
index index.html;
gzip on;
location = /robots.txt {
default_type text/plain;
return 200 "User-agent: *\nAllow: /\n";
}
location / {
try_files \$uri \$uri/ /index.html;
}
# The script-src hash allows mo-pool-ui's inline JSON-LD. If that block changes,
# rebuild mo-pool-ui and recompute with: ./csp-hash.sh build/index.html
add_header Content-Security-Policy "default-src 'none'; script-src 'self' 'sha256-yENZ47wxlUnKLykemLwcnbrHwUk86i6YedHpk5ZL0Kk='; style-src 'self'; img-src 'self' data:; connect-src https://$API_DNS https://stats.uptimerobot.com; font-src 'none'; object-src 'none'; frame-src 'none'; worker-src 'none'; manifest-src 'none'; media-src 'none'; base-uri 'none'; form-action 'none'; frame-ancestors 'none'; upgrade-insecure-requests" always;
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=(), usb=(), serial=(), clipboard-write=(self)" always;
ssl_certificate /etc/letsencrypt/live/$WWW_DNS/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/$WWW_DNS/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
# Redirect non-https traffic to https
if (\$scheme != "https") {
return 301 https://\$host\$request_uri;
}
}
EOF
chown -R www-data:www-data /var/www
chmod g+s /var/www
systemctl restart nginx
clone_repo_once https://github.com/monero-project/monero.git /usr/local/src/monero
cd /usr/local/src/monero
git checkout v0.18.4.6
retry_command git submodule update --init
apply_monero_patches
if ! monero_patch_build_is_current; then
rm -rf build
build_monero_release
fi
(cat <<EOF
set -ex
mkdir -p ~/wallets
cd ~/wallets
test -f ~/wallets/wallet_pass || echo pass >~/wallets/wallet_pass
if [ ! -f ~/wallets/wallet.address.txt ]; then
echo 1 | /usr/local/src/monero/build/release/bin/monero-wallet-cli --offline --create-address-file --generate-new-wallet ~/wallets/wallet --password-file ~/wallets/wallet_pass --command address
fi
if [ ! -f ~/wallets/wallet_fee.address.txt ]; then
echo 1 | /usr/local/src/monero/build/release/bin/monero-wallet-cli --offline --create-address-file --generate-new-wallet ~/wallets/wallet_fee --password-file ~/wallets/wallet_pass --command address
fi
EOF
) | su user -l
echo; echo; echo
if [ ! -f /root/.moneroocean-wallet-seeds-confirmed ]; then
read -p "*** Write down your seeds for wallet and wallet_fee listed above and press ENTER to continue ***"
touch /root/.moneroocean-wallet-seeds-confirmed
fi
id -u monerodaemon >/dev/null 2>&1 || useradd -m monerodaemon -d /home/monerodaemon
ensure_tari_user
configure_monero_hugepages
cat >/lib/systemd/system/monero.service <<EOF
[Unit]
Description=Monero Daemon
After=network.target
[Service]
Environment=MALLOC_ARENA_MAX=2
SupplementaryGroups=$HUGEPAGES_GROUP
LimitMEMLOCK=infinity
ExecStart=/usr/local/src/monero/build/release/bin/monerod --rpc-bind-ip=127.0.0.1 --rpc-bind-port=18083 --hide-my-port --prune-blockchain --enable-dns-blocklist --no-zmq --out-peers 64 --non-interactive --log-level '$MONERO_LOG_CATEGORIES' --block-notify '/bin/bash /home/user/nodejs-pool/block_notify.sh'
Restart=always
User=monerodaemon
Nice=10
CPUQuota=400%
[Install]
WantedBy=multi-user.target
EOF
install_tari_suite
clone_repo_once https://github.com/MoneroOcean/grpc-json-proxy.git /usr/local/src/grpc-json-proxy
patch_tari_config
cat >/lib/systemd/system/xtm.service <<EOF
[Unit]
Description=Tari Daemon
After=network.target
[Service]
ExecStart=/bin/bash -c "(sleep 2; node /usr/local/src/grpc-json-proxy/grpc-json-proxy.js /usr/local/src/grpc-json-proxy/base_node.proto 18146 18142) & (sleep 2; node /usr/local/src/grpc-json-proxy/grpc-json-proxy.js /usr/local/src/grpc-json-proxy/base_node.proto 18148 18142) & /usr/local/src/tari/minotari_node --non-interactive-mode --watch status --disable-splash-screen"
Restart=always
User=$TARI_USER
Environment=HOME=$TARI_HOME
Nice=10
CPUQuota=400%
MemoryHigh=$TARI_MEMORY_HIGH
MemorySwapMax=$TARI_MEMORY_SWAP_MAX
[Install]
WantedBy=multi-user.target
EOF
cat >/lib/systemd/system/xtm_mm.service <<EOF
[Unit]
Description=Tari Merge Mining Daemon
After=network.target
[Service]
ExecStart=/usr/local/src/tari/minotari_merge_mining_proxy --non-interactive-mode
Restart=always
RestartSec=3s
StartLimitBurst=0
User=$TARI_USER
Environment=HOME=$TARI_HOME
Nice=10
CPUQuota=400%
MemoryHigh=$TARI_MM_MEMORY_HIGH
MemorySwapMax=$TARI_MM_MEMORY_SWAP_MAX
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable monero xtm xtm_mm
systemctl start monero
wait_for_monero_sync
rm -f /etc/mysql/conf.d/mysql-native-password.cnf
if mysqld --verbose --help 2>/dev/null | grep -Fq -- "--mysql-native-password[=name]"; then
cat >/etc/mysql/conf.d/mysql-native-password.cnf <<'EOF'
[mysqld]
mysql-native-password=ON
EOF
fi
systemctl restart mysql
for i in $(seq 1 30); do
mysqladmin ping >/dev/null 2>&1 && break
sleep 1
done
mysqladmin ping >/dev/null 2>&1
ROOT_SQL_PASS=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1)
if mysql -Nse "SHOW PLUGINS" | awk '$1=="mysql_native_password" && $2=="ACTIVE" { found=1 } END { exit !found }'; then
ROOT_SQL_AUTH="ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '$ROOT_SQL_PASS';"
USER_SQL_CMD="sudo mysql -u root --password='$ROOT_SQL_PASS'"
else
ROOT_SQL_AUTH="ALTER USER 'root'@'localhost' IDENTIFIED BY '$ROOT_SQL_PASS';"
USER_SQL_CMD="sudo mysql --protocol=socket -u root"
fi
(cat <<EOF
$ROOT_SQL_AUTH
FLUSH PRIVILEGES;
EOF
) | {
if mysql --protocol=socket -u root -e "SELECT 1" >/dev/null 2>&1; then
mysql --protocol=socket -u root
elif test -f /root/mysql_pass; then
mysql -u root --password="$(cat /root/mysql_pass)"
else
mysql -u root
fi
}
echo $ROOT_SQL_PASS >/root/mysql_pass
chmod 600 /root/mysql_pass
grep max_connections /etc/mysql/my.cnf || cat >>/etc/mysql/my.cnf <<'EOF'
[mysqld]
max_connections = 10000
EOF
systemctl restart mysql
(cat <<EOF
set -ex
$(declare -f retry_command)
if [ ! -f /home/user/.nvm/nvm.sh ]; then
retry_command bash -lc 'set -o pipefail; curl -fsSL https://raw.githubusercontent.com/creationix/nvm/v0.33.0/install.sh | bash'
fi
source /home/user/.nvm/nvm.sh
retry_command nvm install $NODEJS_VERSION
NODEJS_VERSION="\$(nvm version "$NODEJS_VERSION")"
nvm alias default "\$NODEJS_VERSION"
test -x /usr/bin/node || sudo ln -s "\$(command -v node)" /usr/bin/node
test -x /usr/bin/npm || sudo ln -s "\$(command -v npm)" /usr/bin/npm
sudo chown -R user:user /usr/local/src/grpc-json-proxy
cd /usr/local/src/grpc-json-proxy
if [ ! -d node_modules ]; then
retry_command npm install --omit=dev
fi
cd /home/user
if [ ! -d /home/user/nodejs-pool/.git ]; then
retry_command git clone https://github.com/MoneroOcean/nodejs-pool.git
fi
cd /home/user/nodejs-pool
if [ ! -d node_modules ]; then
JOBS=$(nproc) retry_command npm install
fi
command -v pm2 >/dev/null 2>&1 || retry_command npm install -g pm2
retry_command pm2 install pm2-logrotate
if [ ! -f cert.key ] || [ ! -f cert.pem ]; then
openssl req -subj "/C=IT/ST=Pool/L=Daemon/O=Mining Pool/CN=mining.pool" -newkey rsa:2048 -nodes -keyout cert.key -x509 -out cert.pem -days 36500
fi
# install lmdb tools
( cd /home/user
if [ ! -d node-lmdb/.git ]; then
retry_command git clone https://github.com/Venemo/node-lmdb.git
fi
cd node-lmdb
git checkout c3135a3809da1d64ce1f0956b37b618711e33519
cd dependencies/lmdb/libraries/liblmdb
test -x mdb_copy || make -j $(nproc)
mkdir -p /home/user/.bin
grep -Fq 'export PATH=/home/user/.bin:$PATH' /home/user/.bashrc || {
echo >>/home/user/.bashrc
echo 'export PATH=/home/user/.bin:$PATH' >>/home/user/.bashrc
}
for i in mdb_copy mdb_dump mdb_load mdb_stat; do cp \$i /home/user/.bin/; done
)
mkdir -p /home/user/pool_db
if [ ! -f config.json ]; then
sed -r 's#("db_storage_path": ).*#\1"/home/user/pool_db/",#' config_example.json >config.json
fi
if ! $USER_SQL_CMD -e "USE pool" >/dev/null 2>&1; then
$USER_SQL_CMD <deployment/base.sql
fi
$USER_SQL_CMD -e "INSERT IGNORE INTO pool.config (module, item, item_value, item_type, Item_desc) VALUES ('api', 'authKey', '$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1)', 'string', 'Auth key sent with all Websocket frames for validation.')"
$USER_SQL_CMD -e "INSERT IGNORE INTO pool.config (module, item, item_value, item_type, Item_desc) VALUES ('api', 'secKey', '$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1)', 'string', 'Secret key for signing miner email unsubscribe links.')"
$USER_SQL_CMD -e "UPDATE pool.config SET item_value = '$(cat /home/user/wallets/wallet.address.txt)' WHERE module = 'pool' and item = 'address';"
$USER_SQL_CMD -e "UPDATE pool.config SET item_value = '$(cat /home/user/wallets/wallet_fee.address.txt)' WHERE module = 'payout' and item = 'feeAddress';"
pm2 describe api >/dev/null 2>&1 || pm2 start init.js --name=api --log-date-format="YYYY-MM-DD HH:mm Z" -- --module=api
pm2 describe monero-wallet-rpc >/dev/null 2>&1 || pm2 start /usr/local/src/monero/build/release/bin/monero-wallet-rpc -- --rpc-bind-port 18082 --password-file /home/user/wallets/wallet_pass --wallet-file /home/user/wallets/wallet --trusted-daemon --disable-rpc-login
sleep 30
pm2 describe block_manager >/dev/null 2>&1 || pm2 start init.js --name=block_manager --log-date-format="YYYY-MM-DD HH:mm:ss:SSS Z" -- --module=block_manager
pm2 describe worker >/dev/null 2>&1 || pm2 start init.js --name=worker --log-date-format="YYYY-MM-DD HH:mm:ss:SSS Z" --node-args="--max_old_space_size=8192" -- --module=worker
pm2 describe payments >/dev/null 2>&1 || pm2 start init.js --name=payments --log-date-format="YYYY-MM-DD HH:mm:ss:SSS Z" --no-autorestart -- --module=payments
pm2 describe remote_share >/dev/null 2>&1 || pm2 start init.js --name=remote_share --log-date-format="YYYY-MM-DD HH:mm:ss:SSS Z" -- --module=remote_share
pm2 describe long_runner >/dev/null 2>&1 || pm2 start init.js --name=long_runner --log-date-format="YYYY-MM-DD HH:mm:ss:SSS Z" -- --module=long_runner
#pm2 start init.js --name=pool --log-date-format="YYYY-MM-DD HH:mm:ss:SSS Z" -- --module=pool
sleep 20
pm2 describe pool_stats >/dev/null 2>&1 || pm2 start init.js --name=pool_stats --log-date-format="YYYY-MM-DD HH:mm:ss:SSS Z" -- --module=pool_stats
pm2 save
sudo env PATH=\$PATH:/home/user/.nvm/versions/node/\$NODEJS_VERSION/bin /home/user/.nvm/versions/node/\$NODEJS_VERSION/lib/node_modules/pm2/bin/pm2 startup systemd -u user --hp /home/user
cd /home/user
if [ ! -d /home/user/mo-pool-ui/.git ]; then
retry_command git clone https://github.com/MoneroOcean/mo-pool-ui.git
fi
cd mo-pool-ui
if [ ! -d node_modules ]; then
retry_command npm install
fi
if [ -r /etc/os-release ]; then
. /etc/os-release
if [ "\${ID:-}" = "ubuntu" ] && [ "\${VERSION_ID:-}" = "26.04" ]; then
export PLAYWRIGHT_HOST_PLATFORM_OVERRIDE=ubuntu24.04-x64
fi
fi
retry_command npx playwright install --with-deps chromium
retry_command npm run build
EOF
) | su user -l
systemctl start xtm xtm_mm
wait_for_tari_sync
echo 'Frontend is installed in /home/user/mo-pool-ui and deployed to /var/www/mo-pool-ui. To rebuild it later, log in as "user" and run: cd ~/mo-pool-ui && npm install && npm run build'