]> ##&name; ###&version; - initial release if [ -e /etc/rc.d/rc.unraid-api ]; then /etc/rc.d/rc.flash_backup stop /etc/rc.d/rc.unraid-api uninstall rm -f /etc/rc.d/rc.unraid-api rm -f /etc/rc.d/rc.flash_backup mv -f /usr/local/emhttp/plugins/dynamix/include/UpdateDNS.php- /usr/local/emhttp/plugins/dynamix/include/UpdateDNS.php mv -f /usr/local/emhttp/plugins/dynamix/Registration.page- /usr/local/emhttp/plugins/dynamix/Registration.page mv -f /usr/local/emhttp/plugins/dynamix/include/DefaultPageLayout.php- /usr/local/emhttp/plugins/dynamix/include/DefaultPageLayout.php mv -f /usr/local/emhttp/plugins/dynamix/DisplaySettings.page- /usr/local/emhttp/plugins/dynamix/DisplaySettings.page rm -rf /boot/config/plugins/Unraid.net rm -rf /usr/local/emhttp/plugins/dynamix.unraid.net rm -f /usr/local/emhttp/webGui/javascript/vue.min.js rm -rf /usr/local/emhttp/webGui/wc fi &node-api; &plugins; /dev/null & cd $old_working_directory sleep 1 status exit 0 } startdebug() { stop local old_working_directory=$(echo $pwd) cd $node_base_directory /usr/local/bin/node/node-api/node_modules/pm2/bin/pm2 start $node_base_directory/node-api/ecosystem.config.js --env=$(echo $env)-debug --no-daemon cd $old_working_directory } stop() { local node_api_pid=$(pidof node-api | awk '{print $1}') if [[ $node_api_pid ]]; then local parent_pid=$(cat /proc/$node_api_pid/status | grep PPid | cut -f2) if [[ $parent_pid != 1 ]]; then kill -9 $parent_pid &> /dev/null else kill -9 $node_api_pid &> /dev/null fi fi } reload() { stop sleep 1 start sleep 1 status exit 0 } install() { # Stop old process stop # Install node-api and plugins for download in ${downloads[@]}; do rm -rf $node_base_directory/${download} mkdir -p $node_base_directory/${download} tar -C $node_base_directory/${download} -xzf /boot/config/plugins/Unraid.net/unraid-${download}.tgz --strip 1 done # Copy across wc files rm -rf /usr/local/emhttp/webGui/wc mkdir -p /usr/local/emhttp/webGui/wc cp /boot/config/plugins/Unraid.net/wc/* /usr/local/emhttp/webGui/wc # Start new process start } uninstall() { stop sleep 1 for download in ${downloads[@]}; do rm -rf $node_base_directory/${download} done rm -f /var/run/node-api.sock } case "$1" in 'status') status ;; 'version') version ;; 'start') start ;; 'switch-env') switchenv ;; 'start-debug') startdebug ;; 'stop') stop sleep 1 status ;; 'reload') reload ;; 'install') install ;; 'uninstall') uninstall ;; *) echo "usage $0 status|start|switch-env|start-debug|stop|reload|install|uninstall" esac ]]> **Unraid.net** Unraid.net provides access to a set web-based services: * Server status such as online/offline, storage used/available, etc. * Links for local and remote access to your server webGUI. * Backup and Restore of your USB Flash boot device. * much more to come A server is registered using your Unraid Community Forum credentials. Registered servers appear under the My Servers forum sub-menu. This is work in progress. Use this for testing purposes only! "", "wanaccess" => "no", "wanport" => "443" ]; } if (empty($remote['wanport'])) { $remote['wanport'] = 443; } $hasCert = $var['USE_SSL']=='auto' && file_exists('/boot/config/ssl/certs/certificate_bundle.pem'); $isRegistered = !empty($remote['apikey']); $boolWebUIAuth = $isRegistered && file_exists('/etc/nginx/htpasswd'); $isActivated = false; $isUptodate = false; if ($isRegistered) { exec("/usr/bin/php -f $docroot/plugins/dynamix.unraid.net/include/UpdateFlashBackup.php status", $output, $retval); $isActivated = ($retval == 0); if ($isActivated) $isUptodate = empty($output); } ?>
Unraid.net Status: : Allow Remote Access: : Disabled until you Provision a SSL Cert and enable SSL/TLS : Disabled until your root user account is password-protected :
WAN Port: : > WAN Port is the external TCP port number setup on your router to NAT/Port Forward traffic from the internet to this > Unraid server SSL port for secure web traffic.
  :
