This guide covers Docker. On a cPanel or Linux server, use the server install guide; on a Windows PC, the Windows install guide.

Before you start

You will need three things:

You do not need Node.js. The image carries its own runtime.

Security first: where to run it

The container publishes the console on a plain HTTP port. That works only on the machine itself: signing in from anywhere else needs https://.

Use an address that cannot be guessed.

Firewall and network access

Docker publishes ports straight past your firewall.

On Linux, Docker writes its own iptables rules, and they are consulted before the ones ufw manages. A container published with -p 3000:3000 is reachable from the internet even while ufw status reports that port as denied.

If anything terminates TLS in front of the container — and on anything internet-facing it should — publish to loopback only. In your compose file, change:

ports:
  - "${GWSB_PORT:-3000}:3000"    # reachable from anywhere

ports:
  - "127.0.0.1:${GWSB_PORT:-3000}:3000"    # reachable only through your proxy

Outbound, the container needs a great deal: Google’s APIs, our licence server, whichever storage destination you have configured. The full list, with the reason for each entry, is on the requirements page.

If you filter outbound traffic by hostname, allow googleusercontent.com as well as googleapis.com — Drive serves the actual file content from there.

Fresh installation

1 Make a directory and put the two files in it. Download them from the download page and rename them:

mkdir gwsbackup && cd gwsbackup

mv ~/Downloads/gwsbackup-docker-1.00-compose.yml docker-compose.yml
mv ~/Downloads/gwsbackup-docker-1.00-env.example .env

2 Generate the two secrets and put them into .env:

openssl rand -hex 32 # paste as ENCRYPTION_KEY
openssl rand -base64 32 # paste as NEXTAUTH_SECRET

While you are in there, set NEXTAUTH_URL to the address you will reach the console on. Leave it blank only if that is plain localhost.

3 Start it. The image is pulled for you; there is nothing to build:

docker compose up -d

Check it came up healthy:

docker compose ps

The status column should read Up (healthy) within a minute. If it says Restarting, go to Troubleshooting — the logs will name the reason.

4 Finish setup in the browser. Open the console at http://localhost:3000 on this machine, or at your https:// address. Setup goes in order: your Admin account; the keys (save the recovery key it shows you — it is shown once — and keep the copy of the encryption key it offers); your licence key; the licence agreement. Then, if you like, where backups go and your first client, whose Connect page walks you through linking its Google Workspace.

The console never sends email. The recovery key is the only way back into the Admin account made here: it resets the password, and unlocks the account after too many wrong passwords. Anyone else is unlocked by an Admin under Settings → Users & security.

Files you must protect

.env holds ENCRYPTION_KEY, and it is not recoverable.

That key decrypts your encrypted backups and every stored client credential. If it is lost, they cannot be recovered — by us or by anyone. Keep a copy of .env somewhere safe and separate from this server, and never change ENCRYPTION_KEY on an install that already holds data.

If the container ever refuses to boot over a missing key, restore the original .env — do not work around it.

Where your data lives

Inside a Docker named volume, not inside the container:

This is why updating does not touch your data: the container is replaced, the volume is not. Your backups are not here at all — they go to the destination you configure: Google Drive, S3-compatible storage or Azure. A local folder is offered only in the Windows edition.

If you swap the named volume for a host folder, chown it to uid 1000 first. The container runs as an unprivileged user, and a host directory keeps its own ownership — which surfaces as SQLITE_READONLY, an error that mentions nothing about permissions.

Backing up the databases

Stop the container first. Copying a live SQLite database can produce a file that will not open:

docker compose stop

docker run --rm -v gwsbackup_gwsbackup-data:/data -v "$PWD:/out" \
  alpine tar czf /out/gwsbackup-data.tar.gz -C /data .

docker compose start

The volume name is your directory name plus _gwsbackup-data. Confirm it with docker volume ls.

The console also backs up these databases itself once a day, encrypted, to your backup destination. A copy like the one above is for moving the install, or for before you change anything by hand.

Updating an existing installation

Set GWSB_VERSION in .env to the new version, then:

docker compose pull
docker compose up -d

Your databases, licence and settings are untouched. Pinning the version keeps updating a decision you make. Once you are on 1.00, the console tells you when a newer version is out, under Settings → System → Updates, with these steps and the version to set. A container cannot replace its own image, so you run them yourself.

Moving to 1.00 from 0.97xx? A compose file downloaded before 1.00 names its version at the end of its image: line instead. Change that number to 1.00, or use the 1.00 compose file in its place, then run the two commands above. If you changed its ports: line, make the same change in the new file.

Troubleshooting

Start with the logs. They are almost always explicit:

docker compose logs --tail=50

“required variable ENCRYPTION_KEY is missing a value”, or “REFUSING TO START — Missing required environment”

.env is missing, or the secrets are still blank. Compose gives the first message and starts nothing; the second comes from the container when it is run without Compose. See step 2.

“ENCRYPTION KEY MISMATCH” in the logs

The container is running with a different ENCRYPTION_KEY from the one this data was encrypted with. The console opens, but stored credentials and encrypted backups cannot be read. Stop the container and restore the original .env before running any backup or restore. Do not carry on with a new key unless you accept losing every stored credential.

SQLITE_READONLY, or permission errors on /app/data

You have replaced the named volume with a host bind mount. Chown the directory to uid 1000, or go back to the named volume.

Connecting a Google Drive destination fails, or Google’s sign-in never comes back

The OAuth app you made in Google Cloud must list the redirect address shown on Settings → Destination. It is built from the address in your browser, so behind a proxy it is the https:// address. Set NEXTAUTH_URL to that same address.

“Too many wrong tries”, or the account is locked

Each account gets five free tries. After that it waits a minute before each try up to the 10th, five minutes up to the 15th and fifteen minutes up to the 20th. The 20th wrong password or two-step code in a row locks the account.

The Admin made at setup gets back in with the recovery key: Forgotten your password? on the sign-in page. It sets a new password, unlocks the account, makes it an Admin again and turns off two-step sign-in. Anyone else is unlocked, or given a new password, by an Admin under Settings → Users & security. The console never sends email, so there is no reset link.

Status shows “unhealthy”

The health check simply asks the console for its login page. If it is failing, the app is not serving — the logs will say why.

What we can and cannot do for you

We can help with the application: installing it, connecting a workspace, backups, restores, anything it does or fails to do. Email support@gwsbackup.com and a person reads it.

We cannot administer your Docker host, your reverse proxy or your firewall — we have no access to them.