Browse Source

Merge pull request #8 from getumbrel/default-node-config

Merged to master
master 0.0.2
BT 5 years ago
committed by GitHub
parent
commit
d0b08d9ef5
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 57
      README.md
  2. 16
      stage2/01-sys-tweaks/01-run.sh
  3. 39
      stage2/01-sys-tweaks/files/rc.local
  4. 46
      stage2/04-docker-compose/01-run.sh
  5. 56
      stage2/04-docker-compose/files/compose-service
  6. 135
      stage2/04-docker-compose/files/umbrel-createwallet.py
  7. 28
      stage2/04-docker-compose/files/umbrel-unlock.py
  8. 7
      stage2/05-prepare-home-dir/01-run.sh
  9. 2
      stage2/06-fix-docker-perms/01-run.sh
  10. 6
      stage2/07-configure-LND/01-run.sh
  11. 38
      stage2/07-configure-LND/files/lnd.conf
  12. 8
      stage2/07-pip-install-deps/01-run.sh
  13. 14
      stage2/08-configure-bitcoind/01-run.sh
  14. 32
      stage2/08-configure-bitcoind/files/bitcoin.conf
  15. 6
      stage2/09-configure-tor/01-run.sh
  16. 22
      stage2/09-configure-tor/files/torrc

57
README.md

