#!/bin/bash # # Bitcoin Node for Solo Miners Appliance Installer # An Open Source Linux Appliance from Robbie Ferguson # (c) 2025 Robbie Ferguson set -e BTC_VER="30.0" APP_ROOT="/opt/btc-solo" WWW_ROOT="/var/www/btc-solo" BITCOIN_CONF="/etc/bitcoin/bitcoin.conf" CERT_DIR="/etc/ssl/localcerts" CKPOOL_USER="ckpool" CKPOOL_PORT="3333" BITCOIN_DATA="/var/lib/bitcoind" BTC_RPC_USER="user" BTC_RPC_PASS="pass" PRUNE_SIZE="550" # --------------------------------------------------------------------------- # PURGE # --------------------------------------------------------------------------- if [[ "$1" == "--purge" ]]; then systemctl stop ckpool 2>/dev/null || true systemctl stop bitcoind 2>/dev/null || true rm -f /var/lib/btc-solo/.setup-complete rm -f /etc/systemd/system/ckpool.service rm -f /etc/systemd/system/bitcoind.service rm -f /etc/nginx/sites-enabled/btc-solo rm -f /etc/nginx/sites-available/btc-solo rm -f /etc/sudoers.d/btc-solo rm -rf "$APP_ROOT" "$WWW_ROOT" "$CERT_DIR" "$BITCOIN_DATA" rm -f /usr/local/sbin/btc-apply-admin.sh /usr/local/sbin/btc-set-prune.sh /usr/local/sbin/btc-make-cert.sh # Remove bitcoin binaries we installed directly rm -f /usr/local/bin/bitcoind /usr/local/bin/bitcoin-cli /usr/local/bin/bitcoin-tx /usr/local/bin/bitcoin-util 2>/dev/null || true systemctl daemon-reload systemctl restart nginx 2>/dev/null || true echo "Bitcoin Solo Miner Appliance purged." exit 0 fi if [[ $EUID -ne 0 ]]; then echo "Run as root." exit 1 fi echo "[1/8] Updating apt…" apt-get update echo "[2/8] Installing base packages…" apt-get install -y \ curl ca-certificates gnupg \ nginx php-fpm php-cli \ git build-essential autoconf automake libtool pkg-config \ libjansson-dev libevent-dev libcurl4-openssl-dev libssl-dev zlib1g-dev \ openssl jq bc # --------------------------------------------------------------------------- # [3/8] Install Bitcoin Core from official binaries # --------------------------------------------------------------------------- echo "[3/8] Installing official Bitcoin Core binaries…" # ===== Detect CPU arch and install correct Bitcoin Core binary ===== detect_arch() { # Prefer dpkg (Debian/Ubuntu), fall back to uname local deb_arch deb_arch=$(dpkg --print-architecture 2>/dev/null || true) case "$deb_arch" in amd64) echo "x86_64-linux-gnu"; return ;; arm64) echo "aarch64-linux-gnu"; return ;; armhf) echo "arm-linux-gnueabihf"; return ;; esac # Fallback by kernel arch local u u=$(uname -m) case "$u" in x86_64) echo "x86_64-linux-gnu" ;; aarch64) echo "aarch64-linux-gnu" ;; armv7l|armv6l) echo "arm-linux-gnueabihf" ;; *) echo "unsupported" ;; esac } BTC_PLAT="$(detect_arch)" if [ "$BTC_PLAT" = "unsupported" ]; then echo "ERROR: Unsupported CPU architecture ($(uname -m))." echo "Tip: For exotic arches, build from source using depends/ then install bitcoind/bitcoin-cli." exit 1 fi BASE_URL="https://bitcoincore.org/bin/bitcoin-core-$BTC_VER" TARBALL="bitcoin-$BTC_VER-$BTC_PLAT.tar.gz" TMPD="$(mktemp -d)" echo "[Bitcoin Core] Detected platform: $BTC_PLAT" echo "[Bitcoin Core] Downloading $TARBALL …" curl -fsSL "$BASE_URL/$TARBALL" -o "$TMPD/$TARBALL" # Get SHA256SUMS (and try to verify signature if gpg is present) curl -fsSL "$BASE_URL/SHA256SUMS" -o "$TMPD/SHA256SUMS" if command -v gpg >/dev/null 2>&1; then curl -fsSL "$BASE_URL/SHA256SUMS.asc" -o "$TMPD/SHA256SUMS.asc" || true # If you’ve already imported the Bitcoin Core release keys, this will verify. # If not, we still proceed after SHA256 check below. gpg --verify "$TMPD/SHA256SUMS.asc" "$TMPD/SHA256SUMS" || echo "[WARN] Could not verify SHA256SUMS signature (no keys?). Continuing with SHA256 check." fi echo "[Bitcoin Core] Verifying tarball checksum …" ( cd "$TMPD" && grep " $TARBALL" SHA256SUMS | sha256sum -c - ) echo "[Bitcoin Core] Installing to /usr/local/bin …" tar -xzf "$TMPD/$TARBALL" -C "$TMPD" install -m 0755 "$TMPD/bitcoin-$BTC_VER/bin/bitcoind" /usr/local/bin/ install -m 0755 "$TMPD/bitcoin-$BTC_VER/bin/bitcoin-cli" /usr/local/bin/ install -m 0755 "$TMPD/bitcoin-$BTC_VER/bin/bitcoin-tx" /usr/local/bin/ install -m 0755 "$TMPD/bitcoin-$BTC_VER/bin/bitcoin-wallet" /usr/local/bin/ rm -rf "$TMPD" echo "[Bitcoin Core] Installed bitcoind/bitcoin-cli for $BTC_PLAT" # systemd service for bitcoind cat > /etc/systemd/system/bitcoind.service < "$BITCOIN_CONF" </dev/null 2>&1 || useradd -r -s /bin/false "$CKPOOL_USER" usermod -aG $CKPOOL_USER www-data # try to restart the running PHP-FPM service so www-data picks up new group php_fpm_service="" # 1) ask systemd what php-fpm services exist php_fpm_service=$(systemctl list-units --type=service --all \ | awk '/php.*fpm\.service/ {print $1; exit}') if [ -n "$php_fpm_service" ]; then systemctl restart "$php_fpm_service" fi mkdir -p "$APP_ROOT/conf" "$APP_ROOT/logs" cat > "$APP_ROOT/conf/ckpool.conf" < /etc/systemd/system/ckpool.service < /usr/local/sbin/btc-apply-admin.sh <<'EOF' #!/bin/bash CONF="/etc/bitcoin/bitcoin.conf" CKPOOL_CONF="/opt/btc-solo/conf/ckpool.conf" ADMINUSER="$1" ADMINPASS="$2" if [[ -z "$ADMINUSER" || -z "$ADMINPASS" ]]; then echo "Usage: $0 " exit 1 fi # Update bitcoin.conf sed -i '/^rpcuser=/d' "$CONF" sed -i '/^rpcpassword=/d' "$CONF" echo "rpcuser=${ADMINUSER}" >> "$CONF" echo "rpcpassword=${ADMINPASS}" >> "$CONF" # Update ckpool config so it can still talk to bitcoind if [[ -f "$CKPOOL_CONF" ]]; then sed -i "s/\"user\"[[:space:]]*:[[:space:]]*\"[^\"]*\"/\"user\" : \"${ADMINUSER}\"/" "$CKPOOL_CONF" sed -i "s/\"pass\"[[:space:]]*:[[:space:]]*\"[^\"]*\"/\"pass\" : \"${ADMINPASS}\"/" "$CKPOOL_CONF" fi systemctl restart bitcoind systemctl restart ckpool EOF chmod 700 /usr/local/sbin/btc-apply-admin.sh # set prune size cat > /usr/local/sbin/btc-set-prune.sh <<'EOF' #!/bin/bash CONF="/etc/bitcoin/bitcoin.conf" SIZE="$1" if [[ -z "$SIZE" ]]; then echo "Usage: $0 " exit 1 fi sed -i '/^prune=/d' "$CONF" if [[ "$SIZE" != "full" ]]; then echo "prune=${SIZE}" >> "$CONF" fi systemctl restart bitcoind EOF chmod 700 /usr/local/sbin/btc-set-prune.sh # setup donation system cat > /usr/local/sbin/btc-set-donation.sh <<'EOF' #!/bin/bash CONF="/opt/btc-solo/conf/ckpool.conf" ADDR="$1" RATE="$2" if [[ -z "$ADDR" || -z "$RATE" ]]; then echo "Usage: $0 " exit 1 fi # ensure conf exists if [[ ! -f "$CONF" ]]; then echo "ckpool.conf not found at $CONF" exit 1 fi # remove old lines sed -i '/"donaddress"/d' "$CONF" sed -i '/"donrate"/d' "$CONF" # add new ones just before the final } # (very simple appender; good enough for our generated file) sed -i '$i \ ,"donaddress" : "'"$ADDR"'",\n "donrate" : '"$RATE"'' "$CONF" systemctl restart ckpool EOF chmod 700 /usr/local/sbin/btc-set-donation.sh # (re)create self-signed cert cat > /usr/local/sbin/btc-make-cert.sh <<'EOF' #!/bin/bash CERTDIR="/etc/ssl/localcerts" mkdir -p "$CERTDIR" openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \ -keyout ${CERTDIR}/btc-solo.key \ -out ${CERTDIR}/btc-solo.crt \ -subj "/C=CA/ST=Ontario/L=Barrie/O=BTC-Solo/OU=IT/CN=$(hostname -f)" chmod 600 ${CERTDIR}/btc-solo.key systemctl restart nginx EOF chmod 700 /usr/local/sbin/btc-make-cert.sh # ensure sudoers.d exists mkdir -p /etc/sudoers.d chmod 750 /etc/sudoers.d # sudoers cat > /etc/sudoers.d/btc-solo <<'EOF' www-data ALL=(root) NOPASSWD: /usr/local/sbin/btc-apply-admin.sh www-data ALL=(root) NOPASSWD: /usr/local/sbin/btc-set-prune.sh www-data ALL=(root) NOPASSWD: /usr/local/sbin/btc-make-cert.sh www-data ALL=(root) NOPASSWD: /usr/local/sbin/btc-set-donation.sh EOF chmod 440 /etc/sudoers.d/btc-solo # --------------------------------------------------------------------------- echo "[6/8] Web UI (dashboard + activate)" # --------------------------------------------------------------------------- # web-owned state dir mkdir -p /var/lib/btc-solo chown www-data:www-data /var/lib/btc-solo # web dashboard mkdir -p "$WWW_ROOT" mkdir -p "$WWW_ROOT/activate" # Main dashboard cat > "$WWW_ROOT/index.php" <<'EOF' Bitcoin Node for Solo Miners

