mirror of
https://github.com/getumbrel/umbrel-apps.git
synced 2024-11-11 16:09:18 +00:00
App Submission: Monero Node (#690)
Co-authored-by: nmfretz <nmfretz@gmail.com>
This commit is contained in:
parent
417d214271
commit
e70fb53470
0
monero/data/app/.gitkeep
Normal file
0
monero/data/app/.gitkeep
Normal file
0
monero/data/i2pd/.gitkeep
Normal file
0
monero/data/i2pd/.gitkeep
Normal file
0
monero/data/monero/.gitkeep
Normal file
0
monero/data/monero/.gitkeep
Normal file
78
monero/docker-compose.yml
Normal file
78
monero/docker-compose.yml
Normal file
|
@ -0,0 +1,78 @@
|
|||
version: "3.7"
|
||||
|
||||
services:
|
||||
app_proxy:
|
||||
environment:
|
||||
APP_HOST: monero_server_1
|
||||
APP_PORT: 9976
|
||||
|
||||
server:
|
||||
image: deverickapollo/umbrel-monero:v1.0.8@sha256:4cfb0a9b852175b73c9c3cb37771eb28c20fd21140bb85a98726dd6d09ee03f9
|
||||
depends_on: [monerod]
|
||||
restart: on-failure
|
||||
expose:
|
||||
- "9976"
|
||||
volumes:
|
||||
- ${APP_DATA_DIR}/data/app:/data # volume to persist advanced settings json
|
||||
- ${APP_MONERO_DATA_DIR}:/monero/.monero # volume to persist bitmonero.conf
|
||||
environment:
|
||||
PORT: "9976"
|
||||
MONERO_HOST: "${APP_MONERO_NODE_IP}"
|
||||
MONERO_P2P_PORT: "${APP_MONERO_P2P_PORT}"
|
||||
MONERO_RPC_PORT: "${APP_MONERO_RPC_PORT}"
|
||||
MONERO_RESTRICTED_RPC_PORT: "${APP_MONERO_RESTRICTED_RPC_PORT}"
|
||||
MONERO_DEFAULT_NETWORK: "${MONERO_DEFAULT_NETWORK}"
|
||||
MONERO_RPC_USER: "${APP_MONERO_RPC_USER}"
|
||||
MONERO_RPC_PASSWORD: "${APP_MONERO_RPC_PASS}"
|
||||
MONERO_RPC_HIDDEN_SERVICE: "${APP_MONERO_RPC_HIDDEN_SERVICE}"
|
||||
MONERO_P2P_HIDDEN_SERVICE: "${APP_MONERO_P2P_HIDDEN_SERVICE}"
|
||||
DEVICE_DOMAIN_NAME: "${DEVICE_DOMAIN_NAME}"
|
||||
MONEROD_IP: "${APP_MONERO_NODE_IP}"
|
||||
TOR_PROXY_IP: "${APP_MONERO_TOR_PROXY_IP}"
|
||||
TOR_PROXY_PORT: "9050"
|
||||
TOR_PROXY_CONTROL_PORT: "9051"
|
||||
TOR_PROXY_CONTROL_PASSWORD: "moneyprintergobrrr"
|
||||
I2P_DAEMON_IP: "${APP_MONERO_I2P_DAEMON_IP}"
|
||||
I2P_DAEMON_PORT: "7656"
|
||||
networks:
|
||||
default:
|
||||
ipv4_address: $APP_MONERO_IP
|
||||
|
||||
monerod:
|
||||
user: "1000:1000"
|
||||
restart: unless-stopped
|
||||
stop_grace_period: 15m
|
||||
command: "${APP_MONERO_COMMAND}"
|
||||
image: ghcr.io/sethforprivacy/simple-monerod:v0.18.3.3@sha256:4e07ca4119cd34d61684c44151296535cb9ba674e081d0a622432be4ac51c2c9
|
||||
ports:
|
||||
- "${APP_MONERO_P2P_PORT}:${APP_MONERO_P2P_PORT}"
|
||||
- "${APP_MONERO_RPC_PORT}:${APP_MONERO_RPC_PORT}"
|
||||
volumes:
|
||||
- "${APP_MONERO_DATA_DIR}:/home/monero/.bitmonero"
|
||||
networks:
|
||||
default:
|
||||
ipv4_address: $APP_MONERO_NODE_IP
|
||||
|
||||
tor:
|
||||
image: getumbrel/tor:0.4.7.8@sha256:2ace83f22501f58857fa9b403009f595137fa2e7986c4fda79d82a8119072b6a
|
||||
user: "1000:1000"
|
||||
restart: on-failure
|
||||
volumes:
|
||||
- ${APP_DATA_DIR}/torrc:/etc/tor/torrc:ro
|
||||
- ${TOR_DATA_DIR}:/data
|
||||
environment:
|
||||
HOME: "/tmp"
|
||||
networks:
|
||||
default:
|
||||
ipv4_address: "${APP_MONERO_TOR_PROXY_IP}"
|
||||
|
||||
# i2pd_daemon:
|
||||
# image: purplei2p/i2pd:release-2.44.0@sha256:d154a599793c393cf9c91f8549ba7ece0bb40e5728e1813aa6dd4c210aa606f6
|
||||
# user: "root"
|
||||
# command: --sam.enabled=true --sam.address=0.0.0.0 --sam.port=7656 --loglevel=error
|
||||
# restart: on-failure
|
||||
# volumes:
|
||||
# - ${APP_DATA_DIR}/data/i2pd:/home/i2pd/data
|
||||
# networks:
|
||||
# default:
|
||||
# ipv4_address: "${APP_MONERO_I2P_DAEMON_IP}"
|
95
monero/exports.sh
Normal file
95
monero/exports.sh
Normal file
|
@ -0,0 +1,95 @@
|
|||
export APP_MONERO_IP="10.21.22.178"
|
||||
export APP_MONERO_NODE_IP="10.21.21.179"
|
||||
export APP_MONERO_TOR_PROXY_IP="10.21.21.180"
|
||||
export APP_MONERO_I2P_DAEMON_IP="10.21.21.181"
|
||||
|
||||
export APP_MONERO_DATA_DIR="${EXPORTS_APP_DIR}/data/monero"
|
||||
export APP_MONERO_RPC_PORT="18081"
|
||||
export APP_MONERO_RESTRICTED_RPC_PORT="18089"
|
||||
export APP_MONERO_P2P_PORT="18080"
|
||||
export APP_MONERO_TOR_PORT="9901"
|
||||
|
||||
#temporarily set to mainnet
|
||||
MONERO_NETWORK="mainnet"
|
||||
MONERO_CHAIN="mainnet"
|
||||
MONERO_ENV_FILE="${EXPORTS_APP_DIR}/.env"
|
||||
|
||||
{
|
||||
MONERO_APP_CONFIG_FILE="${EXPORTS_APP_DIR}/data/app/monero-config.json"
|
||||
if [[ -f "${MONERO_APP_CONFIG_FILE}" ]]
|
||||
then
|
||||
monero_app_network=$(jq -r '.network' "${MONERO_APP_CONFIG_FILE}")
|
||||
case $monero_app_network in
|
||||
"mainnet")
|
||||
MONERO_NETWORK="mainnet";;
|
||||
"testnet")
|
||||
MONERO_NETWORK="testnet";;
|
||||
"stagenet")
|
||||
MONERO_NETWORK="stagenet";;
|
||||
esac
|
||||
fi
|
||||
} > /dev/null || true
|
||||
|
||||
|
||||
|
||||
if [[ ! -f "${MONERO_ENV_FILE}" ]]; then
|
||||
if [[ -z "${MONERO_NETWORK}" ]]; then
|
||||
MONERO_NETWORK="mainnet"
|
||||
fi
|
||||
|
||||
if [[ -z ${MONERO_RPC_USER+x} ]] || [[ -z ${MONERO_RPC_PASS+x} ]] || [[ -z ${MONERO_RPC_AUTH+x} ]]; then
|
||||
MONERO_RPC_USER="monero"
|
||||
MONERO_RPC_DETAILS=$("${EXPORTS_APP_DIR}/scripts/rpcauth.py" "${MONERO_RPC_USER}")
|
||||
MONERO_RPC_PASS=$(echo "$MONERO_RPC_DETAILS" | tail -1)
|
||||
MONERO_RPC_AUTH=$(echo "$MONERO_RPC_DETAILS" | head -2 | tail -1 | sed -e "s/^rpc-login=//")
|
||||
fi
|
||||
|
||||
echo "export APP_MONERO_NETWORK='${MONERO_NETWORK}'" > "${MONERO_ENV_FILE}"
|
||||
echo "export APP_MONERO_RPC_USER='${MONERO_RPC_USER}'" >> "${MONERO_ENV_FILE}"
|
||||
echo "export APP_MONERO_RPC_PASS='${MONERO_RPC_PASS}'" >> "${MONERO_ENV_FILE}"
|
||||
echo "export APP_MONERO_RPC_AUTH='${MONERO_RPC_AUTH}'" >> "${MONERO_ENV_FILE}"
|
||||
fi
|
||||
|
||||
. "${MONERO_ENV_FILE}"
|
||||
|
||||
# Make sure we don't persist the original value in .env if we have a more recent
|
||||
# value from the app config
|
||||
{
|
||||
if [[ ! -z ${MONERO_NETWORK+x} ]] && [[ "${MONERO_NETWORK}" ]] && [[ "${APP_MONERO_NETWORK}" ]]
|
||||
then
|
||||
APP_MONERO_NETWORK="${MONERO_NETWORK}"
|
||||
fi
|
||||
} > /dev/null || true
|
||||
|
||||
if [[ "${APP_MONERO_NETWORK}" == "mainnet" ]]; then
|
||||
MONERO_CHAIN="mainnet"
|
||||
elif [[ "${APP_MONERO_NETWORK}" == "testnet" ]]; then
|
||||
MONERO_CHAIN="testnet"
|
||||
export APP_MONERO_RPC_PORT="28081"
|
||||
export APP_MONERO_P2P_PORT="28080"
|
||||
|
||||
elif [[ "${APP_MONERO_NETWORK}" == "stagenet" ]]; then
|
||||
MONERO_CHAIN="stagenet"
|
||||
export APP_MONERO_RPC_PORT="38081"
|
||||
export APP_MONERO_P2P_PORT="38080"
|
||||
else
|
||||
echo "Warning (${EXPORTS_APP_ID}): Monero Network '${APP_MONERO_NETWORK}' is not supported"
|
||||
fi
|
||||
|
||||
export MONERO_DEFAULT_NETWORK="${MONERO_CHAIN}"
|
||||
|
||||
BIN_ARGS=()
|
||||
BIN_ARGS+=( "--rpc-bind-port=${APP_MONERO_RPC_PORT}" )
|
||||
BIN_ARGS+=( "--rpc-bind-ip=0.0.0.0" )
|
||||
BIN_ARGS+=( "--confirm-external-bind" )
|
||||
|
||||
BIN_ARGS+=( "--rpc-login=\"${APP_MONERO_RPC_AUTH}\"" )
|
||||
|
||||
export APP_MONERO_COMMAND=$(IFS=" "; echo "${BIN_ARGS[@]}")
|
||||
|
||||
# echo "${APP_MONERO_COMMAND}"
|
||||
|
||||
rpc_hidden_service_file="${EXPORTS_TOR_DATA_DIR}/app-${EXPORTS_APP_ID}-rpc/hostname"
|
||||
p2p_hidden_service_file="${EXPORTS_TOR_DATA_DIR}/app-${EXPORTS_APP_ID}-p2p/hostname"
|
||||
export APP_MONERO_RPC_HIDDEN_SERVICE="$(cat "${rpc_hidden_service_file}" 2>/dev/null || echo "notyetset.onion")"
|
||||
export APP_MONERO_P2P_HIDDEN_SERVICE="$(cat "${p2p_hidden_service_file}" 2>/dev/null || echo "notyetset.onion")"
|
26
monero/hooks/pre-start
Executable file
26
monero/hooks/pre-start
Executable file
|
@ -0,0 +1,26 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Delay booting Monero until the RPC and P2P Tor Hidden Services are ready
|
||||
|
||||
HIDDEN_SERVICE_FILE="${TOR_DATA_DIR}/app-${APP_ID}-rpc/hostname"
|
||||
|
||||
if [[ -f "${HIDDEN_SERVICE_FILE}" ]]; then
|
||||
exit
|
||||
fi
|
||||
|
||||
"${UMBREL_ROOT}/scripts/app" compose "${APP_ID}" up --detach monerod
|
||||
"${UMBREL_ROOT}/scripts/app" compose "${APP_ID}" up --detach tor
|
||||
|
||||
echo "App: ${APP_ID} - Generating Tor Hidden Service..."
|
||||
|
||||
for attempt in $(seq 1 100); do
|
||||
if [[ -f "${HIDDEN_SERVICE_FILE}" ]]; then
|
||||
echo "App: ${APP_ID} - Hidden service file created successfully!"
|
||||
break
|
||||
fi
|
||||
sleep 0.1
|
||||
done
|
||||
|
||||
if [[ ! -f "${HIDDEN_SERVICE_FILE}" ]]; then
|
||||
echo "App: ${APP_ID} - Hidden service file wasn't created"
|
||||
fi
|
47
monero/scripts/rpcauth.py
Executable file
47
monero/scripts/rpcauth.py
Executable file
|
@ -0,0 +1,47 @@
|
|||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2015-2018 The Bitcoin Core developers
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
from argparse import ArgumentParser
|
||||
from base64 import urlsafe_b64encode
|
||||
from binascii import hexlify
|
||||
from getpass import getpass
|
||||
from os import urandom
|
||||
|
||||
import hmac
|
||||
|
||||
def generate_salt(size):
|
||||
"""Create size byte hex salt"""
|
||||
return hexlify(urandom(size)).decode()
|
||||
|
||||
def generate_password():
|
||||
"""Create 32 byte b64 password"""
|
||||
return urlsafe_b64encode(urandom(32)).decode('utf-8')
|
||||
|
||||
def password_to_hmac(salt, password):
|
||||
m = hmac.new(bytearray(salt, 'utf-8'), bytearray(password, 'utf-8'), 'SHA256')
|
||||
return m.hexdigest()
|
||||
|
||||
def main():
|
||||
parser = ArgumentParser(description='Create login credentials for a JSON-RPC user')
|
||||
parser.add_argument('username', help='the username for authentication')
|
||||
parser.add_argument('password', help='leave empty to generate a random password or specify "-" to prompt for password', nargs='?')
|
||||
args = parser.parse_args()
|
||||
|
||||
if not args.password:
|
||||
args.password = generate_password()
|
||||
elif args.password == '-':
|
||||
args.password = getpass()
|
||||
|
||||
# Create 16 byte hex salt
|
||||
# salt = generate_salt(16)
|
||||
# password_hmac = password_to_hmac(salt, args.password)
|
||||
|
||||
print('String to be appended to monerod.conf:')
|
||||
# Replaced rpcauth with rpc-login to support monero daemon rpc login format (username:password) instead of (username:salt$hash)
|
||||
print('rpc-login={0}:{1}'.format(args.username, args.password))
|
||||
print('Your password:\n{0}'.format(args.password))
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
13
monero/torrc.template
Normal file
13
monero/torrc.template
Normal file
|
@ -0,0 +1,13 @@
|
|||
SocksPort 0.0.0.0:9050
|
||||
ControlPort 0.0.0.0:9051
|
||||
CookieAuthentication 1
|
||||
CookieAuthFileGroupReadable 1
|
||||
HashedControlPassword 16:39AF5EEFA4FC1D986022FDFB13663669FE50FB6DE9A3B4FE4FC7D82010 # moneyprintergobrrr
|
||||
|
||||
# MONERO Core P2P Hidden Service
|
||||
HiddenServiceDir /data/app-$APP_ID-p2p
|
||||
HiddenServicePort $APP_MONERO_P2P_PORT $APP_MONERO_NODE_IP:$APP_MONERO_TOR_PORT
|
||||
|
||||
# MONERO Core RPC Hidden Service
|
||||
HiddenServiceDir /data/app-$APP_ID-rpc
|
||||
HiddenServicePort $APP_MONERO_RPC_PORT $APP_MONERO_NODE_IP:$APP_MONERO_RPC_PORT
|
25
monero/umbrel-app.yml
Normal file
25
monero/umbrel-app.yml
Normal file
|
@ -0,0 +1,25 @@
|
|||
manifestVersion: 1.1
|
||||
id: monero
|
||||
category: finance
|
||||
name: Monero Node
|
||||
version: "0.18.3.3"
|
||||
tagline: Run a monero node
|
||||
description: >-
|
||||
Run your monero node and independently store and validate every single Monero transaction with it.
|
||||
This is a full node that will download the entire Monero blockchain and store it on your Umbrel.
|
||||
This is the most secure way to run a Monero node, but it will take a long time to sync and will require a lot of storage space.
|
||||
developer: deverickapollo
|
||||
website: https://www.getmonero.org/
|
||||
dependencies: []
|
||||
repo: https://github.com/deverickapollo/umbrel-monero
|
||||
support: https://github.com/deverickapollo/umbrel-monero/issues
|
||||
port: 9976
|
||||
submitter: deverickapollo
|
||||
submission: https://github.com/getumbrel/umbrel-apps/pull/690
|
||||
gallery:
|
||||
- 1.jpg
|
||||
- 2.jpg
|
||||
- 3.jpg
|
||||
path: ""
|
||||
defaultPassword: ""
|
||||
releaseNotes: ""
|
Loading…
Reference in New Issue
Block a user