@ -13,6 +13,63 @@ Customized Underlying Raspbian Operating System for the Umbrel box (based on htt
Alternatively, you may check the latest release too and you may find the image built automatically by github (upon tagging).
## Default logins
Hostname: umbrel.local
Username: umbrel
Password: umbr3lb0x
You may also find them [here](https://github.com/getumbrel/os-base/wiki/Box-System-Defaults)
### Config variables
In the config file there are system defaults, which are used when building the image and for automated builds.
* **GITHUB_USERNAME** - Used if you want to automatically log in to the box without typing a password. This is used at build time.
Then theres other raspbian stuff, that you may find in the [Raspbian documentation](https://github.com/RPi-Distro/pi-gen/blob/master/README.md) which will still work.
## Post bootup checks
For building an API (or scripting), look in /home/umbrel/statuses for the following files
* **disk-partitioned** : meaning the disk is partitioned
* **service-configured** : meaning the umbrel system bootup service is configured and running.
(To add more later as needed)
## Console Commands (Cheat codes)
There is some console commands you can run.
### Lightning Console Commands
#### Get Info
```
docker exec -it "${USER}_lnd_1" lncli getinfo
```
#### Wallet Balance
```
docker exec -it "${USER}_lnd_1" lncli walletbalance
```
#### List Channels
```
docker exec -it "${USER}_lnd_1" lncli listchannels
```
#### Opening a channel
```bash
# where XXX = sats per byte and YYY = the amount
docker exec -it "${USER}_lnd_1" lncli connect pubkey@host:port
docker exec -it "${USER}_lnd_1" lncli open --sat_per_byte=XXX pubkey YYY
# Return value is the txid
```
## TODO:
See the [following list](https://github.com/getumbrel/os-base/labels/TODO)

16
stage2/01-sys-tweaks/01-run.sh

@ -25,6 +25,22 @@ fi
systemctl enable regenerate_ssh_host_keys
EOF
if [ ! -d $ROOTFS_DIR/home/statuses ]; then
echo "Making a directory called 'statuses' for storing statuses of services"
mkdir $ROOTFS_DIR/home/statuses
fi
if [ ! -z ${GITHUB_USERNAME} ]; then
echo "Setting up authorized_keys file"
mkdir -p $ROOTFS_DIR/home/$FIRST_USER_NAME
cd $ROOTFS_DIR/home/$FIRST_USER_NAME
echo "Making .ssh directory"
mkdir -p .ssh
cd .ssh
echo "Fetching from github the ssh keys"
curl "https://github.com/${GITHUB_USERNAME}.keys" > authorized_keys
fi
if [ "${USE_QEMU}" = "1" ]; then
echo "enter QEMU mode"
install -m 644 files/90-qemu.rules "${ROOTFS_DIR}/etc/udev/rules.d/"

39
stage2/01-sys-tweaks/files/rc.local

@ -17,4 +17,43 @@ if [ "$_IP" ]; then
printf "My IP address is %s\n" "$_IP"
fi
# Check for statuses directory
if [ ! -d /home/umbrel/statuses ]; then
mkdir -p /home/umbrel/statuses
chown umbrel.umbrel /home/umbrel/statuses
fi
# Check for disk partition status
if [ ! -f /home/umbrel/statuses/disk-partitioned ]; then
echo "Placeholder for disk partitioning tool"
# Do partitioning at first boot
fi
if [ ! -f /home/umbrel/statuses/service-configured ]; then
if [ -f /home/umbrel/bin/rpcauth.py ]; then
echo "Running rpcauth.py, and generating secrets for bitcoind"
cd /home/umbrel/bin/
./rpcauth.py lncm | tee /home/umbrel/secrets/generated.txt | head -2 | tail -1 > /home/umbrel/secrets/rpcauth.txt
tail -1 /home/umbrel/secrets/generated.txt > /home/umbrel/secrets/rpcpass.txt
echo "Updating bitcoin.conf"
cat /home/umbrel/secrets/rpcauth.txt >> /home/umbrel/bitcoin/bitcoin.conf
# Update RPC Passwords for both LND and INVOICER
RPCPASS=`cat /home/umbrel/secrets/rpcpass.txt`
sed -i "s/RPCPASS/${RPCPASS}/g;" /home/umbrel/invoicer/invoicer.conf
sed -i "s/RPCPASS/${RPCPASS}/g;" /home/umbrel/lnd/lnd.conf
echo "Enabling defaults for umbrelbox"
update-rc.d umbrelbox defaults || exit 1
echo "Enabling startup for umbrel box"
update-rc.d umbrelbox enable || exit 1
echo "starting up umbrelbox get it started now)"
/etc/init.d/umbrelbox start
# TODO: maybe configure wallet when startup is complete? (or put it inside docker-compose)
# Making this as done so we don't go through updates again
touch /home/umbrel/statuses/service-configured
fi
fi
exit 0

46
stage2/04-docker-compose/01-run.sh

@ -1,10 +1,52 @@
# Install docker via pip3 (within chroot)
echo "Installing docker-compose from pip3, and also setting up the box folder structure"
on_chroot << EOF
pip3 install docker-compose
cd /home/${FIRST_USER_NAME}
wget -qO- "https://raw.githubusercontent.com/lncm/thebox-compose-system/master/install-box.sh" | sh
chown -R ${FIRST_USER_NAME}:${FIRST_USER_NAME} /home/${FIRST_USER_NAME}
EOF
# Maybe generate a compose file to use
echo "Docker stuff installed" >> $ROOTFS_DIR/home/$FIRST_USER_NAME/docker-compose.txt
# Maybe generate docker-compose file so we can use it
chmod 755 files/compose-service
# These can be probabably removed
cp files/umbrel-createwallet.py ${ROOTFS_DIR}/home/${FIRST_USER_NAME}/umbrel-createwallet.py
cp files/umbrel-unlock.py ${ROOTFS_DIR}/home/${FIRST_USER_NAME}/umbrel-unlock.py
# Docker compose service
on_chroot << EOF
mkdir -p /etc/init.d
mkdir -p /etc/rc2.d
mkdir -p /etc/rc3.d
mkdir -p /etc/rc4.d
mkdir -p /etc/rc5.d
mkdir -p /etc/rc0.d
mkdir -p /etc/rc1.d
mkdir -p /etc/rc6.d
EOF
echo "Copying the compose service to rootfs (etc/init.d)"
cp files/compose-service ${ROOTFS_DIR}/etc/init.d/umbrelbox
on_chroot << EOF
cd /etc/rc2.d
ln -s /etc/init.d/umbrelbox S01umbrelbox
cd /etc/rc3.d
ln -s /etc/init.d/umbrelbox S01umbrelbox
cd /etc/rc4.d
ln -s /etc/init.d/umbrelbox S01umbrelbox
cd /etc/rc5.d
ln -s /etc/init.d/umbrelbox S01umbrelbox
cd /etc/rc0.d
ln -s /etc/init.d/umbrelbox K01umbrelbox
cd /etc/rc1.d
ln -s /etc/init.d/umbrelbox K01umbrelbox
cd /etc/rc6.d
ln -s /etc/init.d/umbrelbox K01umbrelbox
EOF
echo "Docker stuff installed!"

56
stage2/04-docker-compose/files/compose-service

@ -0,0 +1,56 @@
#!/bin/sh
set -e
### BEGIN INIT INFO
# Provides: docker-compose service
# Required-Start: $syslog $remote_fs docker
# Required-Stop: $syslog $remote_fs docker
# Should-Start: cgroupfs-mount cgroup-lite
# Should-Stop: cgroupfs-mount cgroup-lite
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Starts docker-compose
# Description: Start docker-compose
### END INIT INFO
NAME="compose-service"
DESCRIPTION="Docker compose service"
SCRIPTNAME=/etc/init.d/$NAME
case "$1" in
start)
if [ -f /home/umbrel/docker-compose.yml ]; then
sed -i 's/\${HOME}/\/home\/umbrel/g; ' /home/umbrel/docker-compose.yml
echo "Starting"
cd /home/umbrel
docker-compose up -d
exit 0
else
echo "Docker-compose file doesn't exist"
exit 1
fi
;;
stop)
if [ -f /home/umbrel/docker-compose.yml ]; then
sed -i 's/\${HOME}/\/home\/umbrel/g; ' /home/umbrel/docker-compose.yml
echo "Stopping docker"
cd /home/umbrel
docker-compose down
exit 0
else
echo "Docker-compose file doesn't exist"
exit 1
fi
;;
status)
echo "Status"
docker ps -a
exit 0
;;
*)
echo "Either 'start', 'stop', or 'status'"
exit 1
;;
esac
exit 0