Bitcoin Node for Solo Miners

A Linux Appliance by Robbie Ferguson

Status

Loading status…

Workers

No workers detected yet. This is normal while Bitcoin Core is syncing or if no ASICs are pointed at this server.

EOF # Settings page cat > "$WWW_ROOT/settings.php" <<'EOF' '550 MB (default, small)', (2*1024) => '2 GB', (4*1024) => '4 GB', (8*1024) => '8 GB', (16*1024) => '16 GB', (32*1024) => '32 GB', (64*1024) => '64 GB', (100*1024) => '100 GB', (200*1024) => '200 GB', (300*1024) => '300 GB', (400*1024) => '400 GB', 'full' => 'Full (no pruning)', ]; $current = '550'; $conf = @file_get_contents('/etc/bitcoin/bitcoin.conf'); if ($conf && preg_match('/^prune=(\d+)/m', $conf, $m)) { $current = $m[1]; } elseif ($conf && !preg_match('/^prune=/m', $conf)) { $current = 'full'; } if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['prune'])) { $sel = $_POST['prune']; if (isset($opts[$sel])) { shell_exec('sudo /usr/local/sbin/btc-set-prune.sh ' . escapeshellarg($sel)); $current = $sel; sleep(1); } } $host = $_SERVER['HTTP_HOST'] ?? $_SERVER['SERVER_ADDR'] ?? gethostname(); $host = preg_replace('/:\d+$/', '', $host); // strip port if present $stratum = 'stratum+tcp://' . $host . ':3333'; ?> Bitcoin Node for Solo Miners [Settings]

