diff --git a/CHANGES.md b/CHANGES.md index d253b42ba..17a50f6d1 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -23,7 +23,7 @@ - Update: JoinMarket 0.8.2 [details](https://github.com/JoinMarket-Org/joinmarket-clientserver/releases/tag/v0.8.2) - Update: JoininBox 0.3.4 [details](https://github.com/openoms/joininbox/releases/tag/v0.3.2) - Update: mempool v2.1.2 [detail](https://github.com/mempool/mempool/releases/tag/v2.1.2) -- Update: BTC-RPC-Explorer v2.0.0 [details](https://github.com/janoside/btc-rpc-explorer/blob/master/CHANGELOG.md#v220) +- Update: BTC-RPC-Explorer v3.0.0 [details](https://github.com/janoside/btc-rpc-explorer/blob/master/CHANGELOG.md#v300) - Update: stacking-sats-kraken 0.4.2 [details](https://github.com/dennisreimann/stacking-sats-kraken/blob/master/README.md) ## Whats new in Version 1.6.3 of RaspiBlitz? diff --git a/FAQ.md b/FAQ.md index fdf8203a9..6bc4f9d94 100644 --- a/FAQ.md +++ b/FAQ.md @@ -407,7 +407,7 @@ To build a SD card image from another branch than master, you follow the [Build For example if you want to make a build from the 'dev' branch you execute the following command: -`wget --no-cache https://raw.githubusercontent.com/rootzoll/raspiblitz/dev/build_sdcard.sh && sudo bash build_sdcard.sh false rootzoll dev lcd true true` +`wget --no-cache https://raw.githubusercontent.com/rootzoll/raspiblitz/dev/build_sdcard.sh && sudo bash build_sdcard.sh false false rootzoll dev lcd true true` ## How can I build an SD card from my forked GitHub Repo? @@ -417,7 +417,7 @@ If you fork the RaspiBlitz repo (much welcome) and you want to run that code on * The long way: If you like to install/remove/change services and system configurations you need to build a SD card from your own code. Prepare like in [Build the SD Card Image](README.md#build-the-sd-card-image) from the README but in the end run the command: -`wget --no-cache https://raw.githubusercontent.com/[GITHUB-USERNAME]/raspiblitz/[BRANCH]/build_sdcard.sh && sudo bash build_sdcard.sh false [GITHUB-USERNAME] [BRANCH] lcd true true` +`wget --no-cache https://raw.githubusercontent.com/[GITHUB-USERNAME]/raspiblitz/[BRANCH]/build_sdcard.sh && sudo bash build_sdcard.sh false false [GITHUB-USERNAME] [BRANCH] lcd true true` If you are then working in your forked repo and want to update the scripts on your RaspiBlitz with your latest repo changes, run `/home/admin/XXsyncScripts.sh` - That's OK as long as you don't make changes to the SD card build script - for that you would need to build a fresh SD card again from your repo. @@ -518,11 +518,11 @@ Work notes for the process of producing a new SD card image release: * Start [`Ubuntu LIVE`](http://releases.ubuntu.com/18.04.3/ubuntu-18.04.3-desktop-amd64.iso) from USB stick on the Build Computer (press F12 on startup) * Connect to a secure WiFi (hardware switch on) or LAN -* Download the latest RaspiOS-64bit namend in the [build_sdcard.sh](./build_sdcard.sh) and note the SHA256 checksum +* Download the latest RaspiOS-64bit (zip & sig file) namend in the [build_sdcard.sh](./build_sdcard.sh) and note the SHA256 checksum * From the browser `Show All Downloads` and from the context menu select `Open Containing Folder` * On that file manager open context (right click) on the white-space and select `Open in Terminal` * Compare the checksum with the one you just made note of, using `shasum -a 256 *.zip` -* Install curl if needed `sudo apt-get update && sudo apt-get install -f curl net-tools` +* Install curl if needed `sudo apt-get install -f curl net-tools` * Check signature: `curl https://www.raspberrypi.org/raspberrypi_downloads.gpg.key | gpg --import && gpg --verify *.sig` * The result should say "correct signature" and the fingerprint should end with `8738 CD6B 956F 460C` * Insert an NTFS formatted USB stick and use the file manager to move all files to the USB @@ -537,7 +537,7 @@ Work notes for the process of producing a new SD card image release: * In terminal `ssh pi@[IP-OF-RASPIBLITZ]` * Password is `raspberry` * Run the following command BUT REPLACE `[BRANCH]` with the branch-string of your latest version -* `wget --no-cache https://raw.githubusercontent.com/rootzoll/raspiblitz/[BRANCH]/build_sdcard.sh && sudo bash build_sdcard.sh true rootzoll [BRANCH] lcd true true` +* `wget --no-cache https://raw.githubusercontent.com/rootzoll/raspiblitz/[BRANCH]/build_sdcard.sh && sudo bash build_sdcard.sh false true rootzoll [BRANCH] lcd true true` * Monitor/Check outputs for warnings/errors - install LCD * Login new with `ssh admin@[IP-OF-RASPIBLITZ]` (pw: raspiblitz) and run `./XXprepareRelease.sh` * Disconnect WiFi/LAN on build laptop (hardware switch off) and shutdown diff --git a/build_sdcard.sh b/build_sdcard.sh index 1ffa140e2..e0fe6d842 100755 --- a/build_sdcard.sh +++ b/build_sdcard.sh @@ -9,12 +9,28 @@ ########################################################################## echo "" -echo "****************************************." +echo "*****************************************" echo "* RASPIBLITZ SD CARD IMAGE SETUP v1.7 *" -echo "****************************************." +echo "*****************************************" echo "For details on optional parameters - see build script source code:" -# 1st optional paramater: FATPACK +# 1st optional paramater: NO-INTERACTION +# ---------------------------------------- +# When 'true' then no questions will be ask on building .. so it can be used in build scripts +# for containers or as part of other build scripts (default is false) + +noInteraction="$1" +if [ ${#noInteraction} -eq 0 ]; then + noInteraction="false" +fi +if [ "${noInteraction}" != "true" ] && [ "${noInteraction}" != "false" ]; then + echo "ERROR: NO-INTERACTION parameter needs to be either 'true' or 'false'" + exit 1 +else + echo "1) will use NO-INTERACTION --> '${noInteraction}'" +fi + +# 2nd optional paramater: FATPACK # ------------------------------- # could be 'true' or 'false' (default) # When 'true' it will pre-install needed frameworks for additional apps and features @@ -23,7 +39,7 @@ echo "For details on optional parameters - see build script source code:" # install needed frameworks and libraries on demand when activated by user. # Use 'false' if you want to run your node without: go, dot-net, nodejs, docker, ... -fatpack="$1" +fatpack="$2" if [ ${#fatpack} -eq 0 ]; then fatpack="false" fi @@ -31,36 +47,36 @@ if [ "${fatpack}" != "true" ] && [ "${fatpack}" != "false" ]; then echo "ERROR: FATPACK parameter needs to be either 'true' or 'false'" exit 1 else - echo "1) will use FATPACK --> '${fatpack}'" + echo "2) will use FATPACK --> '${fatpack}'" fi -# 2st optional paramater: GITHUB-USERNAME +# 3rd optional paramater: GITHUB-USERNAME # --------------------------------------- # could be any valid github-user that has a fork of the raspiblitz repo - 'rootzoll' is default # The 'raspiblitz' repo of this user is used to provisioning sd card # with raspiblitz assets/scripts later on. # If this parameter is set also the branch needs to be given (see next parameter). -githubUser="$2" +githubUser="$3" if [ ${#githubUser} -eq 0 ]; then githubUser="rootzoll" fi -echo "2) will use GITHUB-USERNAME --> '${githubUser}'" +echo "3) will use GITHUB-USERNAME --> '${githubUser}'" -# 3rd optional paramater: GITHUB-BRANCH +# 4th optional paramater: GITHUB-BRANCH # ------------------------------------- # could be any valid branch of the given GITHUB-USERNAME forked raspiblitz repo - 'dev' is default -githubBranch="$3" +githubBranch="$4" if [ ${#githubBranch} -eq 0 ]; then githubBranch="dev" fi -echo "3) will use GITHUB-BRANCH --> '${githubBranch}'" +echo "4) will use GITHUB-BRANCH --> '${githubBranch}'" -# 4rd optional paramater: DISPLAY-CLASS +# 5th optional paramater: DISPLAY-CLASS # ---------------------------------------- # Could be 'hdmi', 'headless' or 'lcd' # On 'false' the standard video output is used (HDMI) by default. # https://github.com/rootzoll/raspiblitz/issues/1265#issuecomment-813369284 -displayClass="$4" +displayClass="$5" if [ ${#displayClass} -eq 0 ] || [ "${displayClass}" == "false" ]; then displayClass="hdmi" fi @@ -68,15 +84,15 @@ if [ "${displayClass}" != "hdmi" ] && [ "${displayClass}" != "lcd" ] && [ "${dis echo "ERROR: DISPLAY-CLASS parameter needs to be 'lcd', 'hdmi' or 'headless'" exit 1 else - echo "4) will use DISPLAY-CLASS --> '${displayClass}'" + echo "5) will use DISPLAY-CLASS --> '${displayClass}'" fi -# 5rd optional paramater: TWEAK-BOOTDRIVE +# 6th optional paramater: TWEAK-BOOTDRIVE # --------------------------------------- # could be 'true' (default) or 'false' # If 'true' it will try (based on the base OS) to optimize the boot drive. # If 'false' this will skipped. -tweakBootdrives="$5" +tweakBootdrives="$6" if [ ${#tweakBootdrives} -eq 0 ]; then tweakBootdrives="true" fi @@ -84,20 +100,20 @@ if [ "${tweakBootdrives}" != "true" ] && [ "${tweakBootdrives}" != "false" ]; th echo "ERROR: TWEAK-BOOTDRIVE parameter needs to be either 'true' or 'false'" exit 1 else - echo "5) will use TWEAK-BOOTDRIVE --> '${tweakBootdrives}'" + echo "6) will use TWEAK-BOOTDRIVE --> '${tweakBootdrives}'" fi -# 6rd optional paramater: WIFI +# 7th optional paramater: WIFI # --------------------------------------- # could be 'false' or 'true' (default) or a valid WIFI country code like 'US' (default) # If 'false' WIFI will be deactivated by default # If 'true' WIFI will be activated by with default country code 'US' # If any valid wifi country code Wifi will be activated with that country code by default -modeWifi="$6" +modeWifi="$7" if [ ${#modeWifi} -eq 0 ] || [ "${modeWifi}" == "true" ]; then modeWifi="US" fi -echo "6) will use WIFI --> '${modeWifi}'" +echo "7) will use WIFI --> '${modeWifi}'" # AUTO-DETECTION: CPU-ARCHITECTURE # --------------------------------------- @@ -156,17 +172,16 @@ fi echo "X) will use OPERATINGSYSTEM ---> '${baseimage}'" # USER-CONFIRMATION -echo -n "Do you agree with all parameters above? (yes/no) " -read installRaspiblitzAnswer -if [ "$installRaspiblitzAnswer" == "yes" ] ; then - echo "" - echo "" - echo "Building RaspiBlitz ..." - sleep 3 - echo "" -else - exit 1 +if [ "${noInteraction}" != "true" ]; then + echo -n "Do you agree with all parameters above? (yes/no) " + read installRaspiblitzAnswer + if [ "$installRaspiblitzAnswer" != "yes" ] ; then + exit 1 + fi fi +echo "Building RaspiBlitz ..." +echo "" +sleep 3 # INSTALL TOR echo "*** INSTALL TOR BY DEFAULT ***" @@ -353,70 +368,39 @@ echo "*** CONFIG ***" echo "root:raspiblitz" | sudo chpasswd echo "pi:raspiblitz" | sudo chpasswd -# if not headless - make sure pi user is doing auto login to run display -if [ "${displayClass}" != "headless" ]; then - - # activate auto-login of pi user - if [ "${baseimage}" = "raspbian" ]||[ "${baseimage}" = "raspios_arm64" ]||\ - [ "${baseimage}" = "debian_rpi64" ]; then - # set Raspi to boot up automatically with user pi (for the LCD) - # https://www.raspberrypi.org/forums/viewtopic.php?t=21632 - sudo raspi-config nonint do_boot_behaviour B2 - sudo bash -c "echo '[Service]' >> /etc/systemd/system/getty@tty1.service.d/autologin.conf" - sudo bash -c "echo 'ExecStart=' >> /etc/systemd/system/getty@tty1.service.d/autologin.conf" - sudo bash -c "echo 'ExecStart=-/sbin/agetty --autologin pi --noclear %I 38400 linux' >> /etc/systemd/system/getty@tty1.service.d/autologin.conf" - elif [ "${baseimage}" = "dietpi" ]; then - # set DietPi to boot up automatically with user pi (for the LCD) - # requires AUTO_SETUP_AUTOSTART_TARGET_INDEX=7 in the dietpi.txt - # /DietPi/dietpi/dietpi-autostart overwrites /etc/systemd/system/getty@tty1.service.d/dietpi-autologin.conf on reboot - sudo sed -i 's/agetty --autologin root %I $TERM/agetty --autologin pi --noclear %I 38400 linux/' /DietPi/dietpi/dietpi-autostart - elif [ "${baseimage}" = "ubuntu" ] || [ "${baseimage}" = "armbian" ]; then - sudo bash -c "echo '[Service]' >> /lib/systemd/system/getty@.service" - sudo bash -c "echo 'ExecStart=' >> /lib/systemd/system/getty@.service" - sudo bash -c "echo 'ExecStart=-/sbin/agetty --autologin pi --noclear %I 38400 linux' >> /lib/systemd/system/getty@.service" - else - echo "FAIL: Autostart pi user not available for baseimage(${baseimage}) - please choose 'headless' on DISPLAY-CLASS" - exit 1 - fi - - # activate auto-start of 00infoLCD.sh script on pi user login - if [ "${baseimage}" = "raspbian" ]||[ "${baseimage}" = "raspios_arm64" ]||\ - [ "${baseimage}" = "debian_rpi64" ]||[ "${baseimage}" = "armbian" ]||\ - [ "${baseimage}" = "ubuntu" ]; then - homeFile=/home/pi/.bashrc - autostartDone=$(grep -c "automatic start the LCD" $homeFile) - if [ ${autostartDone} -eq 0 ]; then - # bash autostart for pi - # run as exec to dont allow easy physical access by keyboard - # see https://github.com/rootzoll/raspiblitz/issues/54 - sudo bash -c 'echo "# automatic start the LCD info loop" >> /home/pi/.bashrc' - sudo bash -c 'echo "SCRIPT=/home/admin/00infoLCD.sh" >> /home/pi/.bashrc' - sudo bash -c 'echo "# replace shell with script => logout when exiting script" >> /home/pi/.bashrc' - sudo bash -c 'echo "exec \$SCRIPT" >> /home/pi/.bashrc' - echo "autostart LCD added to $homeFile" - else - echo "autostart LCD already in $homeFile" - fi - elif [ "${baseimage}" = "dietpi" ]; then - homeFile=/home/dietpi/.bashrc - autostartDone=$(grep -c "automatic start the LCD" $homeFile) - if [ ${autostartDone} -eq 0 ]; then - # bash autostart for dietpi - sudo bash -c 'echo "# automatic start the LCD info loop" >> /home/dietpi/.bashrc' - sudo bash -c 'echo "SCRIPT=/home/admin/00infoLCD.sh" >> /home/dietpi/.bashrc' - sudo bash -c 'echo "# replace shell with script => logout when exiting script" >> /home/dietpi/.bashrc' - sudo bash -c 'echo "exec \$SCRIPT" >> /home/dietpi/.bashrc' - echo "autostart LCD added to $homeFile" - else - echo "autostart LCD already in $homeFile" - fi +# prepare auto-start of 00infoLCD.sh script on pi user login (just kicks in if auto-login of pi is activated in HDMI or LCD mode) +if [ "${baseimage}" = "raspbian" ]||[ "${baseimage}" = "raspios_arm64" ]||\ + [ "${baseimage}" = "debian_rpi64" ]||[ "${baseimage}" = "armbian" ]||\ + [ "${baseimage}" = "ubuntu" ]; then + homeFile=/home/pi/.bashrc + autostartDone=$(grep -c "automatic start the LCD" $homeFile) + if [ ${autostartDone} -eq 0 ]; then + # bash autostart for pi + # run as exec to dont allow easy physical access by keyboard + # see https://github.com/rootzoll/raspiblitz/issues/54 + sudo bash -c 'echo "# automatic start the LCD info loop" >> /home/pi/.bashrc' + sudo bash -c 'echo "SCRIPT=/home/admin/00infoLCD.sh" >> /home/pi/.bashrc' + sudo bash -c 'echo "# replace shell with script => logout when exiting script" >> /home/pi/.bashrc' + sudo bash -c 'echo "exec \$SCRIPT" >> /home/pi/.bashrc' + echo "autostart LCD added to $homeFile" else - echo "FAIL: Script Autostart not available for baseimage(${baseimage}) - please choose 'headless' on DISPLAY-CLASS" - exit 1 + echo "autostart LCD already in $homeFile" + fi +elif [ "${baseimage}" = "dietpi" ]; then + homeFile=/home/dietpi/.bashrc + autostartDone=$(grep -c "automatic start the LCD" $homeFile) + if [ ${autostartDone} -eq 0 ]; then + # bash autostart for dietpi + sudo bash -c 'echo "# automatic start the LCD info loop" >> /home/dietpi/.bashrc' + sudo bash -c 'echo "SCRIPT=/home/admin/00infoLCD.sh" >> /home/dietpi/.bashrc' + sudo bash -c 'echo "# replace shell with script => logout when exiting script" >> /home/dietpi/.bashrc' + sudo bash -c 'echo "exec \$SCRIPT" >> /home/dietpi/.bashrc' + echo "autostart LCD added to $homeFile" + else + echo "autostart LCD already in $homeFile" fi - else - echo "# running headless ... no auto-login of pi user for display needed" + echo "WARN: Script Autostart not available for baseimage(${baseimage}) - may just run on 'headless'" fi # change log rotates @@ -570,7 +554,7 @@ echo '%sudo ALL=(ALL) NOPASSWD:ALL' | sudo EDITOR='tee -a' visudo # WRITE BASIC raspiblitz.info to sdcard echo "baseimage=${baseimage}" > /home/admin/raspiblitz.info echo "cpu=${cpu}" >> /home/admin/raspiblitz.info -echo "displayClass=${displayClass}" >> /home/admin/raspiblitz.info +echo "displayClass=headless" >> /home/admin/raspiblitz.info sudo mv ./raspiblitz.info /home/admin/raspiblitz.info sudo chmod 755 /home/admin/raspiblitz.info @@ -1092,8 +1076,8 @@ echo "2. run --> ./XXprepareRelease.sh" echo "" # (do last - because might trigger reboot) -if [ "${displayClass}" != "hdmi" ]; then +if [ "${displayClass}" != "headless" ] || [ "${baseimage}" = "raspbian" ] || [ "${baseimage}" = "raspios_arm64" ]; then echo "*** ADDITIONAL DISPLAY OPTIONS ***" echo "- calling: blitz.display.sh set-display ${displayClass}" - sudo blitz.display.sh set-display ${displayClass} + sudo /home/admin/config.scripts/blitz.display.sh set-display ${displayClass} fi \ No newline at end of file diff --git a/home.admin/_version.info b/home.admin/_version.info index 58a69809e..50cc62d1c 100644 --- a/home.admin/_version.info +++ b/home.admin/_version.info @@ -1,2 +1,2 @@ # RaspiBlitz Version - always [major].[main].[sub] (sub can be a string like '2rc1') -codeVersion="1.7.0RC1" +codeVersion="1.7.0RC2" diff --git a/home.admin/config.scripts/blitz.display.sh b/home.admin/config.scripts/blitz.display.sh index edb4f40ab..f5b41eb8d 100755 --- a/home.admin/config.scripts/blitz.display.sh +++ b/home.admin/config.scripts/blitz.display.sh @@ -445,6 +445,14 @@ function install_headless() { else echo "# auto-login of pi user is already deactivated" fi + elif [ "${baseimage}" = "dietpi" ]; then + # TODO make switch between headless & HDMI possible + echo "# TODO: reverse HDMI mode if set before" + echo "# headless is already the default mode" + elif [ "${baseimage}" = "ubuntu" ] || [ "${baseimage}" = "armbian" ]; then + # TODO make switch between headless & HDMI possible + echo "# TODO: reverse HDMI mode if set before" + echo "# headless is already the default mode" else echo "err='baseimage not supported'" exit 1 @@ -453,18 +461,33 @@ function install_headless() { function uninstall_headless() { if [ "${baseimage}" = "raspbian" ]||[ "${baseimage}" = "raspios_arm64" ]|| [ "${baseimage}" = "debian_rpi64" ]; then + # activate auto-login + sudo raspi-config nonint do_boot_behaviour B2 modificationExists=$(sudo cat /etc/systemd/system/getty@tty1.service.d/autologin.conf | grep -c "autologin pi") if [ "${modificationExists}" == "0" ]; then echo "# activating auto-login of pi user again" - # set Raspi to boot up automatically with user pi (for the LCD) + # set Raspi to boot up automatically with user pi # https://www.raspberrypi.org/forums/viewtopic.php?t=21632 - sudo raspi-config nonint do_boot_behaviour B2 sudo bash -c "echo '[Service]' >> /etc/systemd/system/getty@tty1.service.d/autologin.conf" sudo bash -c "echo 'ExecStart=' >> /etc/systemd/system/getty@tty1.service.d/autologin.conf" sudo bash -c "echo 'ExecStart=-/sbin/agetty --autologin pi --noclear %I 38400 linux' >> /etc/systemd/system/getty@tty1.service.d/autologin.conf" else echo "# auto-login of pi user already active" fi + elif [ "${baseimage}" = "dietpi" ]; then + # set DietPi to boot up automatically with user pi (for the LCD) + # requires AUTO_SETUP_AUTOSTART_TARGET_INDEX=7 in the dietpi.txt + # /DietPi/dietpi/dietpi-autostart overwrites /etc/systemd/system/getty@tty1.service.d/dietpi-autologin.conf on reboot + sudo sed -i 's/agetty --autologin root %I $TERM/agetty --autologin pi --noclear %I 38400 linux/' /DietPi/dietpi/dietpi-autostart + elif [ "${baseimage}" = "ubuntu" ] || [ "${baseimage}" = "armbian" ]; then + modificationExists=$(sudo cat /lib/systemd/system/getty@.service | grep -c "autologin pi") + if [ "${modificationExists}" == "0" ]; then + sudo bash -c "echo '[Service]' >> /lib/systemd/system/getty@.service" + sudo bash -c "echo 'ExecStart=' >> /lib/systemd/system/getty@.service" + sudo bash -c "echo 'ExecStart=-/sbin/agetty --autologin pi --noclear %I 38400 linux' >> /lib/systemd/system/getty@.service" + else + echo "# auto-login of pi user already active" + fi else echo "err='baseimage not supported'" exit 1 @@ -500,23 +523,15 @@ if [ "${command}" == "set-display" ]; then exit 1 fi + # check if display class parameter is given if [ "${paramDisplayClass}" == "" ]; then echo "err='missing parameter'" exit 1 - elif [ "${paramDisplayClass}" == "${displayClass}" ]; then - - # normally dont make any changes here - but it can be the case that this called by recover/update process - # where raspiblitz.info (base image) raspiblitz.conf (user config) have different values - check fo this case: - confAndInfoValueIsSame=$(sudo cat /home/admin/raspiblitz.info | grep -c "displayClass=${paramDisplayClass}}") - if [ "${confAndInfoValueIsSame}" == "0" ]; then - echo "# raspiblitz.info is different from raspiblitz.conf --> enforcing ${displayClass} for both" - source /home/admin/raspiblitz.info - # continue with the raspiblitz.info value of displayClass as actual state (not the overwritten one from raspiblitz.conf) - else - echo "# raspiblitz.info (AND raspiblitz.conf) already running ${displayClass} - no need for change" - exit 1 - fi fi + + echo "# old(${displayClass})" + echo "# new(${paramDisplayClass})" + if [ "${paramDisplayClass}" == "hdmi" ] || [ "${paramDisplayClass}" == "lcd" ] || [ "${paramDisplayClass}" == "headless" ]; then # uninstall old state diff --git a/home.admin/config.scripts/bonus.btc-rpc-explorer.sh b/home.admin/config.scripts/bonus.btc-rpc-explorer.sh index 358422621..41f38923f 100755 --- a/home.admin/config.scripts/bonus.btc-rpc-explorer.sh +++ b/home.admin/config.scripts/bonus.btc-rpc-explorer.sh @@ -117,7 +117,7 @@ if [ "$1" = "1" ] || [ "$1" = "on" ]; then cd /home/btcrpcexplorer sudo -u btcrpcexplorer git clone https://github.com/janoside/btc-rpc-explorer.git cd btc-rpc-explorer - sudo -u btcrpcexplorer git reset --hard v2.2.0 + sudo -u btcrpcexplorer git reset --hard v3.0.0 sudo -u btcrpcexplorer npm install if ! [ $? -eq 0 ]; then echo "FAIL - npm install did not run correctly, aborting"