diff --git a/monero/data/app/.gitkeep b/monero/data/app/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/monero/data/i2pd/.gitkeep b/monero/data/i2pd/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/monero/data/monero/.gitkeep b/monero/data/monero/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/monero/docker-compose.yml b/monero/docker-compose.yml new file mode 100644 index 00000000..eba7b25f --- /dev/null +++ b/monero/docker-compose.yml @@ -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}" diff --git a/monero/exports.sh b/monero/exports.sh new file mode 100644 index 00000000..c687aa18 --- /dev/null +++ b/monero/exports.sh @@ -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")" \ No newline at end of file diff --git a/monero/hooks/pre-start b/monero/hooks/pre-start new file mode 100755 index 00000000..736f3b52 --- /dev/null +++ b/monero/hooks/pre-start @@ -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 \ No newline at end of file diff --git a/monero/scripts/rpcauth.py b/monero/scripts/rpcauth.py new file mode 100755 index 00000000..784f2ff5 --- /dev/null +++ b/monero/scripts/rpcauth.py @@ -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() diff --git a/monero/torrc.template b/monero/torrc.template new file mode 100644 index 00000000..baeca6f4 --- /dev/null +++ b/monero/torrc.template @@ -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 \ No newline at end of file diff --git a/monero/umbrel-app.yml b/monero/umbrel-app.yml new file mode 100644 index 00000000..c1921e05 --- /dev/null +++ b/monero/umbrel-app.yml @@ -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: "" \ No newline at end of file