135
stage2/04-docker-compose/files/umbrel-createwallet.py

@ -0,0 +1,135 @@
#!/usr/bin/env python3
'''
Copyright © 2018-2019 LNCM Contributors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Documented logic
1. Check if theres already a wallet. If there is, then exit.
2. Check for sesame.txt
3. If doesn't exist then check for whether we should save the password (save_password_control_file exists) or not
4. If sesame.txt exists import password in.
5. If sesame.txt doesn't exist ans we don't save the password,create a password and save it in temporary path as defined in temp_password_file_path
6. Now start the wallet creation. Look for a seed defined in seed_filename , if not existing then generate a wallet based on the seed by LND.
'''
import base64, codecs, json, requests, os
import random, string
# Generate seed
url = 'https://localhost:8080/v1/genseed'
# Initialize wallet
url2 = 'https://localhost:8080/v1/initwallet'
cert_path = '/home/umbrel/lnd/tls.cert'
seed_filename = '/home/umbrel/secrets/seed.txt'
# save password control file (Add this file if we want to save passwords)
save_password_control_file = '/home/umbrel/.save_password'
# Create password for writing
temp_password_file_path = '/tmp/.password.txt'
'''
Functions have 2 spaces
'''
def randompass(stringLength=10):
letters = string.ascii_letters
return ''.join(random.choice(letters) for i in range(stringLength))
def main():
if not os.path.exists(save_password_control_file):
# Generate password but dont save it in usual spot
password_str=randompass(stringLength=15)
temp_password_file = open(temp_password_file_path, "w")
# Check if there is an existing file, if not generate a random password
if not os.path.exists("/home/umbrel/secrets/lnd-password.txt"):
# sesame file doesnt exist
password_str=randompass(stringLength=15)
if not os.path.exists(save_password_control_file):
# Use tempory file if there is a password control file there
temp_password_file = open(temp_password_file_path, "w")
temp_password_file.write(password_str)
temp_password_file.close()
else:
# Use sesame.txt if password_control_file exists
password_file = open("/home/umbrel/secrets/lnd-password.txt","w")
password_file.write(password_str)
password_file.close()
else:
# Get password from file if sesame file already exists
password_str = open('/home/umbrel/secrets/lnd-password.txt', 'r').read().rstrip()
# Convert password to byte encoded
password_bytes = str(password_str).encode('utf-8')
# Step 1 get seed from web or file
# Send request to generate seed if seed file doesnt exist
if not os.path.exists(seed_filename):
r = requests.get(url, verify=cert_path)
if r.status_code == 200:
json_seed_creation = r.json()
json_seed_mnemonic = json_seed_creation['cipher_seed_mnemonic']
json_enciphered_seed = json_seed_creation['enciphered_seed']
seed_file = open(seed_filename, "w")
for word in json_seed_mnemonic:
seed_file.write(word + "\n")
seed_file.close()
data = { 'cipher_seed_mnemonic': json_seed_mnemonic, 'wallet_password': base64.b64encode(password_bytes).decode()}
# Data doesnt get set if cant create the seed but that is fine, handle it later
else:
# Seed exists
seed_file = open(seed_filename, "r")
seed_file_words = seed_file.readlines()
import_file_array = []
for importword in seed_file_words:
import_file_array.append(importword.replace("\n", ""))
# Generate init wallet file from what was posted
data = { 'cipher_seed_mnemonic': import_file_array, 'wallet_password': base64.b64encode(password_bytes).decode()}
# Step 2: Create wallet
try:
data
except NameError:
print("data isn't defined")
pass
else:
# Data is defined so proceed
r2 = requests.post(url2, verify=cert_path, data=json.dumps(data))
if r2.status_code == 200:
# If create wallet was successful
print("Create wallet is successful")
else:
print("Create wallet is not successful")
'''
Main entrypoint function
Testing creation notes:
rm /home/lncm/seed.txt
rm /media/important/important/lnd/sesame.txt
docker stop compose_lndbox_1 ; rm -fr /media/important/important/lnd/data/chain/ ; docker start compose_lndbox_1
'''
if __name__ == '__main__':
if os.path.exists("/home/umbrel/lnd"):
if not os.path.exists("/home/umbrel/lnd/data/chain/bitcoin/mainnet/wallet.db"):
main()
else:
print('Wallet already exists! Please delete .lnd/data/chain and then restart LND')
else:
print('LND directory does not exist!')

