Security

We make sure that your Microbolt is secured against unauthorized remote access.

The Microbolt will be visible from the internet and therefore needs to be secured against online attacks using various methods.

Login with SSH keys

One of the best options to secure the sensitive SSH login is to disable passwords altogether and require an SSH key certificate. Only someone with physical possession of the private certificate key can log in.

Preparations on host system

Create a new public/private key pair

⚠️

Skip if you already have one

ssh-keygen -t rsa -b 4096

Follow instructions, optionally enter a key passphrase to protect your key, you can use password [A]

The public key now needs to be copied to the PC

cat ./.ssh/id_rsa.pub |
    ssh satoshi@nakamoto01 "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
 

Preparations on server system

It’s also recommended to change default ssh port 22, to something else like 2222

Disable password and root logins

sed 's/DROPBEAR_OPTS=""/DROPBEAR_OPTS="-w -s -p 2222"/' /etc/conf.d/dropbear > _
$SU mv -f _ /etc/conf.d/dropbear
 

Restart service to apply changes

if $SU rc-service dropbear status | grep -q "started"; then
    $SU rc-service dropbear restart
elif $SU rc-service sshd status | grep -q "started"; then
    $SU rc-service sshd restart
fi

Disable root account

$SU passwd -l root

Firewall

A firewall controls what kind of outside traffic your machine accepts and which applications can send data out. By default, many network ports are open and listening for incoming connections. Closing unnecessary ports can mitigate many potential system vulnerabilities.

For now, only SSH should be reachable from the outside. Bitcoin Core and LND are using Tor and don’t need incoming ports.

Install awall

$SU apk add awall iptables ip6tables

Load the necessary kernel modules and load them at boot

$SU modprobe -av ip_tables ip6_tables
printf "%s\n" \
    "ip_tables" \
    "ip6_tables" \
    | $SU tee /etc/modules-load.d/awall.conf

Configure and enable the firewall rules

Replace eth0 with your network interface

$SU $EDITOR /etc/awall/optional/base-config.json
/etc/awall/optional/base-config.json
{
  "description": "Base zones and policies",
 
  "zone": {
    "internet": { "iface": "eth0" }
  },
 
  "policy": [
     { "in": "internet", "action": "drop" },
     { "out": "internet", "action": "accept" }
  ]
}
💡

If you changed the SSH port, replace "service": "ssh" with your new port "service": { "proto": "tcp", "port": 2222 }, or whatever you chose

$SU $EDITOR /etc/awall/optional/ssh.json
/etc/awall/optional/ssh.json
{
  "description": "Allow incoming SSH access (TCP/22)",
 
  "filter": [
    {
      "in": "internet",
      "out": "_fw",
      "service": "ssh",
      "action": "accept",
      "conn-limit": { "count": 3, "interval": 60 }
    }
  ]
}

Enable the firewall on boot

$SU rc-update add iptables
$SU rc-update add ip6tables

Start the firewall

$SU awall list
output
base-config  disabled  Base zones and policies
ssh          disabled  Allow incoming SSH access (TCP/22)
$SU awall enable base-config ssh
$SU awall activate

Check if the firewall is properly configured and active

$SU iptables -S | grep 22
output
-A INPUT -i eth0 -p tcp -m tcp --dport 22 -j limit-ssh-0

If you find yourself locked out by mistake, you can connect a keyboard and screen to your PC to log in locally and fix these settings (especially for the SSH port).

Reverse proxy

Several components of this guide will expose a communication port, for example, the Block Explorer, or the ThunderHub web interface for your Lightning node. Even if you use these services only within your own home network, communication should always be encrypted. Otherwise, any device in the same network can listen to the exchanged data, including passwords.

We use Caddy to encrypt the communication with SSL/TLS (Transport Layer Security). This setup is called a “reverse proxy”: Caddy provides secure communication to the outside and routes the traffic back to the internal service without encryption. Alternatively you can also install nginx to perform the same functions.

⚠️

We do not recommend using the Caddy available in Alpine because it will conflict when Caddy updates itself to the latest version and adds modules. Also, the provided init script is not as complete as the one proposed in this guide.

Create the caddy user/group

$SU addgroup -S caddy
$SU adduser \
    -S \
    -D \
    -H \
    -h /dev/null \
    -s /sbin/nologin \
    -G caddy \
    -g caddy \
    caddy
  • Add the user satoshi to the group caddy
$SU adduser satoshi caddy

Download latest release