Bitcoin Node for Solo Miners

A Linux Appliance by Robbie Ferguson

Stratum Endpoint

Username: BTC address for payout

Password: anything

Blockchain Prune Size

Note: Prune size only limits stored block data. You should also expect the node to use up to 500 MB for chainstate and metadata. Actual disk usage will be higher than the value selected here.

Changing this will restart bitcoind.

Donate to Bald Nerd

If you happen to win a BTC block, you can donate a small percentage to Robbie Ferguson (developer of this appliance, host of Category5 Technology TV) with big thanks. You can set to 0 if you prefer to keep the full block to yourself.

EOF # AJAX status info cat > "$WWW_ROOT/status.php" <<'EOF' 'not activated']); exit; } header('Content-Type: application/json'); // ---- 1) bitcoin core info ---- $btcInfo = null; $out = shell_exec('/usr/local/bin/bitcoin-cli -conf=/etc/bitcoin/bitcoin.conf getblockchaininfo 2>/dev/null'); if ($out) { $btcInfo = json_decode($out, true); } // ---- 2) service health ---- function svc($name) { $res = trim(shell_exec('systemctl is-active ' . escapeshellarg($name) . ' 2>/dev/null')); return $res === 'active' ? 'active' : $res; } $services = [ 'bitcoind' => svc('bitcoind'), 'ckpool' => svc('ckpool'), ]; // ---- 3) system info (non-sensitive) ---- // uptime $uptime_seconds = null; if (is_readable('/proc/uptime')) { $up = trim(file_get_contents('/proc/uptime')); $parts = explode(' ', $up); $uptime_seconds = (int)floatval($parts[0]); } // load average $load = function_exists('sys_getloadavg') ? sys_getloadavg() : null; // memory $mem_total = null; $mem_avail = null; if (is_readable('/proc/meminfo')) { $meminfo = file('/proc/meminfo', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); foreach ($meminfo as $line) { if (strpos($line, 'MemTotal:') === 0) { $mem_total = (int)filter_var($line, FILTER_SANITIZE_NUMBER_INT) * 1024; } elseif (strpos($line, 'MemAvailable:') === 0) { $mem_avail = (int)filter_var($line, FILTER_SANITIZE_NUMBER_INT) * 1024; } } } // disk (root) $disk_root_total = @disk_total_space('/'); $disk_root_free = @disk_free_space('/'); // disk (bitcoind datadir) $btcDir = '/var/lib/bitcoind'; $disk_btc_total = @disk_total_space($btcDir); $disk_btc_free = @disk_free_space($btcDir); // bitcoind dir size $btc_dir_size = null; $du = shell_exec('du -sb ' . escapeshellarg($btcDir) . ' 2>/dev/null'); if ($du) { $parts = preg_split('/\s+/', trim($du)); if (isset($parts[0]) && ctype_digit($parts[0])) { $btc_dir_size = (int)$parts[0]; } } // ---- 4) output ---- echo json_encode([ 'initialblockdownload' => $btcInfo['initialblockdownload'] ?? null, 'blocks' => $btcInfo['blocks'] ?? null, 'headers' => $btcInfo['headers'] ?? null, 'verificationprogress' => $btcInfo['verificationprogress'] ?? null, 'pruned' => $btcInfo['pruned'] ?? null, 'services' => $services, 'system' => [ 'uptime_seconds' => $uptime_seconds, 'loadavg' => $load, 'mem_total_bytes' => $mem_total, 'mem_available_bytes' => $mem_avail, 'disk_root' => [ 'total_bytes' => $disk_root_total, 'free_bytes' => $disk_root_free, ], 'disk_bitcoind' => [ 'total_bytes' => $disk_btc_total, 'free_bytes' => $disk_btc_free, 'used_bytes' => $btc_dir_size, ], ], ], JSON_UNESCAPED_SLASHES); EOF # activation page cat > "$WWW_ROOT/activate/index.php" <<'EOF' Create New Admin User