Flash backup: : Not activated   : > Click Activate to set up a local git repo for your local USB Flash boot device and connect to a dedicated remote on unraid.net tied tothis server. : Activated: Not up-to-dateUp-to-date   : > The Not Up-to-date status indicates there are local files which are changed vs. the remote on unraid.net. > Click Update to push changes to the remote. > Click Changes to see what has changed.   : > The Up-to-date status indicates your local configuration matches that stored on the unraid.net remote.   : > Click Deactivate to pause communication with your remote on unraid.net. > Click Reinitialize to erase all change history in both local and unraid.net remote.
]]>
mv -f /usr/local/emhttp/plugins/dynamix/include/UpdateDNS.php /usr/local/emhttp/plugins/dynamix/include/UpdateDNS.php- "", "wanaccess" => "no", "wanport" => "443" ]; } if (empty($remote['wanport'])) { $remote['wanport'] = 443; } if ($cli) { $remoteaccess = $remote['wanaccess']; $externalport = $remote['wanport']; $username = ''; $password = ''; } else { $remoteaccess = $_POST['remoteaccess']; $externalport = $_POST['externalport']; $username = $_POST['username']; $password = $_POST['password']; } $isRegistered = !empty($remote['apikey']); // protocol, hostname, internalport list($protocol, $hostname, $internalport) = explode(":", rtrim(file_get_contents("/var/run/nginx.origin"))); $hostname = substr($hostname, 2); if (!$isRegistered && empty($username) && !preg_match('/.*\.unraid\.net$/', $hostname)) { response_complete(406, '{"error":"Nothing to do"}'); } // keyfile $var = parse_ini_file('/var/local/emhttp/var.ini'); $keyfile = @file_get_contents($var['regFILE']); if ($keyfile === false) { response_complete(406, '{"error":"Registration key required"}'); } $keyfile = @base64_encode($keyfile); // internalip extract(parse_ini_file('/var/local/emhttp/network.ini',true)); $internalip = $eth0['IPADDR:0']; $ch = curl_init('https://keys.lime-technology.com/account/server/register'); curl_setopt($ch, CURLOPT_POST, 1); if (!$isRegistered && empty($username)) { curl_setopt($ch, CURLOPT_POSTFIELDS, [ 'internalip' => $internalip, 'keyfile' => $keyfile ]); } else { // servername, servercomment $servername = $var['NAME']; $servercomment = $var['COMMENT']; if (empty($username)) { curl_setopt($ch, CURLOPT_POSTFIELDS, [ 'servername' => $servername, 'servercomment' => $servercomment, 'protocol' => $protocol, 'hostname' => $hostname, 'internalport' => $internalport, 'internalip' => $internalip, 'remoteaccess' => $remoteaccess, 'externalport' => $externalport, 'keyfile' => $keyfile ]); } else { curl_setopt($ch, CURLOPT_POSTFIELDS, [ 'servername' => $servername, 'servercomment' => $servercomment, 'protocol' => $protocol, 'hostname' => $hostname, 'internalport' => $internalport, 'internalip' => $internalip, 'remoteaccess' => $remoteaccess, 'externalport' => $externalport, 'username' => $username, 'password' => $password, 'keyfile' => $keyfile ]); } } curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $result = curl_exec($ch); $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $error = curl_error($ch); curl_close($ch); if ($result === false) { response_complete(500, '{"error":"'.$error.'"}'); } response_complete($httpcode, $result, 'success'); ?> ]]> /dev/null # flush: this will ensure we start with a clean repo flush # start watcher loop as background process exec ${TASKNAME} &>/dev/null & exit 0 } stop() { # terminate watcher loop/process pkill --full "${TASKNAME}" &>/dev/null # remove any queued jobs and flush changes flush exit 0 } reload() { stop sleep 1 start sleep 1 status exit 0 } flush() { # remove any queued jobs _removequeue # push any changes ad-hoc echo ${TASKACTION} | at ${QUEUE} now &>/dev/null } _watch() { # start watcher loop while true; do if [ "$(git -C /boot status -s)" ]; then _hasqueue || ( logger "adding task: ${TASKACTION}" --tag flash_backup; echo ${TASKACTION} | at ${QUEUE} now +1 minute &>/dev/null ) fi sleep 60; done } _hasqueue() { # returns false if the queue is empty, true otherwise if [ -z "$(atq ${QUEUE})" ]; then return 1 fi return 0 } _removequeue() { # delete any at jobs in queue f atq ${QUEUE} | while read line; do id=`echo ${line} | cut -d " " -f 1` atrm ${id} done } _enabled() { local output=$(git -C /boot config --get remote.origin.url) if [[ $output == *"backup.unraid.net"* ]]; then return 0 fi return 1 } case "$1" in 'status') status ;; 'start') start ;; 'stop') stop ;; 'reload') reload ;; 'flush') flush ;; 'watch') _watch ;; *) echo "usage $0 status|start|stop|reload|flush" esac ]]> 1) $command = $argv[1]; if ($argc > 2) $command = $argv[2]; } else { $command = $_POST['command']; $commitmsg = $_POST['commitmsg']; } if (empty($command)) $command='init'; if (empty($commitmsg)) $commitmsg='Config change'; // keyfile $var = parse_ini_file("/var/local/emhttp/var.ini"); $keyfile = @file_get_contents($var['regFILE']); if ($keyfile === false) { response_complete(406, '{"error":"Registration key required"}'); } $keyfile = @base64_encode($keyfile); // check if activated if ($command != 'activate') { exec('git -C /boot config --get remote.origin.url', $config_output, $return_var); if (($return_var != 0) || (strpos($config_output[0],'backup.unraid.net') === false)) { response_complete(406, '{"error":"Not activated"}'); } } // if deactivate command, just remove our origin if ($command == 'deactivate') { exec('git --git-dir /boot/.git remote remove origin &>/dev/null'); response_complete(200, '{}'); } // build a list of sha256 hashes of the bzfiles $bzfilehashes = []; $allbzfiles = ['bzimage','bzfirmware','bzmodules','bzroot','bzroot-gui']; foreach ($allbzfiles as $bzfile) { $sha256 = trim(@file_get_contents("/boot/$bzfile.sha256")); if (strlen($sha256) != 64) { response_complete(406, '{"error":"Invalid or missing '.$bzfile.'.sha256 file"}'); } $bzfilehashes[] = $sha256; } $ch = curl_init('https://keys.lime-technology.com/backup/flash/activate'); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, [ 'keyfile' => $keyfile, 'version' => $var['version'], 'bzfiles' => implode(',', $bzfilehashes) ]); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $result = curl_exec($ch); $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $error = curl_error($ch); curl_close($ch); if ($result === false) { response_complete(500, '{"error":"'.$error.'"}'); } $json = json_decode($result, true); if (empty($json) || empty($json['ssh_privkey'])) { response_complete(406, $result); } // save the public and private keys if (!file_exists('/root/.ssh')) { mkdir('/root/.ssh', 0700); } if ($json['ssh_privkey'] != file_get_contents('/root/.ssh/unraidbackup_id_ed25519')) { file_put_contents('/root/.ssh/unraidbackup_id_ed25519', $json['ssh_privkey']); chmod('/root/.ssh/unraidbackup_id_ed25519', 0600); file_put_contents('/root/.ssh/unraidbackup_id_ed25519.pub', $json['ssh_pubkey']); chmod('/root/.ssh/unraidbackup_id_ed25519.pub', 0644); } // add configuration to use our keys if (!file_exists('/root/.ssh/config') || strpos(file_get_contents('/root/.ssh/config'),'Host backup.unraid.net') === false) { file_put_contents('/root/.ssh/config', 'Host backup.unraid.net IdentityFile ~/.ssh/unraidbackup_id_ed25519 IdentitiesOnly yes ', FILE_APPEND); chmod('/root/.ssh/config', 0644); } // add our server as a known host if (!file_exists('/root/.ssh/known_hosts') || strpos(file_get_contents('/root/.ssh/known_hosts'),'backup.unraid.net,54.70.72.154') === false) { file_put_contents('/root/.ssh/known_hosts', 'backup.unraid.net,54.70.72.154 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBKrKXKQwPZTY25MoveIw7fZ3IoZvvffnItrx6q7nkNriDMr2WAsoxu0DrU2QrSLH5zFF1ibv4tChS1hOpiYObiI='."\n", FILE_APPEND); chmod('/root/.ssh/known_hosts', 0644); } // blow away existing repo if reinit command if ($command == 'reinit') { exec('rm -rf /boot/.git'); } // ensure git repo is setup on the flash drive if (!file_exists('/boot/.git/info/exclude')) { exec('git init /boot &>/dev/null'); } // setup a nice git description if (!file_exists('/boot/.git/description') || strpos(file_get_contents('/boot/.git/description'),$var['NAME']) === false) { file_put_contents('/boot/.git/description', 'Unraid flash drive for '.$var['NAME']."\n"); } // setup git ignore for files we dont need in the flash backup if (strpos(file_get_contents('/boot/.git/info/exclude'),'startup.nsh') === false) { file_put_contents('/boot/.git/info/exclude', '# Unraid OS Flash Backup # Blacklist everything /* # Whitelist selected root files !*.sha256 !changes.txt !license.txt !startup.nsh !EFI*/ EFI*/boot/* !EFI*/boot/syslinux.cfg !syslinux/ syslinux/* !syslinux/syslinux.cfg !syslinux/syslinux.cfg- # Whitelist entire config directory !config/ # except for selected files config/drift config/plugins/unRAIDServer.plg config/random-seed config/shadow config/smbpasswd config/wireguard/privatekey config/plugins/**/*.tgz config/plugins/**/*.txz config/plugins/**/*.tar.bz2 '); } // ensure git user is configured exec('git --git-dir /boot/.git config user.email \'gitbot@unraid.net\' &>/dev/null'); exec('git --git-dir /boot/.git config user.name \'gitbot\' &>/dev/null'); // ensure upstream git server is configured and in-sync exec('git --git-dir /boot/.git remote add -f -t master -m master origin git@backup.unraid.net:~/flash.git &>/dev/null'); if ($command != 'reinit') { exec('git --git-dir /boot/.git reset origin/master &>/dev/null'); exec('git --git-dir /boot/.git checkout -B master origin/master &>/dev/null'); } // establish status exec('git -C /boot status --porcelain', $status_output, $return_var); if ($return_var != 0) { response_complete(406, '{"error":"'.${status_output[0]}.'"}'); } if ($command == 'status') { $data = implode("\n", $status_output); response_complete($httpcode, '{"data":"'.$data.'"}', $data); } if (($command == 'update') || ($command == 'reinit')) { // push changes upstream if (!empty($status_output)) { exec('git -C /boot add -A &>/dev/null'); if ($command == 'reinit') { exec('git -C /boot commit -m \'Initial commit\' &>/dev/null'); exec('git -C /boot push --force --set-upstream origin master &>/dev/null'); } else { exec('git -C /boot commit -m ' . escapeshellarg($commitmsg) . ' &>/dev/null'); exec('git -C /boot push --set-upstream origin master &>/dev/null'); } } } response_complete($httpcode, '{}'); ?> ]]> #sb-title {display:none} #sb-info {display:none} ]]> "", "username" => "", "avatar" => "", "wanaccess" => "no", "wanport" => "443" ]; } if (empty($remote['username'])) { $remote['username'] = ''; } if (empty($remote['avatar'])) { $remote['avatar'] = ''; } $arr = []; $arr['event'] = 'STATE'; $arr['ts'] = time(); $arr['guid'] = $var['flashGUID']; $arr['state'] = $license_state; $arr['keyfile'] = $key_contents; $arr['reggen'] = $var['regGen']; $arr['flashproduct'] = $var['flashProduct']; $arr['flashvendor'] = $var['flashVendor']; $arr['servername'] = $var['NAME']; $arr['serverip'] = $_SERVER['SERVER_ADDR']; $arr['internalip'] = $_SERVER['SERVER_ADDR']; $arr['internalport'] = $_SERVER['SERVER_PORT']; $arr['protocol'] = $_SERVER['REQUEST_SCHEME']; $arr['registered'] = empty($remote['apikey']) || empty($var['regFILE']) ? 0 : 1; $arr['username'] = $remote['username']; $arr['avatar'] = $remote['avatar']; echo json_encode($arr); ?> ]]> https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.js https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.min.js $MANIFEST_JSON echo "📋 Received manifest" # take each key and add it to MANIFEST_TXT KEYS=($((<${MANIFEST_JSON} jq -r 'keys | @sh') | tr -d \'\")) for ix in ${!KEYS[*]} do echo "${URL}${KEYS[$ix]}" >> $MANIFEST_TXT echo "✨ ${URL}${KEYS[$ix]}" done echo "🚀 Parsed Manifest – start downloads" xargs -n 1 curl --http2 -s -O < $MANIFEST_TXT echo "✅ Registration Wizard files downloaded" if [ -f "$MANIFEST_TXT" ]; then echo "â˜„ī¸đŸšŽ Dump temp files" rm $MANIFEST_TXT rm $MANIFEST_JSON fi # Copy files to boot mkdir -p /boot/config/plugins/Unraid.net/wc cp /usr/local/emhttp/webGui/wc/* /boot/config/plugins/Unraid.net/wc ]]> ]]> ]]> ($remote['email']) ? $remote['email'] : '', "flashproduct" => $var['flashProduct'], "flashvendor" => $var['flashVendor'], "guid" => $var['flashGUID'], "internalip" => $_SERVER['SERVER_ADDR'], "internalport" => $_SERVER['SERVER_PORT'], "keyfile" => str_replace(['+','/','='], ['-','_',''], trim(base64_encode(@file_get_contents($var['regFILE'])))), "protocol" => $_SERVER['REQUEST_SCHEME'], "reggen" => (int)$var['regGen'], "registered" => empty($remote['apikey']) || empty($var['regFILE']) ? 0 : 1, "servername" => $var['NAME'], "serverip" => $_SERVER['SERVER_ADDR'], "site" => $_SERVER['REQUEST_SCHEME']."://".$_SERVER['HTTP_HOST'], "state" => strtoupper(empty($var['regCheck']) ? $var['regTy'] : $var['regCheck']), ]; ?> " > ]]> ]]> /\n<\/head>/g' > /usr/local/emhttp/plugins/dynamix/include/DefaultPageLayout.php sed -i $'/