28
stage2/04-docker-compose/files/umbrel-unlock.py

@ -0,0 +1,28 @@
#!/usr/bin/env python3
import base64, codecs, json, requests
url = 'https://localhost:8080/v1/unlockwallet'
cert_path = '/home/umbrel/lnd/tls.cert'
password_str = open('/home/umbrel/secrets/lnd-password.txt', 'r').read().rstrip()
password_bytes = str(password_str).encode('utf-8')
data = {
'wallet_password': base64.b64encode(password_bytes).decode(),
}
def main():
try:
r = requests.post(url, verify=cert_path, data=json.dumps(data))
except:
# Silence connection errors when lnd is not running
pass
else:
try:
print(r.json())
except:
# JSON will fail to decode when unlocked already since response is empty
pass
if __name__ == '__main__':
main()

7
stage2/05-prepare-home-dir/01-run.sh

@ -1,4 +1,7 @@
# Test out image
echo "Hello World" >> $ROOTFS_DIR/home/$FIRST_USER_NAME/hello.txt
# Save password (for createwallet script).
# We will remove this later when a more suitable secure system is finalized.
touch $ROOTFS_DIR/home/$FIRST_USER_NAME/.save_password
echo "Executables directory"
mkdir -p $ROOTFS_DIR/home/$FIRST_USER_NAME/bin

2
stage2/06-fix-docker-perms/01-run.sh

@ -1,5 +1,7 @@
echo "Adding lncm to DOCKER group"
echo "Also fixing permissions on folders"
on_chroot << EOF
usermod -a -G docker $FIRST_USER_NAME
chown -R $FIRST_USER_NAME:$FIRST_USER_NAME /home/$FIRST_USER_NAME
EOF

6
stage2/07-configure-LND/01-run.sh

@ -0,0 +1,6 @@
chmod 644 files/lnd.conf
echo "Copying lnd.conf to overwrite the existing LND.conf"
cp files/lnd.conf ${ROOTFS_DIR}/home/${FIRST_USER_NAME}/lnd/lnd.conf
on_chroot << EOF
chown -R ${FIRST_USER_NAME}:${FIRST_USER_NAME} /home/${FIRST_USER_NAME}
EOF