Create New Admin User

This sets the Bitcoin node’s administrative (RPC) credentials used to control the server itself.

Keep these private — they grant full access to your node.

These credentials are not used by miners to connect; miners only need your Bitcoin address and can use any password.

EOF # --------------------------------------------------------------------------- echo "Console Dashboard" # --------------------------------------------------------------------------- cat > /usr/local/sbin/btc-console-dashboard <<'EOF' #!/bin/bash # Text/ANSI dashboard for Bitcoin Solo Miner (non-blocking, with system stats) BITCOIN_CLI="/usr/local/bin/bitcoin-cli" BITCOIN_CONF="/etc/bitcoin/bitcoin.conf" BTC_DIR="/var/lib/bitcoind" # colors RED="\033[31m" GRN="\033[32m" YEL="\033[33m" CYN="\033[36m" BOLD="\033[1m" RST="\033[0m" CONSEC_FAILS=0 MAX_FAILS=3 LAST_INFO="" get_ip() { ip -4 addr show scope global 2>/dev/null | awk '/inet / {print $2}' | cut -d/ -f1 | head -n1 } make_bar() { local pct="$1" local width="$2" [ -z "$pct" ] && pct=0 pct=$(printf "%.1f" "$pct") # clamp if (( $(echo "$pct < 0" | bc -l 2>/dev/null || echo 0) )); then pct=0; fi if (( $(echo "$pct > 100" | bc -l 2>/dev/null || echo 0) )); then pct=100; fi local filled=$(printf "%.0f" "$(echo "$pct / 100 * $width" | bc -l)") local empty=$((width - filled)) printf "[" for ((i=0; i/dev/null || true tput cup 0 0; echo -e "${BOLD}Bitcoin Node for Solo Miners${RST}" tput cup 1 0; echo -e "A Linux Appliance by Robbie Ferguson" tput cup 2 0; printf '%*s' "$(tput cols)" '' | tr ' ' '-' } draw_loading() { tput cup 3 0; echo -e "${YEL}Loading node status…${RST}\033[K" } draw_dashboard() { # args: # 1 now 2 ip 3 web 4 status 5 bar 6 progress 7 services 8 cpu 9 mem 10 disk 11 workers local now="$1" local ip="$2" local web="$3" local status="$4" local bar="$5" local progress="$6" local services="$7" local cpu="$8" local mem="$9" local disk="${10}" local workers="${11}" tput cup 3 0; echo -e "Time: ${CYN}${now}${RST}\033[K" tput cup 4 0; echo -e "IP: ${CYN}${ip}${RST}\033[K" tput cup 5 0; echo -e "Web: ${CYN}${web}${RST}\033[K" tput cup 6 0; printf '%*s' "$(tput cols)" '' | tr ' ' '-' tput cup 7 0; echo -e "${status}\033[K" tput cup 8 0; echo -e "${bar}\033[K" tput cup 9 0; echo -e "${progress}\033[K" tput cup 10 0; echo -e "${services}\033[K" tput cup 11 0; printf '%*s' "$(tput cols)" '' | tr ' ' '-' tput cup 12 0; echo -e "CPU load: ${cpu}\033[K" tput cup 13 0; echo -e "Memory: ${mem}\033[K" tput cup 14 0; echo -e "Disk (${BTC_DIR}): ${disk}\033[K" tput cup 16 0; echo -e "Workers:\033[K" tput cup 17 2; echo -e "${workers}\033[K" tput cup 19 0; echo -e "(Appliance console view — use the web UI for full details.)\033[K" } draw_header draw_loading FIRST_DONE=0 while true; do # -------- collect data (non-blocking) -------- NOW=$(date '+%Y-%m-%d %H:%M') IPADDR=$(get_ip) [ -z "$IPADDR" ] && IPADDR="No network" WEB="https://${IPADDR}/" BTC_STATE=$(systemctl is-active bitcoind 2>/dev/null || true) CKP_STATE=$(systemctl is-active ckpool 2>/dev/null || true) STATUS_LINE="" PROGRESS_LINE="" BAR_LINE="[--------------] 0.0%" SERVICES_LINE="Bitcoin: ${BTC_STATE} CKPool: ${CKP_STATE}" WORKERS_LINE="No workers detected (point your ASICs at this node)" # cpu load if [ -r /proc/loadavg ]; then read -r L1 L5 L15 _ < /proc/loadavg CPU_LINE="${L1} ${L5} ${L15}" else CPU_LINE="n/a" fi # memory if [ -r /proc/meminfo ]; then MEM_TOTAL=$(awk '/MemTotal:/{print $2}' /proc/meminfo) MEM_AVAIL=$(awk '/MemAvailable:/{print $2}' /proc/meminfo) if [ -n "$MEM_TOTAL" ] && [ -n "$MEM_AVAIL" ]; then MEM_USED=$((MEM_TOTAL - MEM_AVAIL)) MEM_PCT=$((MEM_USED * 100 / MEM_TOTAL)) MEM_LINE="$(printf "%dMiB / %dMiB (%d%% used)" "$((MEM_USED/1024))" "$((MEM_TOTAL/1024))" "$MEM_PCT")" else MEM_LINE="n/a" fi else MEM_LINE="n/a" fi # disk if df -h "$BTC_DIR" >/dev/null 2>&1; then read -r _ SIZE USED AVAIL USEP MNT <<< "$(df -h "$BTC_DIR" | awk 'NR==2{print $1,$2,$3,$4,$5,$6}')" DISK_LINE="${AVAIL} free of ${SIZE} (${USEP} used)" else DISK_LINE="n/a" fi # bitcoin-cli, but don't let it hang INFO=$(timeout 15 "$BITCOIN_CLI" -conf="$BITCOIN_CONF" getblockchaininfo 2>/dev/null) if [ -z "$INFO" ]; then # failed this round CONSEC_FAILS=$((CONSEC_FAILS + 1)) # if we have an older good value, reuse it if [ -n "$LAST_INFO" ]; then INFO="$LAST_INFO" fi else # success – store and reset fail counter LAST_INFO="$INFO" CONSEC_FAILS=0 fi if [ "$BTC_STATE" != "active" ]; then STATUS_LINE="${RED}❌ Bitcoin service is not running.${RST}" elif [ -z "$INFO" ]; then if [ $CONSEC_FAILS -ge $MAX_FAILS ]; then STATUS_LINE="${RED}❌ bitcoin-cli has not responded for several checks.${RST}" BAR_LINE="[--------------] 0.0%" PROGRESS_LINE="" else # transient hiccup — keep showing last good data, or at least don't scream STATUS_LINE="${YEL}⚠ Waiting for Bitcoin Core…${RST}" fi else if command -v jq >/dev/null 2>&1; then IBD=$(echo "$INFO" | jq -r '.initialblockdownload') BLOCKS=$(echo "$INFO" | jq -r '.blocks') HEADERS=$(echo "$INFO" | jq -r '.headers') PROG=$(echo "$INFO" | jq -r '.verificationprogress') PRUNED=$(echo "$INFO" | jq -r '.pruned') if [ "$PROG" != "null" ]; then PROG_PCT=$(printf "%.1f" "$(echo "$PROG * 100" | bc -l 2>/dev/null || echo 0)") else PROG_PCT="0.0" fi if [ "$IBD" = "true" ]; then if [ "$(echo "$PROG_PCT < 0.1" | bc -l 2>/dev/null || echo 0)" = "1" ]; then STATUS_LINE="${YEL}⚠ Bitcoin Core is starting up and loading blockchain data…${RST}" else STATUS_LINE="${YEL}⚠ Syncing blockchain… ${PROG_PCT}%${RST}" fi else STATUS_LINE="${GRN}✔ Bitcoin Core is ready.${RST}" fi PROGRESS_LINE="Blocks: ${BLOCKS} / ${HEADERS} $( [ "$PRUNED" = "true" ] && echo '(pruned)' )" BAR_LINE=$(make_bar "$PROG_PCT" 30) else STATUS_LINE="${CYN}ℹ Bitcoin Core is active (install jq for more detail).${RST}" fi fi # -------- draw -------- draw_dashboard "$NOW" "$IPADDR" "$WEB" "$STATUS_LINE" "$BAR_LINE" "$PROGRESS_LINE" "$SERVICES_LINE" "$CPU_LINE" "$MEM_LINE" "$DISK_LINE" "$WORKERS_LINE" FIRST_DONE=1 sleep 5 done EOF chmod +x /usr/local/sbin/btc-console-dashboard cat > /etc/systemd/system/btc-console-dashboard.service <<'EOF' [Unit] Description=Bitcoin Solo Miner Console Dashboard (dialog) After=network-online.target WantedBy=multi-user.target [Service] Type=simple ExecStart=/usr/local/sbin/btc-console-dashboard StandardInput=tty StandardOutput=tty TTYPath=/dev/tty1 TTYReset=yes TTYVHangup=yes Restart=always [Install] WantedBy=getty.target EOF systemctl daemon-reload systemctl disable getty@tty1.service --now 2>/dev/null || true systemctl enable --now btc-console-dashboard.service # --------------------------------------------------------------------------- echo "NGINX with HTTPS + redirect" # --------------------------------------------------------------------------- mkdir -p "$CERT_DIR" openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \ -keyout ${CERT_DIR}/btc-solo.key \ -out ${CERT_DIR}/btc-solo.crt \ -subj "/C=CA/ST=Ontario/L=Barrie/O=BTC-Solo/OU=IT/CN=$(hostname -f)" >/dev/null 2>&1 chmod 600 ${CERT_DIR}/btc-solo.key cat > /etc/nginx/sites-available/btc-solo < /etc/logrotate.d/btc-solo <<'EOF' /opt/btc-solo/logs/*.log { weekly rotate 8 compress missingok notifempty copytruncate } EOF cat > /etc/logrotate.d/nginx <<'EOF' /var/log/nginx/*.log { weekly rotate 8 compress missingok notifempty copytruncate } EOF # --------------------------------------------------------------------------- echo "[8/8] Done" # --------------------------------------------------------------------------- echo echo "================================================================" echo " Bitcoin Solo Miner Appliance installed." echo echo " 1) Open: https://$(hostname -I | awk '{print $1}')/activate/" echo " 2) Set Admin Username / Admin Password" echo " 3) (Optional) Regenerate the cert" echo " 4) You will be redirected to the dashboard." echo echo " Stratum endpoint for ASICs: stratum+tcp://$(hostname -I | awk '{print $1}'):${CKPOOL_PORT}" echo "================================================================"