cd /tmp
LATEST=$(wget -qO- https://api.github.com/repos/caddyserver/caddy/releases/latest | grep "tag_name" | cut -d '"' -f 4 | sed 's/^v//')
wget https://github.com/caddyserver/caddy/releases/download/v$LATEST/caddy_${LATEST}_linux_amd64.tar.gz \
    https://github.com/caddyserver/caddy/releases/download/v$LATEST/caddy_${LATEST}_checksums.txt
  • Checksum check
grep caddy_${LATEST}_linux_amd64.tar.gz caddy_${LATEST}_checksums.txt | sha512sum -c
output
caddy_${LATEST}_linux_amd64.tar.gz: OK

Extract and install binary

$SU tar xzf caddy_${LATEST}_linux_amd64.tar.gz caddy -C /usr/bin/
  • Add necessary modules
$SU caddy add-package github.com/mholt/caddy-l4

Configuration

  • First of all, create directories for configuration files
$SU mkdir -p \
    /etc/caddy/sites \
    /etc/caddy/streams
$SU $EDITOR /etc/caddy/Caddyfile
/etc/caddy/Caddyfile
{
        local_certs
        ocsp_stapling off
        log {
                format console
        }
        layer4 {
                import /etc/caddy/streams/*.caddy
        }
}
(tls) {
        tls internal {
                on_demand
        }
}
https:// {
        import tls
}
import /etc/caddy/sites/*.caddy
Use your own self-signed certificates
$SU openssl req \
    -x509 \
    -nodes \
    -newkey rsa:4096 \
    -keyout /path/to/your-key.pem \
    -out /path/to/your-cert.pem \
    -subj "/CN=localhost" \
    -days 3650
 
$SU chown \
    caddy:caddy \
    /path/to/your-key.pem \
    /path/to/your-cert.pem
/etc/caddy/Caddyfile
 [...]
 (tls) {
-        tls internal {
+        tls /path/to/your-cert.pem /path/to/your-key.pem {
                 on_demand
         }
 }
 [...]

Create the Caddy service

$SU $EDITOR /etc/init.d/caddy
/etc/init.d/caddy
#!/sbin/openrc-run
 
: ${CADDY_CONFIGFILE:=/etc/caddy/Caddyfile}
: ${CADDY_DATADIR:=/var/lib/caddy}
: ${CADDY_LOGDIR:=/var/log/caddy}
: ${CADDY_USER:=caddy}
: ${CADDY_GROUP:=caddy}
: ${CADDY_BIN:=/usr/bin/caddy}
: ${CADDY_OPTS=${CADDY_OPTS}}
: ${CADDY_SIGTERM_TIMEOUT:=600}
 
CADDY_PIDDIR="/run/caddy"
 
name="Caddy web server"
description="Fast, multi-platform web server with automatic HTTPS"
 
required_files="${CADDY_CONFIGFILE}"
pidfile="${CADDY_PIDDIR}/${SVCNAME}.pid"
retry="${CADDY_SIGTERM_TIMEOUT}"
capabilities="^cap_net_bind_service"
 
command="${CADDY_BIN}"
command_args="run
              --config ${CADDY_CONFIGFILE}
              ${CADDY_OPTS}"
command_user="${CADDY_USER}:${CADDY_GROUP}"
command_background="true"
 
start_stop_daemon_args="--env XDG_CONFIG_HOME=${CADDY_DATADIR%/caddy}
                        --env XDG_DATA_HOME=${CADDY_DATADIR%/caddy}
                        --stdout ${CADDY_LOGDIR}/debug.log
                        --stderr ${CADDY_LOGDIR}/debug.log"
 
extra_commands="checkconfig"
description_checkconfig="Check configuration"
 
extra_started_commands="reload"
description_reload="Reload configuration without downtime"
 
depend() {
  need net localmount
  after firewall
}
 
start_pre() {
    checkpath --file      --mode 0660 --owner "${command_user}" "${CADDY_CONFIGFILE}"
    checkpath --directory --mode 0750 --owner "${command_user}" "${CADDY_DATADIR}"
    checkpath --directory --mode 0755 --owner "${command_user}" "${CADDY_LOGDIR}"
    checkpath --directory --mode 0755 --owner "${command_user}" "${CADDY_PIDDIR}"
    checkconfig
}
 
checkconfig() {
  if [ ! -f "${CADDY_CONFIGFILE}" ] ; then
    ewarn "${CADDY_CONFIGFILE} does not exist." && return 1
  fi
  $command validate ${command_args#run} > /dev/null 2>&1
  eend $?
}
 
reload() {
  if ! service_started "${SVCNAME}" ; then
      eerror "${SVCNAME} isn't running" && return 1
  fi
  checkconfig || { eerror "Invalid configuration file !" && return 1; }
 
  ebegin "Reloading ${SVCNAME}"
  $command reload --force ${command_args#run} > /dev/null 2>&1
  eend $?
}
  • Enable execution permission
$SU chmod +x /etc/init.d/caddy

Enable and start the Caddy service

$SU rc-service caddy start
$SU rc-update add caddy
  • You can monitor the Caddy logs by entering this command. Exit with Ctrl + C
tail -f /var/log/caddy/debug.log