===================================================================== GWS BACKUP cPanel / Shared Hosting Installation Guide by KIKO Solutions — https://gwsbackup.com ===================================================================== Thank you for downloading GWS Backup. This guide walks you through installing the app on a cPanel server. The same steps apply to most Passenger-based Node.js hosting. Full illustrated guide + FAQ: https://gwsbackup.com/install.html Questions: support@gwsbackup.com --------------------------------------------------------------------- 1. BEFORE YOU START — WHAT YOU NEED --------------------------------------------------------------------- * A cPanel account that can run a Node.js app: "Setup Node.js App" (CloudLinux Node.js Selector) or "Application Manager" (cPanel's own). Most quality shared hosts have one. * Node.js 22.13 or newer available in the selector. This is REQUIRED — GWS Backup uses the SQLite engine built into Node, which needs no switch only from 22.13. The app will not start on anything older. * PHP with the ZipArchive extension (standard on cPanel) — used by the one-command update script. * Outbound HTTPS access (the server must reach Google's APIs, the GWS Backup licence server and gwsbackup.com, for updates). * YOUR FREE LICENCE KEY. The software will not run without one. Keys are free: ask for yours with the form on the home page, https://gwsbackup.com/#register — it is emailed to you straight away (a few sign-ups are checked by a person first, within 1-2 days). One key = one running installation at a time. Disk / memory: the app itself is ~100 MB. Memory depends on how many backups run at the same time, not on how many workspaces you have: allow about 1 GB for each backup running at once. The console works out how many your server can take ("Backups at once", Settings -> System) and the rest wait their turn. On a small server (2 GB or less) they run one at a time, so give each workspace its own start time, an hour or more apart. Backup data itself is stored in your own Google Drive, S3-compatible or Azure storage — not on the web server. --------------------------------------------------------------------- 2. SECURITY FIRST — WHERE TO INSTALL (PLEASE READ) --------------------------------------------------------------------- ► NEVER install GWS Backup inside public_html. The application folder contains your encrypted credentials database (gws-backup.db) and your .env, which holds the encryption key. If those files live under public_html, a misconfiguration could let anyone on the internet download them. The app is served by Node.js/Passenger — it does not need to be in your web root, and it must not be. Correct: /home/youruser/gwsbackup <-- app root Wrong: /home/youruser/public_html/backup <-- never do this ► Use a RANDOM subdomain name. Create a subdomain that cannot be guessed, e.g.: vault-k7x93q.yourdomain.com console-2f8zt.yourdomain.com Do NOT use obvious names like backup.yourdomain.com or gws.yourdomain.com. Bots constantly scan common subdomain names looking for admin panels. A random name keeps automated scanners and casual snoopers away from your login page. Don't link to it from anywhere public. ► Always enable HTTPS (run AutoSSL on the new subdomain before you first log in). --------------------------------------------------------------------- 3. FRESH INSTALLATION (cPanel) --------------------------------------------------------------------- STEP 1 — Create the subdomain cPanel → Domains → Create a New Domain (or "Subdomains"). * Name: something random, e.g. vault-k7x93q.yourdomain.com * Document root: a folder OUTSIDE public_html, e.g. /home/youruser/gwsbackup_web Then run SSL/TLS Status → AutoSSL so the subdomain gets a certificate. STEP 2 — Create the Node.js application cPanel → Software → Setup Node.js App → Create Application: * Node.js version: 22.13 or newer * Application mode: Production * Application root: gwsbackup (folder in your home dir, NOT inside public_html) * Application URL: the random subdomain from Step 1 * Application startup file: app.js Click CREATE, then STOP the app for now. With Application Manager instead: cPanel -> Software -> Application Manager -> Register Application, with the same values. It uses the system Node, so check that it is 22.13 or newer first (section 5a). STEP 3 — Upload the application files cPanel → File Manager → open the application root folder (e.g. /home/youruser/gwsbackup): * Upload the two files from this download into that folder: gwsbackup-cpanel--app.zip gwsbackup-cpanel--installer.php * Open "Terminal" in cPanel (or SSH), then: cd ~/gwsbackup php gwsbackup-cpanel--installer.php The installer extracts the application and removes the zip. It keeps itself in the folder, ready for the next update. It also adds one cron job, which keeps the console running (see "Keeping the console awake" below). If it cannot, it prints the line for you to add in cPanel -> Cron Jobs. (Alternative without a terminal: use File Manager's "Extract" on the app zip directly in the application root, then delete the zip, and add the keep-awake cron job by hand — see "Keeping the console awake" in section 4.) STEP 4 — Set the application URL variable Back in Setup Node.js App, add an environment variable: NEXTAUTH_URL = https://vault-k7x93q.yourdomain.com (your real subdomain, with https://). This is required for Google Drive OAuth callbacks to return to the right address. STEP 5 — Start the app In Setup Node.js App, click START (or RESTART). On first boot the app generates its own keys and writes them to .env in the app folder. Open that file and copy ENCRYPTION_KEY somewhere safe BEFORE you put any client data in — see section 5. STEP 6 — First-run setup in the browser Visit https://your-random-subdomain/ The setup takes you through six steps, in order. If you sign out half way, it picks up at the right one. 1. Your account — create your administrator account and SAVE THE RECOVERY KEY it gives you somewhere safe (it is shown once; the app never sends email, so it is the only way back in if the password is lost). 2. Keys — confirm the recovery key is stored, and download a copy of the encryption key to keep off this server. (It can wait; Overview reminds you until you have it.) 3. Licence — paste the key we emailed you. (No key yet? Ask for one at https://gwsbackup.com/#register — the setup waits at this step until you have it.) Validation needs an internet connection. 4. Agreement — read and accept the licence agreement. 5. Where backups go — choose Google Drive, S3-compatible storage or Azure, and test it. Can be skipped; it is Settings -> Destination later. 6. First client — its name and Google Workspace domain, then its Connect page: the APIs to switch on, the service account key to paste, and the Client ID and scopes to copy into the client's Google Admin console (domain-wide delegation). Test tries every permission. Can be skipped too. DONE. Each client's schedule is in its own Settings, and Overview shows a short checklist of anything still to do. --------------------------------------------------------------------- 4. UPDATING AN EXISTING INSTALLATION --------------------------------------------------------------------- 1. Download the latest release from gwsbackup.com. 2. Upload the new gwsbackup-cpanel--app.zip AND gwsbackup-cpanel--installer.php into your existing application root (the folder with gws-backup.db in it). 3. In cPanel Terminal / SSH: cd ~/gwsbackup php gwsbackup-cpanel--installer.php The installer AUTOMATICALLY BACKS UP YOUR DATABASES first (to db_backups/backup_db_.zip), clears the old build, extracts the new one, removes the zip and any older installers. Your databases, .env, licence and settings are untouched. It also checks that the keep-awake cron job (below) is there, and adds it if it is not. 4. Restart the app in Setup Node.js App. UPDATING FROM THE CONSOLE (from 1.00) From version 1.00 the console can update itself. When a new version is out (it looks about every six hours), the sidebar says so, and Settings -> System -> Updates installs it when an Admin presses Install update: * it will not start while a backup or restore is running or waiting, and starts none while it works; * it downloads the release, checks it against our signed release list, and stops if anything does not match; * it moves the files it replaces into previous/, then runs the release's own installer, which backs up your databases first, exactly as in step 3 above; * it restarts the console. If the new version fails to start twice, app.js puts the previous one back, keeps the failed files in failed-/, and Updates says so. While our licence server cannot be reached, only critical fixes install. Updating by hand, as above, always works too. KEEPING THE CONSOLE AWAKE cPanel starts the app only when somebody opens a page, and its nightly maintenance restarts the web server, which stops the app. Until somebody opens the console again, nothing runs: no scheduled backups and no licence checks. One cron job fixes this, by asking the console for /api/health every five minutes: */5 * * * * curl -fsS -o /dev/null --max-time 60 https://YOUR-CONSOLE-ADDRESS/api/health The installer adds it for you, ending in a comment that starts "# gws-backup keep-awake" and names your app folder. It leaves every other cron job alone and saves a copy of them first, in db_backups/crontab-before-.txt. To add it by hand, use cPanel -> Cron Jobs with your console's real address. /api/health needs no sign-in and returns only {"ok":true}. On its first start after an update that changes the database, the app copies each database file into pre-upgrade/ before changing anything. If the copy cannot be made (not enough disk, for example) it changes nothing and refuses to start; see STARTUP-BLOCKED.txt in section 6. After updating from 0.9701 or earlier: if you had version pruning switched on, scheduled pruning waits until an Admin confirms it on Settings -> Retention, which shows what it would remove first. Housekeeping is automatic: each night, when no backup is due, the app tidies and compacts its databases, keeps the newest 3 archives in db_backups/ and pre-upgrade/ copies for 30 days, and removes the rest. Move any older archive you want to keep somewhere else. Settings -> System -> Housekeeping shows when each task last ran. --------------------------------------------------------------------- 5. FILES YOU MUST PROTECT (AND BACK UP YOURSELF) --------------------------------------------------------------------- In your application root: * .env — contains ENCRYPTION_KEY. This is the master key to your BACKUPS, not just a setting. Encrypted with it: every email (with its subject, sender, recipients, date and labels), every calendar and contacts backup, Drive files (by default for clients added from 1.00), the console's own database backups, and every stored credential. File and folder names are not encrypted. Without the key that data is permanently unreadable by any means. Copy it somewhere safe, off this server (Settings -> Users & security -> Encryption key downloads it). Only ENCRYPTION_KEY is irreplaceable. NEXTAUTH_SECRET can be regenerated (it only signs everyone out), and DATABASE_URL, NEXTAUTH_URL, PORT and GWS_DEPLOYMENT are specific to THIS server — do not copy those onto a different one without checking them. * gws-backup.db — the application database (client configs, encrypted credentials), with its gws-backup.db-wal / -shm files beside it. * clients/ — one database per client: each client's backup index. Without these, backups cannot be found to restore. * db_backups/ — automatic pre-update database backups. * pre-upgrade/ — a copy of each database, taken by the app itself just before it upgrades the layout. If you ever migrate servers: STOP the app on the old server first, then move the whole application folder together — gws-backup.db with its -wal / -shm files, the clients/ folder, and the same .env. Never delete a -wal file: it can hold your most recent changes. Remember: your licence key may only be live on one installation at a time — retire the old server when the new one goes live. READING YOUR BACKUPS WITHOUT THE APP decrypt-backup.mjs, in the app folder, decrypts backups you have downloaded from your storage into ordinary files and emails, with nothing but Node.js and the key: node decrypt-backup.mjs --in --out --key-file The key comes from --key-file (the file Settings -> Users & security downloads, or a .env), else ENCRYPTION_KEY, else the .env in the current folder; never from the command line. It never talks to Google or to your storage, and changes nothing it reads. --------------------------------------------------------------------- 5a. RUNNING MAINTENANCE SCRIPTS ON THE SERVER --------------------------------------------------------------------- Some tasks ship as .mjs scripts you run yourself. restore-console-db.mjs needs the SAME Node.js that runs the application (decrypt-backup.mjs runs on any Node 18 or newer, on any computer). cPanel installs it in a virtual environment, so a plain `node` in a terminal usually gives: command node not found This is normal and does not mean Node is missing. Which fix applies depends on which tool your cPanel has. Both exist in the wild and they put Node in different places: IF YOU HAVE "Setup Node.js App" (CloudLinux Node.js Selector) It runs each app in a virtual environment. In cPanel -> Software -> Setup Node.js App, copy the command shown next to "Enter to the virtual environment". It looks like: source /home/YOURUSER/nodevenv/gwsbackup/22/bin/activate && cd /home/YOURUSER/gwsbackup Paste that into the terminal. `node` then works for that session. IF YOU HAVE "Application Manager" (cPanel's own, EasyApache) There is no virtual environment to enter — Node is installed system-wide by EasyApache and simply is not on your PATH. Find it: ls -d /opt/cpanel/ea-nodejs*/bin/node \ /opt/alt/alt-nodejs*/root/usr/bin/node \ /usr/local/bin/node /usr/bin/node 2>/dev/null Then use that full path in place of `node`, e.g. cd ~/gwsbackup /opt/cpanel/ea-nodejs22/bin/node restore-console-db.mjs --file gws-console-.db.gwsenc Nothing needs enabling in WHM. The application is already running on one of these interpreters — if it starts at all, a suitable Node exists on the machine. IF NEITHER LISTS ANYTHING — ask the running app ps -u $USER -o pid,args | grep -i node The path in that output is the exact interpreter your application was launched with, which is always the right one to use. CHECK IT IS THE RIGHT NODE node --version # must be 22.13 or newer node -e "require('node:sqlite'); console.log('sqlite ok')" The application and restore-console-db.mjs both use Node's built-in SQLite, which needs a switch before 22.13. If `node --version` shows an older release you are on a different Node than the app uses — go back and pick the interpreter the application itself runs on. ALWAYS STOP THE APP FIRST for anything that writes to the database. It holds gws-backup.db, and every file under clients/, open. --------------------------------------------------------------- 5b. DATABASES FROM BEFORE v0.96 --------------------------------------------------------------- Every install from v0.96 onwards keeps its backup index in one file per client, under clients/. An install that began before v0.96 and was never migrated still keeps it inside gws-backup.db (and perhaps gws-backup-archive.db). This version does not open that older layout. It changes nothing, refuses to start, and writes STARTUP-BLOCKED.txt beside gws-backup.db saying what it found and what to do: install 0.9613 over it, run the two migration scripts from 0.9613 there, then install this version again. 0.9613 is no longer on the website: email support@gwsbackup.com and we will send it, or do the move with you. The layout this version uses: gws-backup.db the console: settings, users, clients, schedules, job log, audit log clients/.db one per client: that client's entire backup index A gws-backup-archive.db left empty by the old migration is not used any more and can be deleted. EVERY ONE OF THESE FILES MUST TRAVEL TOGETHER. The installer zips them all, the console's own database backup copies them all, and restore-console-db.mjs restores them all. A copy of gws-backup.db on its own is the settings and none of the backups. --------------------------------------------------------------------- 5c. RESTORING THE CONSOLE'S OWN DATABASE --------------------------------------------------------------------- The console backs ITSELF up every night, to the destination your client backups go to, under _gws-console-database/. There is nothing to switch on. Settings -> System -> Console database backup shows the copies it holds and has a "Back up now" button. One backup is a SET of files sharing a timestamp: gws-console-.db.gwsenc the console gws-console--client-.db.gwsenc one per client gws-console-.txt the manifest The .gwsenc files are encrypted with the ENCRYPTION_KEY in this server's .env. The manifest is plain text: it lists every file in the set, names the key they need by its fingerprint, and gives the restore command. The newest set of each of the last 7 days and of each of the last 4 weeks is kept; older sets are removed whole. Copies taken by 0.9613 and earlier are plain .db files, with a -archive.db beside some of them. restore-console-db.mjs still reads those. TO RESTORE 1. Stop the console. 2. Download EVERY file of the set you want into the app folder. (S3/R2/Azure: your provider's console. Google Drive: the _gws-console-database folder inside your backup folder.) 3. CHECK THE COPY BEFORE YOU TRUST IT: node restore-console-db.mjs --file gws-console-.db.gwsenc It finds the client files of the same set itself, decrypts and verifies each one, and — the part that matters — proves the credentials inside decrypt with the ENCRYPTION_KEY in this server's .env. Restore with the wrong key and the console comes up looking completely healthy, with every client and setting present, while not one connection works and nothing explains why. The check takes seconds and rules that out. 4. If everything passes, run it again with --install. It moves the current database files aside (.replaced-) rather than overwriting them, and removes the stale -wal / -shm sidecars that belong to the database being replaced. 5. Start the console. RESTORING ONTO A DIFFERENT SERVER Bring the ENCRYPTION_KEY with you. Everything else in .env can be regenerated; that one cannot, and without it neither the copies nor the credentials inside them can be read by any means. Set it in the new server's .env BEFORE running the check in step 3. --------------------------------------------------------------------- 6. TROUBLESHOOTING --------------------------------------------------------------------- * App won't start, and STARTUP-BLOCKED.txt is beside gws-backup.db → The app found something it will not open or could not upgrade, and changed nothing. The file says what and how to fix it. Delete it once fixed; it is rewritten if the problem is still there. * App won't start, and the error page or the host's log mentions "node:sqlite" → Your Node version is too old. Select Node 22.13 or newer in Setup Node.js App (Application Manager: see section 5a). * "Could not reach the licence server" / "The licence server did not respond in time" → The server has no outbound internet access, or a firewall is blocking HTTPS. The first licence check needs it; after that the console keeps working on the answer it holds and says the licence was not re-checked. * Sign-in page says sign-in needs https → You opened the console over http://. Run AutoSSL on the subdomain and use the https:// address. * "This account is locked after too many wrong tries" → After 5 wrong passwords or two-step codes in a row, each try waits: 1 minute up to the 10th, 5 minutes up to the 15th, 15 minutes up to the 20th. The 20th locks the account. The Admin made at setup unlocks it with the recovery key ("Forgotten your password?" on the sign-in page). Anyone else: an Admin unlocks them, or sets a new password, under Settings -> Users & security. * Something else: an Admin can download the app's log from Settings -> System (keys, tokens and passwords are taken out first) and send it with the problem. * Login page loads without styling / 404s on assets → The app was extracted into the wrong folder, or the application root doesn't match the folder you uploaded to. * Google Drive connection redirects to the wrong address → NEXTAUTH_URL is missing or wrong (Step 4 above). Still stuck? https://gwsbackup.com/faq.html Or email support@gwsbackup.com (allow 1–2 days for free edition support) --------------------------------------------------------------------- LICENCE --------------------------------------------------------------------- GWS Backup is free to use under the GWS Backup Free Licence (https://gwsbackup.com/licence.html). It is not open source and may not be rebranded, resold or redistributed. One licence key permits one running installation at a time. Key usage is monitored; abused keys can be withdrawn. (c) KIKO Solutions Ltd — https://gwsbackup.com =====================================================================