Browse Source

Add samourai-server app (#461)

Co-authored-by: Mayank <mayankchhabra9@gmail.com>
Co-authored-by: Luke Childs <lukechilds123@gmail.com>
tor-0.4.4.7
Lounès Ksouri 4 years ago
committed by GitHub
parent
commit
6e2584d378
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 137
      apps/samourai-server/docker-compose.yml
  2. 0
      apps/samourai-server/mysql/data/.gitkeep
  3. 203
      apps/samourai-server/mysql/db-scripts/1_db.sql
  4. 2
      apps/samourai-server/mysql/mysql-dojo.cnf
  5. 14
      apps/samourai-server/mysql/update-db.sh
  6. 349
      apps/samourai-server/nginx/connect/css/normalize.css
  7. 123
      apps/samourai-server/nginx/connect/css/style.css
  8. 19
      apps/samourai-server/nginx/connect/img/icon.svg
  9. 92
      apps/samourai-server/nginx/connect/index.html
  10. 5
      apps/samourai-server/nginx/connect/js/conf.template.js
  11. 2
      apps/samourai-server/nginx/connect/js/qrcode.min.js
  12. 37
      apps/samourai-server/nginx/connect/js/script.js
  13. 74
      apps/samourai-server/nginx/mainnet.conf
  14. 45
      apps/samourai-server/nginx/nginx.conf
  15. 79
      apps/samourai-server/nginx/testnet.conf
  16. 79
      apps/samourai-server/nginx/wait-for
  17. 0
      apps/samourai-server/whirlpool/.gitkeep
  18. 10
      scripts/app
  19. 12
      scripts/configure
  20. 6
      templates/.env-sample
  21. 8
      templates/torrc-sample

137
apps/samourai-server/docker-compose.yml

@ -0,0 +1,137 @@
version: "3.7"
x-logging:
&default-logging
driver: journald
options:
tag: "umbrel-app {{.Name}}"
services:
db:
image: mariadb:10.5.8@sha256:8040983db146f729749081c6b216a19d52e0973134e2e34c0b4fd87f48bc15b0
init: true
logging: *default-logging
restart: on-failure
stop_grace_period: 5m
user: "1000:1000"
environment:
MYSQL_DATABASE: samourai-main
MYSQL_ROOT_PASSWORD: rootpassword
MYSQL_USER: samourai
MYSQL_PASSWORD: password
volumes:
- ${APP_DATA_DIR}/mysql/data:/var/lib/mysql
- ${APP_DATA_DIR}/mysql/db-scripts:/docker-entrypoint-initdb.d
- ${APP_DATA_DIR}/mysql/mysql-dojo.cnf:/etc/mysql/conf.d/mysql-dojo.cnf
- ${APP_DATA_DIR}/mysql/update-db.sh:/update-db.sh
networks:
default:
ipv4_address: $APP_SAMOURAI_SERVER_DB_IP
node:
image: louneskmt/dojo-nodejs:1.8.0@sha256:6643de76267e3a2cfd4f6d593d560a8dd001a54a7e5f9cc8df77d4cab5f1e1bf
init: true
logging: *default-logging
restart: on-failure
command: "/home/node/app/wait-for-it.sh db:3306 --timeout=720 --strict -- /home/node/app/restart.sh"
user: "1000:1000"
environment:
# GLOBAL
COMMON_BTC_NETWORK: $BITCOIN_NETWORK
DOJO_NODEJS_VERSION_TAG: 1.8.0
TOR_PROXY_IP: $TOR_PROXY_IP
TOR_PROXY_PORT: $TOR_PROXY_PORT
# MYSQL
MYSQL_DATABASE: samourai-main
MYSQL_USER: samourai
MYSQL_PASSWORD: password
# NODEJS
NODE_GAP_EXTERNAL: 100
NODE_GAP_INTERNAL: 100
NODE_ADDR_FILTER_THRESHOLD: 1000
NODE_ADDR_DERIVATION_MIN_CHILD: 2
NODE_ADDR_DERIVATION_MAX_CHILD: 2
NODE_ADDR_DERIVATION_THRESHOLD: 10
NODE_TXS_SCHED_MAX_ENTRIES: 10
NODE_TXS_SCHED_MAX_DELTA_HEIGHT: 18
NODE_JWT_ACCESS_EXPIRES: 900
NODE_JWT_REFRESH_EXPIRES: 7200
NODE_PREFIX_STATUS: status
NODE_PREFIX_SUPPORT: support
NODE_PREFIX_STATUS_PUSHTX: status
NODE_TRACKER_MEMPOOL_PERIOD: 10000
NODE_TRACKER_UNCONF_TXS_PERIOD: 300000
NODE_ACTIVE_INDEXER: local_indexer
NODE_FEE_TYPE: ECONOMICAL
# SECURITY
NODE_API_KEY: $SAMOURAI_SERVER_NODE_API_KEY
NODE_ADMIN_KEY: $SAMOURAI_SERVER_NODE_ADMIN_KEY
NODE_JWT_SECRET: $SAMOURAI_SERVER_NODE_JWT_SECRET
# BITCOIN
BITCOIND_IP: $BITCOIN_IP
BITCOIND_RPC_PORT: $BITCOIN_RPC_PORT
BITCOIND_RPC_USER: $BITCOIN_RPC_USER
BITCOIND_RPC_PASSWORD: $BITCOIN_RPC_PASS
BITCOIND_ZMQ_RAWTXS: $BITCOIN_ZMQ_RAWTX_PORT
BITCOIND_ZMQ_BLK_HASH: $BITCOIN_ZMQ_HASHBLOCK_PORT
# EXPLORER
EXPLORER_INSTALL: "off"
# INDEXER
INDEXER_IP: $ELECTRUM_IP
INDEXER_RPC_PORT: $ELECTRUM_PORT
INDEXER_BATCH_SUPPORT: inactive # 'active' for ElectrumX, 'inactive' otherwise
depends_on:
- db
networks:
default:
ipv4_address: $APP_SAMOURAI_SERVER_NODE_IP
whirlpool:
image: louneskmt/dojo-whirlpool:1.2.1@sha256:8674bca0d901e8d65d49e5cf38c597c37bf1d99168114a58b63b242dd1b38d05
init: true
logging: *default-logging
restart: on-failure
command: /restart.sh
user: "1000:1000"
environment:
COMMON_BTC_NETWORK: $BITCOIN_NETWORK
WHIRLPOOL_RESYNC: "on"
WHIRLPOOL_DEBUG: "off"
WHIRLPOOL_DEBUG_CLIENT: "off"
NGINX_IP: $APP_SAMOURAI_SERVER_IP
volumes:
- ${APP_DATA_DIR}/whirlpool:/home/whirlpool/.whirlpool-cli
networks:
default:
ipv4_address: $APP_SAMOURAI_SERVER_WHIRLPOOL_IP
nginx:
image: nginx:1.19-alpine@sha256:c2ce58e024275728b00a554ac25628af25c54782865b3487b11c21cafb7fabda
init: true
logging: *default-logging
restart: on-failure
command: /bin/sh -c "envsubst < /var/www/connect/js/conf.template.js > /var/www/connect/js/conf.js && /wait-for node:8080 --timeout=720 -- nginx"
volumes:
- ${APP_DATA_DIR}/nginx/wait-for:/wait-for
- ${APP_DATA_DIR}/nginx/nginx.conf:/etc/nginx/nginx.conf
- ${APP_DATA_DIR}/nginx/${BITCOIN_NETWORK}.conf:/etc/nginx/sites-enabled/dojo.conf
- ${APP_DATA_DIR}/nginx/connect:/var/www/connect
environment:
COMMON_BTC_NETWORK: $BITCOIN_NETWORK
DOJO_HIDDEN_SERVICE: $APP_HIDDEN_SERVICE
WHIRLPOOL_HIDDEN_SERVICE: $SAMOURAI_SERVER_WHIRLPOOL_HIDDEN_SERVICE
NODE_PREFIX_SUPPORT: support
NODE_ADMIN_KEY: $SAMOURAI_SERVER_NODE_ADMIN_KEY
ports:
- "$APP_SAMOURAI_SERVER_PORT:80"
depends_on:
- node
networks:
default:
ipv4_address: $APP_SAMOURAI_SERVER_IP

0
apps/samourai-server/mysql/data/.gitkeep

203
apps/samourai-server/mysql/db-scripts/1_db.sql

@ -0,0 +1,203 @@
# Database tables
# Copyright © 2019 – Katana Cryptographic Ltd. All Rights Reserved.
# Naming conventions
# 1. Table names are lowercase plural
# 2. Join table names are snake_case plural
# 3. Column names have a table prefix
# 4. Foreign key names match primary key of foreign table
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
--
-- Table structure for table `addresses`
--
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE IF NOT EXISTS `addresses` (
`addrID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`addrAddress` varchar(74) DEFAULT NULL,
PRIMARY KEY (`addrID`),
UNIQUE KEY `addrAddress` (`addrAddress`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `banned_addresses`
--
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE IF NOT EXISTS `banned_addresses` (
`bannedAddressId` int(11) NOT NULL AUTO_INCREMENT,
`addrAddress` varchar(35) NOT NULL,
PRIMARY KEY (`bannedAddressId`),
UNIQUE KEY `banned_addresses_addresses` (`addrAddress`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `blocks`
--
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE IF NOT EXISTS `blocks` (
`blockID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`blockHash` char(64) NOT NULL DEFAULT '',
`blockParent` int(10) unsigned DEFAULT NULL,
`blockHeight` int(10) unsigned NOT NULL DEFAULT '0',
`blockTime` int(10) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`blockID`),
UNIQUE KEY `blockHash` (`blockHash`),
KEY `blockParent` (`blockParent`),
KEY `blockHeight` (`blockHeight`),
CONSTRAINT `blocks_ibfk_1` FOREIGN KEY (`blockParent`) REFERENCES `blocks` (`blockID`) ON DELETE SET NULL ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `hd`
--
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE IF NOT EXISTS `hd` (
`hdID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`hdXpub` char(112) DEFAULT NULL,
`hdCreated` int(10) unsigned NOT NULL DEFAULT '0',
`hdType` smallint(5) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`hdID`),
UNIQUE KEY `hdXpub` (`hdXpub`),
KEY `hdCreated` (`hdCreated`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `hd_addresses`
--
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE IF NOT EXISTS `hd_addresses` (
`hdAddrID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`hdID` int(10) unsigned NOT NULL DEFAULT '0',
`addrID` int(10) unsigned NOT NULL DEFAULT '0',
`hdAddrChain` smallint(5) unsigned NOT NULL DEFAULT '0',
`hdAddrIndex` int(10) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`hdAddrID`),
UNIQUE KEY `hdID_2` (`hdID`,`addrID`),
KEY `hdID` (`hdID`),
KEY `addrID` (`addrID`),
CONSTRAINT `hd_addresses_ibfk_1` FOREIGN KEY (`hdID`) REFERENCES `hd` (`hdID`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `hd_addresses_ibfk_2` FOREIGN KEY (`addrID`) REFERENCES `addresses` (`addrID`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `inputs`
--
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE IF NOT EXISTS `inputs` (
`inID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`outID` int(10) unsigned NOT NULL DEFAULT '0',
`txnID` int(10) unsigned NOT NULL DEFAULT '0',
`inIndex` int(10) unsigned NOT NULL DEFAULT '0',
`inSequence` int(10) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`inID`),
UNIQUE KEY `txnID_2` (`txnID`,`inIndex`),
KEY `outID` (`outID`),
KEY `txnID` (`txnID`),
CONSTRAINT `inputs_ibfk_1` FOREIGN KEY (`txnID`) REFERENCES `transactions` (`txnID`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `inputs_ibfk_2` FOREIGN KEY (`outID`) REFERENCES `outputs` (`outID`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `outputs`
--
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE IF NOT EXISTS `outputs` (
`outID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`txnID` int(10) unsigned NOT NULL DEFAULT '0',
`addrID` int(10) unsigned NOT NULL DEFAULT '0',
`outIndex` int(10) unsigned NOT NULL DEFAULT '0',
`outAmount` bigint(20) unsigned NOT NULL DEFAULT '0',
`outScript` varchar(20000) NOT NULL DEFAULT '',
PRIMARY KEY (`outID`),
UNIQUE KEY `txnID_2` (`txnID`,`addrID`,`outIndex`),
KEY `txnID` (`txnID`),
KEY `addrID` (`addrID`),
CONSTRAINT `outputs_ibfk_1` FOREIGN KEY (`txnID`) REFERENCES `transactions` (`txnID`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `outputs_ibfk_2` FOREIGN KEY (`addrID`) REFERENCES `addresses` (`addrID`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `transactions`
--
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE IF NOT EXISTS `transactions` (
`txnID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`txnTxid` char(64) DEFAULT NULL,
`txnCreated` int(10) unsigned NOT NULL DEFAULT '0',
`txnVersion` int(10) unsigned NOT NULL DEFAULT '0',
`txnLocktime` int(10) unsigned NOT NULL DEFAULT '0',
`blockID` int(10) unsigned DEFAULT NULL,
PRIMARY KEY (`txnID`),
UNIQUE KEY `txnTxid` (`txnTxid`),
KEY `txnCreated` (`txnCreated`),
KEY `blockID` (`blockID`),
CONSTRAINT `transactions_ibfk_1` FOREIGN KEY (`blockID`) REFERENCES `blocks` (`blockID`) ON DELETE SET NULL ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `scheduled_transactions`
--
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE IF NOT EXISTS `scheduled_transactions` (
`schID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`schTxid` char(64) NOT NULL DEFAULT '',
`schCreated` int(10) unsigned NOT NULL DEFAULT '0',
`schRaw` varchar(50000) NOT NULL DEFAULT '',
`schParentID` int(10) unsigned DEFAULT NULL,
`schParentTxid` char(64) DEFAULT '',
`schDelay` int(10) unsigned NOT NULL DEFAULT '0',
`schTrigger` int(10) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`schID`),
UNIQUE KEY `schTxid` (`schTxid`),
KEY `schParentID` (`schParentID`),
CONSTRAINT `scheduled_transactions_ibfk_1` FOREIGN KEY (`schParentID`) REFERENCES `scheduled_transactions` (`schID`) ON DELETE SET NULL ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

2
apps/samourai-server/mysql/mysql-dojo.cnf

@ -0,0 +1,2 @@
[mysqld]
sql_mode="NO_ENGINE_SUBSTITUTION"

14
apps/samourai-server/mysql/update-db.sh

@ -0,0 +1,14 @@
#!/bin/bash
for i in {30..0}; do
if echo "SELECT 1" | mysql -h"db" -u"root" -p"$MYSQL_ROOT_PASSWORD" &> /dev/null; then
break
fi
echo "MySQL init process in progress..."
sleep 1
done
if [ -f /docker-entrypoint-initdb.d/2_update.sql ]; then
mysql -h"db" -u"root" -p"$MYSQL_ROOT_PASSWORD" "$MYSQL_DATABASE" < /docker-entrypoint-initdb.d/2_update.sql
echo "Updated database with 2_update.sql"
fi

349
apps/samourai-server/nginx/connect/css/normalize.css

@ -0,0 +1,349 @@
/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
/* Document
========================================================================== */
/**
* 1. Correct the line height in all browsers.
* 2. Prevent adjustments of font size after orientation changes in iOS.
*/
html {
line-height: 1.15; /* 1 */
-webkit-text-size-adjust: 100%; /* 2 */
}
/* Sections
========================================================================== */
/**
* Remove the margin in all browsers.
*/
body {
margin: 0;
}
/**
* Render the `main` element consistently in IE.
*/
main {
display: block;
}
/**
* Correct the font size and margin on `h1` elements within `section` and
* `article` contexts in Chrome, Firefox, and Safari.
*/
h1 {
font-size: 2em;
margin: 0.67em 0;
}
/* Grouping content
========================================================================== */
/**
* 1. Add the correct box sizing in Firefox.
* 2. Show the overflow in Edge and IE.
*/
hr {
box-sizing: content-box; /* 1 */
height: 0; /* 1 */
overflow: visible; /* 2 */
}
/**
* 1. Correct the inheritance and scaling of font size in all browsers.
* 2. Correct the odd `em` font sizing in all browsers.
*/
pre {
font-family: monospace, monospace; /* 1 */
font-size: 1em; /* 2 */
}
/* Text-level semantics
========================================================================== */
/**
* Remove the gray background on active links in IE 10.
*/
a {
background-color: transparent;
}
/**
* 1. Remove the bottom border in Chrome 57-
* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
*/
abbr[title] {
border-bottom: none; /* 1 */
text-decoration: underline; /* 2 */
text-decoration: underline dotted; /* 2 */
}
/**
* Add the correct font weight in Chrome, Edge, and Safari.
*/
b,
strong {
font-weight: bolder;
}
/**
* 1. Correct the inheritance and scaling of font size in all browsers.
* 2. Correct the odd `em` font sizing in all browsers.
*/
code,
kbd,
samp {
font-family: monospace, monospace; /* 1 */
font-size: 1em; /* 2 */
}
/**
* Add the correct font size in all browsers.
*/
small {
font-size: 80%;
}
/**
* Prevent `sub` and `sup` elements from affecting the line height in
* all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
/* Embedded content
========================================================================== */
/**
* Remove the border on images inside links in IE 10.
*/
img {
border-style: none;
}
/* Forms
========================================================================== */
/**
* 1. Change the font styles in all browsers.
* 2. Remove the margin in Firefox and Safari.
*/
button,
input,
optgroup,
select,
textarea {
font-family: inherit; /* 1 */
font-size: 100%; /* 1 */
line-height: 1.15; /* 1 */
margin: 0; /* 2 */
}
/**
* Show the overflow in IE.
* 1. Show the overflow in Edge.
*/
button,
input { /* 1 */
overflow: visible;
}
/**
* Remove the inheritance of text transform in Edge, Firefox, and IE.
* 1. Remove the inheritance of text transform in Firefox.
*/
button,
select { /* 1 */
text-transform: none;
}
/**
* Correct the inability to style clickable types in iOS and Safari.
*/
button,
[type="button"],
[type="reset"],
[type="submit"] {
-webkit-appearance: button;
}
/**
* Remove the inner border and padding in Firefox.
*/
button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
border-style: none;
padding: 0;
}
/**
* Restore the focus styles unset by the previous rule.
*/
button:-moz-focusring,
[type="button"]:-moz-focusring,
[type="reset"]:-moz-focusring,
[type="submit"]:-moz-focusring {
outline: 1px dotted ButtonText;
}
/**
* Correct the padding in Firefox.
*/
fieldset {
padding: 0.35em 0.75em 0.625em;
}
/**
* 1. Correct the text wrapping in Edge and IE.
* 2. Correct the color inheritance from `fieldset` elements in IE.
* 3. Remove the padding so developers are not caught out when they zero out
* `fieldset` elements in all browsers.
*/
legend {
box-sizing: border-box; /* 1 */
color: inherit; /* 2 */
display: table; /* 1 */
max-width: 100%; /* 1 */
padding: 0; /* 3 */
white-space: normal; /* 1 */
}
/**
* Add the correct vertical alignment in Chrome, Firefox, and Opera.
*/
progress {
vertical-align: baseline;
}
/**
* Remove the default vertical scrollbar in IE 10+.
*/
textarea {
overflow: auto;
}
/**
* 1. Add the correct box sizing in IE 10.
* 2. Remove the padding in IE 10.
*/
[type="checkbox"],
[type="radio"] {
box-sizing: border-box; /* 1 */
padding: 0; /* 2 */
}
/**
* Correct the cursor style of increment and decrement buttons in Chrome.
*/
[type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button {
height: auto;
}
/**
* 1. Correct the odd appearance in Chrome and Safari.
* 2. Correct the outline style in Safari.
*/
[type="search"] {
-webkit-appearance: textfield; /* 1 */
outline-offset: -2px; /* 2 */
}
/**
* Remove the inner padding in Chrome and Safari on macOS.
*/
[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
/**
* 1. Correct the inability to style clickable types in iOS and Safari.
* 2. Change font properties to `inherit` in Safari.
*/
::-webkit-file-upload-button {
-webkit-appearance: button; /* 1 */
font: inherit; /* 2 */
}
/* Interactive
========================================================================== */
/*
* Add the correct display in Edge, IE 10+, and Firefox.
*/
details {
display: block;
}
/*
* Add the correct display in all browsers.
*/
summary {
display: list-item;
}
/* Misc
========================================================================== */
/**
* Add the correct display in IE 10+.
*/
template {
display: none;
}
/**
* Add the correct display in IE 10.
*/
[hidden] {
display: none;
}

123
apps/samourai-server/nginx/connect/css/style.css

@ -0,0 +1,123 @@
body {
background-color: #1D1B1B;
font-family: system-ui,-apple-system,BlinkMacSystemFont,Roboto,Helvetica Neue,Segoe UI,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;
color: #fff;
}
*, h1, h2, h3, h4, h5, h6, p, span {
color: #fff;
font-size: 20px;
font-weight: normal;
}
.success {
color: #63FB72;
}
.text-muted {
opacity: 0.8;
}
hr {
width: 100%;
height: 2px;
background: #2F2C2C;
border: none;
}
.container {
padding: 40px;
max-width: 1440px;
margin: auto;
}
.app-icon {
border-radius: 20px;
}
.app {
display: flex;
margin: 20px 0 40px 0;
}
.app > .app-icon {
flex-shrink: 0;
height: 140px;
width: 140px;
box-shadow: 0 0 40px 0 rgba(0,0,0,0.95);
margin-right: 24px;
}
.app > .app-details > .app-status {
display: block;
font-size: 20px;
margin: 10px 0 0 0;
}
.app > .app-details > .app-name {
font-size: 52px;
line-height: 52px;
font-weight: bold;
margin: 10px 0 0 0;
}
.heading {
display: flex;
}
.heading > .number {
flex-shrink: 0;
background: #C12525;
height: 66px;
width: 66px;
border-radius: 100%;
line-height: 66px;
text-align: center;
font-size: 36px;
font-weight: bold;
box-shadow: 0 0 20px 0 rgba(0,0,0,0.8);
}
.heading > .text {
font-size: 52px;
line-height: 52px;
font-weight: bold;
display: inline-block;
margin: 5px 0 0 20px;
}
.steps {
margin: 40px 0 0 9px;
}
.steps > .step {
margin-bottom: 20px;
font-size: 20px;
font-weight: normal;
}
.qr {
position: relative;
width: 260px;
height: 260px;
margin: 20px 0;
}
.qr > .icon {
position: absolute;
top: 50%;
left: 50%;
transform: translate3d(-50%, -50%, 0);
height: 66px;
width: 66px;
background: #ffffff;
}
.qr > .icon > img {
display: block;
width: 60px;
height: 60px;
margin: 3px 0 0 3px;
border-radius: 15%;
}

19
apps/samourai-server/nginx/connect/img/icon.svg

@ -0,0 +1,19 @@
<svg width="256" height="256" viewBox="0 0 256 256" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="256" height="256" fill="url(#paint0_linear)"/>
<mask id="mask0" mask-type="alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="256" height="256">
<rect width="256" height="256" fill="url(#paint1_linear)"/>
</mask>
<g mask="url(#mask0)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M64.3568 113.21C72.1844 114.081 77.4308 112.872 85.2587 113.743C85.2587 113.453 92.4829 114.576 93.6356 115.483C102.415 115.483 94.5779 100.849 93.6356 97.1949C92.6537 91.3966 97.7832 83.6072 103.475 82.8264C107.827 82.2296 109.438 82.4578 113.005 84.4519C117.332 88.0956 117.579 90.5577 119.379 95.0608C121.746 100.982 114.753 111.986 122.686 115.61C145.82 124.042 148.264 157.253 147.494 189.884C148.512 197.518 150.734 198.823 155.166 202.362C170.629 213.349 204.919 211.992 221 222.953C220.471 224.481 220.838 223.799 220.161 224.696C219.426 227.066 218.729 227.256 217.645 229.053C216.736 228.261 217.574 229.121 216.806 228.181C201.958 218.569 165.839 217.628 149.857 209.141C149.857 209.431 155.782 214.299 155.782 214.299C164.504 223.347 174.472 242.191 176.751 257C167.486 256.525 151.956 257 141.523 257H67.7118V256.128C71.3461 247.124 79.6846 243.24 83.3189 234.236C85.1395 231.214 91.3432 220.896 93.2764 218.274C96.5898 213.779 105.081 201.619 107.162 195.022C100.862 192.718 90.1559 172.307 87.9519 161.076C72.89 156.777 35.1168 147.446 38.2125 136.852C39.9219 134.412 51.4883 124.005 48.4203 121.924C45.4137 113.383 36.1252 113.62 35 101.881C39.7804 95.6624 36.4924 96.2591 47.5816 94.0379C53.0565 97.2762 59.0191 91.385 59.3242 87.9377C67.0835 84.9964 67.2247 84.0332 67.7118 82.7089C72.1452 82.8353 73.2624 86.6421 73.2624 86.6421C81.9815 84.5132 114.323 71.8908 126.482 68.105C138.642 64.3193 169.313 54.5298 183.074 49.8432C194.279 46.0269 203.717 42.1575 219.141 42V42.8714C218.466 43.7612 219.682 41.3673 219.141 42.8714C210.755 44.6159 200.915 48.5642 193.978 50.7146C175.19 56.5381 140.369 68.4586 122.288 74.2052C115.15 76.4739 71.668 90.8614 75.8987 94.271C72.6142 98.5505 65.1501 106.827 64.3568 113.21V113.21Z" fill="white"/>
</g>
<defs>
<linearGradient id="paint0_linear" x1="128" y1="0" x2="128" y2="256" gradientUnits="userSpaceOnUse">
<stop stop-color="#C12526"/>
<stop offset="1" stop-color="#9D1E1F"/>
</linearGradient>
<linearGradient id="paint1_linear" x1="128" y1="0" x2="128" y2="256" gradientUnits="userSpaceOnUse">
<stop stop-color="#C12526"/>
<stop offset="1" stop-color="#9D1E1F"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

92
apps/samourai-server/nginx/connect/index.html

@ -0,0 +1,92 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Samourai Server</title>
<link rel="shortcut icon" type="image/jpg" href="img/icon.svg" />
<link rel="stylesheet" href="css/normalize.css">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<section class="container">
<div class="app">
<img class="app-icon" src="img/icon.svg" />
<div class="app-details">
<span class="app-status success">&#9679; Running</span>
<h1 class="app-name">Samourai Server</h1>
</div>
</div>
<p class="text-muted">Follow the instructions below to pair Dojo and Whirlpool running on your Umbrel to your
Samourai Wallet.
</p>
</section>
<hr />
<section class="container">
<div class="heading">
<span class="number">1</span>
<h2 class="text">How to connect Dojo</h2>
</div>
<ol class="steps">
<li class="step">Open the Samourai Wallet app on your phone.</li>
<li class="step">If you already have an existing wallet on it, send all of your funds to a different wallet
that you
control and erase your existing wallet from Settings > Wallet > Secure Erase Wallet. If you don’t
have a wallet setup, skip this step.</li>
<li class="step">Select Mainnet.</li>
<li class="step">Tap the 3-dot menu and select “Connect to existing Dojo”.</li>
<li class="step">Tap “Connect to existing Dojo” and scan this QR Code:
<div class="qr">
<div class="qr-contents"></div>
<div class="icon">
<img src="img/icon.svg" />
</div>
</div>
</div>
</li>
<li class="step">Tap "Start New Wallet" and finish the wallet creation process.</li>
<li class="step">Congratulations! Your Samourai Wallet is now backed by the Dojo server running on your
Umbrel. Open
Network Options by tapping the WiFi-like icon on the top to verify if “Dojo Full Node” is successfully
enabled (it should display a green dot).</li>
</ol>
</section>
<hr />
<section class="container">
<div class="heading">
<span class="number">2</span>
<h2 class="text">How to connect Whirlpool</h2>
</div>
<ol class="steps">
<li class="step">Install <a href="https://gist.github.com/lukechilds/0be1d56ecd28092822e4fa750b5945c0" target="_blank">Tor</a> on your computer.</li>
<li class="step">Download and install <a href="https://code.samourai.io/whirlpool/whirlpool-gui/-/releases"
target="_blank">Whirlpool GUI</a>.</li>
<li class="step">Select: Advanced: remote CLI.</li>
<li class="step">Enter "<b id="whirlpool-hidden-service"></b>" (without quotes) in “CLI
address”.</li>
<li class="step">Tor proxy should now auto enable and set itself to “socks5://127.0.0.1:9050”.</li>
<li class="step">Click connect.</li>
<li class="step">Click QR code icon to scan a QR code from Samourai Wallet on your phone.</li>
<li class="step">Open Samourai Wallet on your phone.</li>
<li class="step">Go Settings > Transactions > Experimental > Pair to Whirlpool GUI. Show the QR code on your
phone to your desktop's webcam to scan it.</li>
<li class="step">Click “Initialize GUI”.</li>
<li class="step">Enter your Samourai Wallet’s passphrase (BIP39 passphrase set in Samourai wallet).</li>
<li class="step">Choose a number of mixes for a UTXO.</li>
<li class="step">Click “Mix”.</li>
<li class="step">Congratulations! Whirlpool is now mixing your UTXOs on your Umbrel!</li>
</ol>
<p><strong>Note:</strong> You'll need to open Whirlpool GUI and re-enter your password to continue mixing after restarting or updating your Umbrel.</p>
</section>
<script src="js/qrcode.min.js"></script>
<script src="js/conf.js"></script>
<script src="js/script.js"></script>
</body>
</html>

5
apps/samourai-server/nginx/connect/js/conf.template.js

@ -0,0 +1,5 @@
var dojoHiddenService = "$DOJO_HIDDEN_SERVICE";
var whirlpoolHiddenService = "http://$WHIRLPOOL_HIDDEN_SERVICE";
var bitcoinNetwork = "$COMMON_BTC_NETWORK";
var apiKey = "$NODE_ADMIN_KEY";
var supportPrefix = "$NODE_PREFIX_SUPPORT";

2
apps/samourai-server/nginx/connect/js/qrcode.min.js

File diff suppressed because one or more lines are too long

37
apps/samourai-server/nginx/connect/js/script.js

@ -0,0 +1,37 @@
var baseRoute = bitcoinNetwork == "testnet" ? "test/v2" : "v2";
fetch(`http://${window.location.host}/${baseRoute}/auth/login`, {
method: 'POST',
headers: new Headers({
'Content-Type': 'application/x-www-form-urlencoded'
}),
body: `apikey=${apiKey}`
})
.then(response => response.json())
.then(data => {
fetch(`http://${window.location.host}/${baseRoute}/${supportPrefix}/pairing`, {
method: 'GET',
headers: new Headers({
'Authorization': 'Bearer ' + data.authorizations.access_token,
'Content-Type': 'application/json'
})
})
.then(response => response.json())
.then(data => {
var pairingInfo = data;
pairingInfo.pairing.url = `http://${dojoHiddenService}/${baseRoute}`;
const qrcodeSvg = new QRCode({
content: JSON.stringify(pairingInfo),
join: true,
container: "svg-viewbox",
padding: 3,
color: "#000000",
background: "#ffffff",
ecl: "M",
}).svg();
document.querySelector('.qr-contents').innerHTML = qrcodeSvg;
document.getElementById('whirlpool-hidden-service').innerText = `${whirlpoolHiddenService}`;
});
});

74
apps/samourai-server/nginx/mainnet.conf

@ -0,0 +1,74 @@
# Proxy WebSockets
# https://www.nginx.com/blog/websocket-nginx/
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
# WebSocket server listening here
upstream websocket {
server node:8080;
}
# Site Configuration
server {
listen 80;
server_name _;
# Set proxy timeouts for the application
proxy_connect_timeout 600;
proxy_read_timeout 600;
proxy_send_timeout 600;
send_timeout 600;
# Connection details page
location /connect {
alias /var/www/connect;
index index.html;
try_files $uri $uri/ =404;
}
# Proxy WebSocket connections first
location /v2/inv {
proxy_pass http://websocket;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
# PushTX server is separate, so proxy first
location /v2/pushtx/ {
proxy_pass http://node:8081/;
}
# Tracker server is separate, so proxy first
location /v2/tracker/ {
proxy_pass http://node:8082/;
}
# Proxy requests to maintenance tool
location = /admin/conf/index.js {
proxy_pass http://node:8080/static/admin/conf/index-mainnet.js;
}
location /admin/ {
proxy_pass http://node:8080/static/admin/;
}
# Proxy all other v2 requests to the accounts server
location /v2/ {
proxy_pass http://node:8080/;
}
# Redirect onion address to maintenance tool
location = / {
return 301 /admin;
}
# Serve remaining requests
location / {
return 200 '{"status":"ok"}';
add_header Content-Type application/json;
}
}

45
apps/samourai-server/nginx/nginx.conf

@ -0,0 +1,45 @@
user nginx;
worker_processes auto;
daemon off;
# Log critical errors and higher to stderr
# (see https://github.com/nginxinc/docker-nginx/blob/594ce7a8bc26c85af88495ac94d5cd0096b306f7/mainline/alpine/Dockerfile#L104)
error_log /var/log/nginx/error.log crit;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Disable activity logging for privacy.
access_log off;
# Do not reveal the version of server
server_tokens off;
sendfile on;
keepalive_timeout 95;
# Enable response compression
gzip on;
# Compression level: 1-9
gzip_comp_level 1;
# Disable gzip compression for older IE
gzip_disable msie6;
# Minimum length of response before gzip kicks in
gzip_min_length 128;
# Compress these MIME types in addition to text/html
gzip_types application/json;
# Help with proxying by adding the Vary: Accept-Encoding response
gzip_vary on;
include /etc/nginx/sites-enabled/*.conf;
}

79
apps/samourai-server/nginx/testnet.conf

@ -0,0 +1,79 @@
# Proxy WebSockets
# https://www.nginx.com/blog/websocket-nginx/
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
# WebSocket server listening here
upstream websocket {
server node:8080;
}
# Site Configuration
server {
listen 80;
server_name _;
# Set proxy timeouts for the application
proxy_connect_timeout 600;
proxy_read_timeout 600;
proxy_send_timeout 600;
send_timeout 600;
# Connection details page
location /connect {
alias /var/www/connect;
index index.html;
try_files $uri $uri/ =404;
}
# Proxy WebSocket connections first
location /test/v2/inv {
proxy_pass http://websocket;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
# PushTX server is separate, so proxy first
location /test/v2/pushtx/ {
proxy_pass http://node:8081/;
}
# Tracker server is separate, so proxy first
location /test/v2/tracker/ {
proxy_pass http://node:8082/;
}
# Proxy requests to maintenance tool
location = /admin/conf/index.js {
proxy_pass http://node:8080/static/admin/conf/index-testnet.js;
}
location /admin/ {
proxy_pass http://node:8080/static/admin/;
}
# Proxy all other v2 requests to the accounts server
location /test/v2/ {
proxy_pass http://node:8080/;
}
# Redirect onion address to maintenance tool
location = / {
return 301 /admin;
}
# Serve remaining requests
location / {
return 200 '{"status":"ok"}';
add_header Content-Type application/json;
}
location /test/ {
return 200 '{"status":"ok"}';
add_header Content-Type application/json;
}
}

79
apps/samourai-server/nginx/wait-for

@ -0,0 +1,79 @@
#!/bin/sh
TIMEOUT=15
QUIET=0
echoerr() {
if [ "$QUIET" -ne 1 ]; then printf "%s\n" "$*" 1>&2; fi
}
usage() {
exitcode="$1"
cat << USAGE >&2
Usage:
$cmdname host:port [-t timeout] [-- command args]
-q | --quiet Do not output any status messages
-t TIMEOUT | --timeout=timeout Timeout in seconds, zero for no timeout
-- COMMAND ARGS Execute command with args after the test finishes
USAGE
exit "$exitcode"
}
wait_for() {
for i in `seq $TIMEOUT` ; do
nc -z "$HOST" "$PORT" > /dev/null 2>&1
result=$?
if [ $result -eq 0 ] ; then
if [ $# -gt 0 ] ; then
exec "$@"
fi
exit 0
fi
sleep 1
done
echo "Operation timed out" >&2
exit 1
}
while [ $# -gt 0 ]
do
case "$1" in
*:* )
HOST=$(printf "%s\n" "$1"| cut -d : -f 1)
PORT=$(printf "%s\n" "$1"| cut -d : -f 2)
shift 1
;;
-q | --quiet)
QUIET=1
shift 1
;;
-t)
TIMEOUT="$2"
if [ "$TIMEOUT" = "" ]; then break; fi
shift 2
;;
--timeout=*)
TIMEOUT="${1#*=}"
shift 1
;;
--)
shift
break
;;
--help)
usage 0
;;
*)
echoerr "Unknown argument: $1"
usage 1
;;
esac
done
if [ "$HOST" = "" -o "$PORT" = "" ]; then
echoerr "Error: you need to provide a host and port to test."
usage 2
fi
wait_for "$@"

0
apps/samourai-server/whirlpool/.gitkeep

10
scripts/app

@ -106,6 +106,16 @@ compose() {
export APP_DATA_DIR="${app_data_dir}"
export APP_HIDDEN_SERVICE="$(cat "${app_hidden_servive_file}" 2>/dev/null || echo "notyetset.onion")"
export APP_SEED=$(derive_entropy "${app_entropy_identifier}")
# App specific env vars
# Note: Hardcoding app specific env vars is a short term solution. Long term
# these values will be registered in an apps manifest and generated dynamically.
local whirlpool_hidden_service_file="${UMBREL_ROOT}/tor/data/app-${app}-whirlpool/hostname"
export SAMOURAI_SERVER_WHIRLPOOL_HIDDEN_SERVICE="$(cat "${whirlpool_hidden_service_file}" 2>/dev/null || echo "notyetset.onion")"
export SAMOURAI_SERVER_NODE_API_KEY=$(derive_entropy "env-${app_entropy_identifier}-NODE_API_KEY")
export SAMOURAI_SERVER_NODE_ADMIN_KEY=$(derive_entropy "env-${app_entropy_identifier}-NODE_ADMIN_KEY")
export SAMOURAI_SERVER_NODE_JWT_SECRET=$(derive_entropy "env-${app_entropy_identifier}-NODE_JWT_SECRET")
docker-compose \
--env-file "${env_file}" \
--project-name "${app}" \

12
scripts/configure

@ -147,6 +147,12 @@ APP_MEMPOOL_IP="10.21.21.26"
APP_MEMPOOL_PORT="3006"
APP_MEMPOOL_API_IP="10.21.21.27"
APP_MEMPOOL_DB_IP="10.21.21.28"
APP_SAMOURAI_SERVER_IP="10.21.21.22"
APP_SAMOURAI_SERVER_PORT="3005"
APP_SAMOURAI_SERVER_WHIRLPOOL_IP="10.21.21.23"
APP_SAMOURAI_SERVER_WHIRLPOOL_PORT="8898"
APP_SAMOURAI_SERVER_DB_IP="10.21.21.24"
APP_SAMOURAI_SERVER_NODE_IP="10.21.21.25"
# Generate RPC credentials
if [[ -z ${BITCOIN_RPC_USER+x} ]] || [[ -z ${BITCOIN_RPC_PASS+x} ]] || [[ -z ${BITCOIN_RPC_AUTH+x} ]]; then
@ -292,6 +298,12 @@ for template in "${NGINX_CONF_FILE}" "${BITCOIN_CONF_FILE}" "${LND_CONF_FILE}" "
sed -i "s/<app-mempool-port>/${APP_MEMPOOL_PORT}/g" "${template}"
sed -i "s/<app-mempool-db-ip>/${APP_MEMPOOL_DB_IP}/g" "${template}"
sed -i "s/<app-mempool-api-ip>/${APP_MEMPOOL_API_IP}/g" "${template}"
sed -i "s/<app-samourai-server-ip>/${APP_SAMOURAI_SERVER_IP}/g" "${template}"
sed -i "s/<app-samourai-server-port>/${APP_SAMOURAI_SERVER_PORT}/g" "${template}"
sed -i "s/<app-samourai-server-whirlpool-ip>/${APP_SAMOURAI_SERVER_WHIRLPOOL_IP}/g" "${template}"
sed -i "s/<app-samourai-server-whirlpool-port>/${APP_SAMOURAI_SERVER_WHIRLPOOL_PORT}/g" "${template}"
sed -i "s/<app-samourai-server-db-ip>/${APP_SAMOURAI_SERVER_DB_IP}/g" "${template}"
sed -i "s/<app-samourai-server-node-ip>/${APP_SAMOURAI_SERVER_NODE_IP}/g" "${template}"
done

6
templates/.env-sample

@ -50,3 +50,9 @@ APP_MEMPOOL_IP=<app-mempool-ip>
APP_MEMPOOL_PORT=<app-mempool-port>
APP_MEMPOOL_DB_IP=<app-mempool-db-ip>
APP_MEMPOOL_API_IP=<app-mempool-api-ip>
APP_SAMOURAI_SERVER_IP=<app-samourai-server-ip>
APP_SAMOURAI_SERVER_PORT=<app-samourai-server-port>
APP_SAMOURAI_SERVER_WHIRLPOOL_IP=<app-samourai-server-whirlpool-ip>
APP_SAMOURAI_SERVER_WHIRLPOOL_PORT=<app-samourai-server-whirlpool-port>
APP_SAMOURAI_SERVER_DB_IP=<app-samourai-server-db-ip>
APP_SAMOURAI_SERVER_NODE_IP=<app-samourai-server-node-ip>

8
templates/torrc-sample

@ -65,4 +65,12 @@ HiddenServicePort 80 <app-btcpay-server-ip>:<app-btcpay-server-port>
HiddenServiceDir /var/lib/tor/app-mempool
HiddenServicePort 80 <app-mempool-ip>:<app-mempool-port>
# samourai-server Hidden Service
HiddenServiceDir /var/lib/tor/app-samourai-server
HiddenServicePort 80 <app-samourai-server-ip>:80
# samourai-server whirlpool Hidden Service
HiddenServiceDir /var/lib/tor/app-samourai-server-whirlpool
HiddenServicePort 80 <app-samourai-server-whirlpool-ip>:<app-samourai-server-whirlpool-port>
HashedControlPassword <password>

Loading…
Cancel
Save