38
stage2/07-configure-LND/files/lnd.conf

@ -0,0 +1,38 @@
[Application Options]
listen=0.0.0.0:9735
rpclisten=0.0.0.0:10009
restlisten=0.0.0.0:8080
maxpendingchannels=3
minchansize=1337
alias=Umbrel Node
color=#5351FB
; Makes routing faster but have to use images built with experimental tag
[Routing]
routing.assumechanvalid=1
[Bitcoin]
; If the Bitcoin chain should be active. Atm, only a single chain can be
; active.
bitcoin.active=1
bitcoin.mainnet=1
; Use neutrino for now, but maybe it could be permanent and then switch
; to a full node once its working?
bitcoin.node=neutrino
bitcoin.defaultchanconfs=2
; Add neutrino peers
; TODO: umbrel to set up a neutrino peer to support umbrel nodes
[neutrino]
neutrino.addpeer=bb2.breez.technology
neutrino.addpeer=mainnet1-btcd.zaphq.io
neutrino.addpeer=mainnet2-btcd.zaphq.io
[tor]
tor.active=1
tor.control=9051
tor.socks=9050
tor.v3=1
tor.dns=soa.nodes.lightning.directory:53

8
stage2/07-pip-install-deps/01-run.sh

@ -1,8 +0,0 @@
echo "Install Python dependencies"
## Add in any python dependencies within the chroot
on_chroot << EOF
pip3 install noma
EOF

14
stage2/08-configure-bitcoind/01-run.sh

@ -0,0 +1,14 @@
# TODO: configure username and password (internally)
chmod 644 files/bitcoin.conf
mkdir ${ROOTFS_DIR}/home/${FIRST_USER_NAME}/bitcoin
cp files/bitcoin.conf ${ROOTFS_DIR}/home/${FIRST_USER_NAME}/bitcoin/bitcoin.conf
echo "Downloading password utility"
cd ${ROOTFS_DIR}/home/${FIRST_USER_NAME}/bin
curl "https://raw.githubusercontent.com/bitcoin/bitcoin/master/share/rpcauth/rpcauth.py" 2>/dev/null 1>rpcauth.py
chmod 755 rpcauth.py
on_chroot << EOF
chown -R ${FIRST_USER_NAME}:${FIRST_USER_NAME} /home/${FIRST_USER_NAME}
EOF

32
stage2/08-configure-bitcoind/files/bitcoin.conf

@ -0,0 +1,32 @@
onion=127.0.0.1:9050
torcontrol=127.0.0.1:9051
server=1
rest=1
# Some Pi optimizations
maxmempool=512
maxconnections=40
maxuploadtarget=5000
port=8333
rpcport=8332
# Keep it pruned while we don't have a extenal drive to work with
prune=550
# When we have one we remove this
# Temporary solution while we don't have the drives
# txindex=1
# blockfilterindex=1
peerbloomfilters=0
addresstype=bech32
avoidpartialspends=1
logips=1
logtimestamps=0
logthreadnames=1
nodebuglogfile=1
rpcbind=0.0.0.0

6
stage2/09-configure-tor/01-run.sh

@ -0,0 +1,6 @@
# TODO: configure username and password (internally)
chmod 644 files/torrc
mkdir -p ${ROOTFS_DIR}/etc/tor/
echo "Overriding TORRC"
cp files/torrc ${ROOTFS_DIR}/etc/tor/torrc

22
stage2/09-configure-tor/files/torrc

@ -0,0 +1,22 @@
SocksPort 9050 # Default: Bind to localhost:9050 for local connections.
Log notice syslog
Log debug file /var/log/tor/debug.log
#RunAsDaemon 1
DataDirectory /var/lib/tor
ControlPort 9051
# Use password Later when lnd supports it
#HashedControlPassword 16:872860B76453A77D60CA2BB8C1A7042072093276A3D701AD684053EC4C
CookieAuthentication 1
# Allow this for now
# TOR HOSTNAME
HiddenServiceDir /var/lib/tor/sshd
HiddenServicePort 22 127.0.0.1:22
HiddenServiceDir /var/lib/tor/web
HiddenServicePort 80 127.0.0.1:80
Loading…
Cancel
Save