Updating ServerList
This document describes the official update and recovery procedure for ServerList.
ServerList updates are distributed as complete release packages. The built-in command-line updater validates the release, creates and verifies a mandatory recovery backup, safely applies the new version, runs database migrations, refreshes Laravel runtime state, and verifies that the application is healthy before returning it to service.
Important: Never manually overwrite an existing ServerList installation with files from a new release archive. Always use the official ServerList updater.
1. Overview
A normal ServerList update follows this process:
Download release
↓
Upload release package to the server
↓
Run scripts/update.sh
↓
Validate release package
↓
Run installation preflight
↓
Enable maintenance mode and drain/stop writers
↓
Create and verify mandatory recovery backup
↓
Apply release-managed files
↓
Remove obsolete release-managed files
↓
Run database migrations
↓
Refresh Laravel runtime state
↓
Verify storage and signal queue restart (workers stay stopped)
↓
Run internal application health check
↓
Install the new release manifest
↓
Run external HTTP health check while writes remain blocked
↓
Restore prior maintenance and worker state
↓
Update complete
Customer configuration, uploaded media, and other persistent installation data are protected during this process.
2. Obtaining an Update
ServerList updates are downloaded manually from the official ServerList distribution channel.
A release package is a complete .tar.gz archive, for example:
ServerList-1.3.0.tar.gz
ServerList-x.y.z.tar.gz
Always obtain ServerList updates from the official distribution source.
Do not use release packages supplied by unknown third parties.
The admin navigation checks Viwosi Labs for release availability and may show a
link to a newer release. This notification does not download or install
anything. Installing an update remains an administrator-controlled manual
process using this guide and scripts/update.sh.
Viwosi Labs may publish updates, but updates are not guaranteed.
3. Where to Upload the Release Package
The release archive does not need to be placed inside the ServerList installation.
It is recommended to upload it somewhere outside the public web root.
For example:
/home/serverlist/updates/ServerList-1.3.0.tar.gz
Other non-public locations are also acceptable as long as the Linux user performing the update can read the file.
For example, upgrade an installation running ServerList 1.2.2 to 1.3.0 by
uploading the ServerList-1.3.0.tar.gz release package and running the normal
scripts/update.sh procedure. The updater applies the release-managed files
and runs all required database migrations; no separate manual database step is
required for this release.
Do not place update archives somewhere that makes them publicly downloadable through the website.
After a successful update, the uploaded release archive may be removed.
4. Update User
Run the updater as the Linux user that owns the ServerList application files.
Do not run normal ServerList updates as root.
The deployment username is installation-specific. It may, for example, be:
serverlist
but ServerList does not require or assume a fixed Linux username.
The updater verifies that the current user owns the installation and can safely modify the required application paths.
Application updates still run without root privileges. On the standard deployment, only the installed root-owned control adapter uses narrowly scoped passwordless sudo to drain/resume fixed services. It cannot run arbitrary commands, install releases or run application code as root.
System-level preparation, such as initially creating the backup directory, may require an administrator.
5. Backup Directory
Every ServerList update requires a protected backup directory outside the live application and outside the public web root.
The standard location is:
/var/backups/serverlist
This directory must already exist and must be writable by the Linux user that owns ServerList.
Creating this directory is normally a one-time deployment task performed by the server administrator.
The standard deployment setup command creates/checks it with installation ownership and 0750 permissions. The standalone scripts/prepare-backups.sh remains available for initial installation and custom deployments.
The updater will refuse to continue if the backup directory:
- does not exist;
- is not writable;
- is inside the ServerList installation;
- cannot safely store the mandatory recovery backup.
Backups may contain sensitive application and database data. They must never be stored inside the public web directory.
6. Standard deployment: before your first update
If you completed the current standard deployment guide, setup is already done.
You do not need SERVERLIST_UPDATE_QUIESCENCE_HOOK or a customer-written hook.
For an existing installation that lacks the controls, an administrator runs:
sudo /usr/bin/python3 -I /var/www/serverlist/scripts/standard-deployment.py setup --install /var/www/serverlist --nginx-site /etc/nginx/sites-available/serverlist
Use the actual application and root-owned Nginx sites-available file paths. Allow a brief maintenance window. Setup preserves TLS/site settings, adopts the old documented queue/cron configuration, prepares backups, and supplies the restricted control adapter. It does not copy release files or run migrations. It supports a single dedicated Nginx/PHP-FPM ServerList VPS; custom layouts use the custom adapter guide.
If the installed release predates this setup script, extract the official new
release into a separate non-public staging directory, never over the live
installation. Run its scripts/standard-deployment.py setup with --install
pointing to the existing application. Then run the staged scripts/update.sh
from the live application's directory for this first update. This keeps all
release validation and backup protections intact and also handles an older
updater that does not yet discover the standard adapter automatically.
Do not manually copy new release files into the live installation. Root-owned deployment tooling is intentionally outside the application's release-managed files; rerun setup from a trusted release when release notes require an adapter upgrade. Setup refuses replacement during an unresolved update.
7. Normal update
Download the official release archive to a non-public location readable by the installation owner. Run:
cd /var/www/serverlist
sudo -u www-data ./scripts/update.sh /path/to/ServerList-version.tar.gz
If already logged in as the installation owner, simply run ./scripts/update.sh.
For the first adoption using separately staged tooling:
cd /var/www/serverlist
sudo -u www-data /path/to/staged-release/scripts/update.sh /path/to/ServerList-version.tar.gz
No manual service stops, barrier changes or sudoers edits are needed. Wait for
success, verify the site and retain the backup. Do not run Composer or npm for
a normal update; official releases include dependencies and frontend assets.
Custom deployments may explicitly set SERVERLIST_UPDATE_QUIESCENCE_HOOK to
their tested external hook instead of using the supplied standard adapter.
The target version must be strictly newer than the installed version. The updater refuses same-version installs and downgrades before it changes the live application. Read the target release notes before updating.
8. Release Validation
Before the live installation is modified, the updater validates the release package.
Validation includes checks for:
- a readable release archive;
- safe archive paths;
- supported file types;
- duplicate archive paths;
- required release metadata;
- a valid ServerList version;
- safe release-manifest paths;
- release file hashes;
- unexpected files;
- persistent-data boundary violations.
Every official release contains a generated release manifest describing the release-managed files and their SHA-256 hashes.
If release validation fails, the update stops before the live installation is modified.
9. Installation Preflight
After validating the release, the updater performs read-only checks against the existing ServerList installation.
These include checks for:
- a recognizable ServerList installation;
- the currently installed version;
- the installation lock;
- the existing
.env; - correct installation ownership;
- writable application paths;
- writable persistent storage;
- writable Laravel cache paths;
- PHP 8.4.1 or newer for the CLI runtime;
- all installer-required PHP extensions, including native Mbstring, Iconv, LibXML, PostgreSQL PDO and Redis;
- PostgreSQL backup tools;
- required command-line utilities;
- available filesystem space;
- a writable protected backup directory.
The updater also checks every release-managed target before beginning the backup.
A failed preflight stops the update before the live installation is changed. The runtime checks use the staged release’s requirements without booting Laravel. PHP-FPM and queue workers must also use PHP 8.4.1 or newer (PHP 8.x) with the same required extensions; CLI preflight cannot validate those separate processes.
10. Mandatory Recovery Backup
A complete verified recovery backup is mandatory for every update.
There is no supported option to skip it.
The updater creates a new timestamped directory below:
/var/backups/serverlist
For example:
/var/backups/serverlist/20260902T184037Z-1.0.0
A completed recovery backup contains:
database.dump
environment.env
storage-public.tar.gz
storage-private.tar.gz
persistent-state.tar.gz
application.tar.gz
backup-info.txt
SHA256SUMS
SNAPSHOT_COMPLETE
The updater changes maintenance/worker state before backup, but does not replace release files or run migrations until the snapshot has been completely created and verified.
Standard deployment consistency and recovery
The installed adapter closes Nginx ingress except exact GET /up, prevents new
systemd worker/scheduler starts, drains old Nginx workers and active PHP-FPM
requests, and gracefully stops queue processing. It restarts PHP-FPM behind the
barrier for read-only health checks. It never clears queues or force-kills
writers. Every verification checks managed configuration, service/cgroup state
and unexpected artisan writer processes, not merely a flag file.
Prior service state is stored privately under /var/lib/serverlist-update,
separate from the application-owned backup. The updater still preserves Laravel
maintenance files in the backup's .quiescence directory. Both ingress and
writer barriers persist across updater termination and reboot. Another update
cannot replace unresolved operational state.
Failures before release mutation restore the previous operation automatically
when possible. Failures after mutation keep the site closed and require verified
recovery; do not simply run artisan up. Restore/check the matching application,
database and media as described below. Once an administrator has verified the
recovered application and restored the saved Laravel maintenance files, the
standard adapter can resume using the state path printed by the updater:
sudo /usr/local/libexec/serverlist-update-control resume /var/backups/serverlist/ACTUAL-BACKUP-DIRECTORY/.quiescence
Do not guess that path or remove barrier files manually. The helper checks it against the root-owned saved transaction. Previously stopped workers remain stopped. A failed resume reasserts both barriers; the updater also attempts a fresh drain. Original deployment configuration backups and operational metadata must be kept until recovery is finished.
For custom infrastructure, see the separate hook contract.
Explicit SERVERLIST_UPDATE_QUIESCENCE_HOOK always overrides the default adapter.
11. PostgreSQL Backup
ServerList uses PostgreSQL.
Before an update, the updater securely loads the effective Laravel database configuration and creates:
database.dump
using PostgreSQL's custom dump format.
The database dump is then checked using PostgreSQL restore tooling.
Database passwords are not printed to the terminal or written to backup-info.txt.
Temporary PostgreSQL authentication material is created with restrictive permissions and removed when it is no longer required.
A read-only PostgreSQL schema-dump preflight runs before downtime. If the subsequent recovery dump or verification fails, no release files or migrations are applied; the updater restores the prior operational state and retains incomplete artifacts for diagnosis.
12. Environment Backup
The customer's existing .env is copied to:
environment.env
inside the protected recovery backup.
The live .env is persistent installation data.
A normal ServerList update never replaces it with a release-provided configuration file.
The contents of .env are not printed by the updater.
13. Persistent Storage Backup
ServerList separately backs up persistent application storage.
Public customer data is stored below:
storage/app/public
and is backed up as:
storage-public.tar.gz
This may include server banners, covers, site media, and other uploaded files.
Private persistent storage is backed up as:
storage-private.tar.gz
Persistent installation state, including the installed-state information required for recovery, is backed up as:
persistent-state.tar.gz
These backups are verified before the update may continue.
14. Application Backup
The currently installed ServerList application is backed up as:
application.tar.gz
This archive contains the application state required to restore the previous release.
When an installed release manifest exists, it is included in the application recovery backup.
This is important because the installed manifest records which files belonged to the previous ServerList release.
The application backup is created and verified before any release-managed files are changed.
15. Backup Metadata and Checksums
Every recovery point contains:
backup-info.txt
with non-sensitive information about the backup and update.
Secrets such as database passwords, application keys, and tokens are not written to this file.
The recovery directory also contains:
SHA256SUMS
The updater performs a final SHA-256 verification of the mandatory backup artifacts and rechecks writer quiescence before writing SNAPSHOT_COMPLETE. The marker is written last; without it the artifacts must not be treated as a completed recovery point.
If any required backup artifact fails verification, the update is aborted.
16. Persistent Customer Data
Normal ServerList updates preserve customer-specific data.
Protected persistent paths include:
.env
storage/app/public/**
storage/app/private/**
storage/app/installed
Release synchronization is not permitted to overwrite these locations.
Uploaded server media, custom site media, configuration secrets, and installation state therefore survive normal updates.
The release package contains product-provided assets separately, such as bundled hero images and bundled server-cover presets under public/images.
Those bundled product assets are release-managed and may legitimately change between ServerList versions.
17. Release-Managed Files
ServerList itself manages application files such as:
app/**
bootstrap/**
config/**
database/**
docs/**
licenses/**
public/build/**
public/images/**
resources/**
routes/**
scripts/**
vendor/**
artisan
composer.json
composer.lock
VERSION
The exact set of managed files is recorded in the release manifest.
During an update, the updater synchronizes these files from the verified release package.
Every applied managed file is checked against the release manifest after synchronization.
18. Obsolete File Removal
A new ServerList version may remove files that existed in an older version.
Leaving those files behind can cause incorrect behavior or security problems.
For installations with an existing release manifest, the updater compares:
previously managed files
with:
new release managed files
Files that were managed by the previous release but no longer exist in the new release are classified as obsolete.
The updater safely removes only those obsolete managed files.
It does not recursively delete arbitrary directories and does not use this mechanism to remove customer-persistent data.
This obsolete-file mechanism is part of the normal ServerList update process.
19. Maintenance Mode
After preflight, ServerList enters Laravel maintenance mode and the deployment hook drains and stops all writers. Only then does the updater create the database and media recovery snapshot.
During maintenance mode, public requests receive an HTTP 503 response.
The updater verifies that Laravel's maintenance state was created correctly before proceeding.
The application and deployment write barrier remain closed while backups, release files, migrations, runtime state, and both internal and external health checks are processed. Existing maintenance options are saved and restored on success; an already-offline installation is not brought online.
20. Database Migrations
After the new release-managed files have been applied and verified, the updater runs Laravel production migrations.
Conceptually:
php artisan migrate --force --no-interaction
The updater never uses destructive commands such as:
migrate:fresh
A verified pre-update PostgreSQL dump already exists before migrations are allowed to run.
If migrations fail, the update stops and ServerList remains in maintenance mode.
21. Laravel Runtime Refresh
After migrations, the updater clears Laravel runtime caches using targeted commands.
The update process currently refreshes:
compiled views
configuration cache
route cache
event cache
compiled services and package state
This is intentionally handled by the updater.
Customers should not normally need to run:
php artisan optimize:clear
during a standard ServerList update.
Node.js and npm are not required for normal customer updates because compiled frontend assets are already included in the release.
Composer is also not required during a normal update because production dependencies are included in the release package.
22. Public Storage Link
The updater verifies:
public/storage
before returning ServerList to service.
The link must point to the installation's persistent:
storage/app/public
If the link is missing, the updater may recreate the expected Laravel storage link.
If an unexpected file, directory, or incorrect symlink occupies this path, the updater stops rather than replacing it unsafely.
23. Queue Workers
After application code and runtime state have been updated, ServerList signals Laravel queue workers to restart.
Conceptually:
php artisan queue:restart --no-interaction
This signal alone is not a quiescence mechanism. The deployment hook has already drained and stopped workers, including workers using --force, and must keep them stopped until the updater calls resume. Resume starts fresh processes only for workers that were running before the update; queued jobs are not deleted.
Workers must listen to both default and server-scans (substitute the configured
REDIS_QUEUE name for default if changed), with a 60-second worker timeout.
When upgrading an older worker definition, update its service arguments and
restart the service as described in Production Setup. The updater does not
edit systemd configuration, and queue:restart cannot change queue subscriptions.
24. Internal Health Check
Before ServerList leaves maintenance mode, the updater performs an internal application health check.
This verifies that:
- Laravel can bootstrap successfully;
- the configured database can be reached;
- a database health query succeeds;
- no database migrations remain pending.
If the internal health check fails, the updater stops and ServerList remains in maintenance mode.
25. Installed Release Manifest
After the application has passed its internal health check, the verified manifest from the new release is installed as:
release-manifest.txt
in the ServerList installation root.
The manifest is installed atomically.
The updater then verifies the installed application against this manifest.
This installed manifest becomes the authoritative managed-file state used by the next ServerList update.
It allows future releases to determine which old files may safely be removed as obsolete.
26. Returning ServerList Online
Before downtime, the updater prepares and validates the external health-check URL from ServerList's effective Laravel application configuration. It uses this preserved customer URL for verification after the internal update phases succeed.
After the external health check also succeeds, ServerList restores its previous maintenance state and calls the deployment hook to restore the previous worker/ingress state.
Saved maintenance files and options are restored exactly, or removed if the site was previously online. If resume fails partway through, the updater attempts to close maintenance and quiesce writers again, reports failure, and retains recovery data.
27. External Application Health Check
While maintenance mode and the deployment write barrier are still active, the updater performs an HTTP request against ServerList's public health endpoint (Laravel excludes /up from maintenance mode):
/up
For example:
https://servers.example.com/up
The URL is derived from the application's effective configured APP_URL.
The health endpoint must return:
HTTP 200
for the update to be considered successful.
TLS certificate verification remains enabled for HTTPS installations.
If the external health check and operational-state restoration succeed, the update is complete. A previously online site returns online; existing maintenance mode is preserved.
28. Successful Update
A successful update ends with output similar to:
ServerList update completed successfully.
Installed version: 1.3.0
Installation: /var/www/serverlist
Recovery backup: /var/backups/serverlist/...
8132 verified release-managed files were applied.
1 obsolete managed files were removed.
0 obsolete managed files were already absent.
Database migrations completed successfully.
Laravel runtime caches refreshed successfully.
Public storage link verified successfully.
Laravel queue restart signal sent successfully.
Internal application healthcheck passed successfully.
Installed release manifest committed and verified successfully.
External application healthcheck passed successfully.
[OK] ServerList pre-update operational state restored.
The exact number of managed or obsolete files depends on the release.
After this message, the update is complete.
The uploaded release .tar.gz may then be removed if desired.
Do not delete the recovery backup merely because the update succeeded.
29. Failed External Health Check
If the public /up health check does not return HTTP 200, the updater treats the update as failed.
Maintenance and the deployment write barrier remain active. The updater reasserts quiescence on failure; it does not open the site to perform the health check.
The updater reports the location of the verified pre-update recovery backup.
Do not simply run:
php artisan up
after a failed update.
First determine the cause of the failure or perform the appropriate recovery procedure.
30. Other Update Failures
If an update fails after live application changes have started, the updater does not report success.
When maintenance mode is active, the installation should remain in maintenance mode.
The updater reports the verified recovery backup location when one has already been created.
Do not repeatedly rerun a failed update without understanding the failure.
Do not manually mix files from the old and new releases.
If database migrations started or may have modified the database, use the complete recovery procedure.
31. Recovery Principles
The verified pre-update backup is the authoritative recovery point.
ServerList does not use generic Laravel migration rollback commands as its primary software-update recovery strategy.
Database migrations may transform or remove data in ways that cannot safely be reversed using application migration commands alone.
A complete rollback may therefore require restoring:
previous application
+
pre-update PostgreSQL database
+
persistent installation state where required
These components belong to the same recovery point.
32. Recovery Before Database Migrations
If an update failed after application files began changing but before database migrations were executed, restoring the previous application may be sufficient.
However, this is only appropriate when it is certain that no database changes occurred.
If there is any uncertainty, use the complete recovery procedure.
Keep ServerList in maintenance mode while recovery is performed.
33. Recovery After Database Migrations
If migrations started, completed, or may have modified the database, restore both the previous application and the pre-update database.
The recovery process is conceptually:
1. Keep maintenance and the deployment write barrier active; keep all writers stopped
2. Preserve the failed installation for diagnostics if required
3. Restore application.tar.gz
4. Restore PostgreSQL from database.dump
5. Restore environment.env if required
6. Restore matching public/private media from the same recovery snapshot
7. Restore persistent installation state if required
8. Verify filesystem ownership and permissions
9. Verify the public storage link
10. Refresh Laravel runtime state
11. Keep queue workers stopped (do not clear their queues)
12. Verify Laravel and the database
13. Verify the public /up endpoint with the write barrier still active
14. Restore saved maintenance state and resume prior workers/ingress only after verification
The exact restore commands depend on the deployment environment and should be performed by an administrator familiar with Linux, PostgreSQL, and the ServerList installation.
Never destroy or modify the only copy of the recovery backup while performing a restore.
34. Backup Preservation
The updater never uses the recovery backup as a temporary working directory.
The backup remains available after the update succeeds or fails.
Automatic pre-update backups are deployment recovery points. They are not a replacement for normal server backup practices.
Administrators should separately maintain an appropriate backup and retention strategy, preferably including off-server backups.
Old automatic update backups may eventually be removed according to the administrator's own retention policy.
Do not remove the newest recovery point until the updated installation has been sufficiently verified and a suitable backup policy is in place.
35. Security
ServerList update and backup operations are designed to avoid exposing secrets.
The updater:
- does not print database passwords;
- does not print the contents of
.env; - does not write secrets to
backup-info.txt; - uses restrictive permissions for temporary PostgreSQL authentication material;
- removes temporary database credentials;
- validates release archive paths;
- rejects unsafe archive file types;
- validates release hashes;
- protects persistent customer-data boundaries;
- rejects unsafe managed-file targets;
- limits privileged standard-deployment operations to the installed fixed control helper;
- does not automatically execute downloads from arbitrary URLs.
Always obtain update packages from the official ServerList distribution source.
36. Troubleshooting
If an update fails, first read the final updater output carefully.
The output identifies the stage that failed and, after a successful mandatory backup, reports the recovery backup directory.
Useful information when requesting support includes:
installed ServerList version
target ServerList version
operating system
PHP version
PostgreSQL version
the updater stage that failed
the exact error message
Do not publicly share:
.env contents
database passwords
APP_KEY
SMTP passwords
API keys
tokens
private backup archives
When requesting support, provide only the relevant non-secret updater output.
37. Versioning
ServerList releases use semantic-style version numbers.
Examples:
1.0.0
1.0.1
1.1.0
2.0.0
In general:
PATCH 1.0.0 -> 1.0.1
is used for compatible fixes;
MINOR 1.0.0 -> 1.1.0
is used for compatible features and improvements;
MAJOR 1.x.x -> 2.0.0
may contain larger or compatibility-affecting changes.
Always read the release notes before updating.
A release may contain version-specific instructions that supplement this general guide.
38. Release Update Model
ServerList releases use the following update model:
- release packages are downloaded manually;
- updates are performed from the command line;
- no automatic web updater is required;
- the release archive may be stored outside the installation;
- production dependencies and frontend assets are included;
- a verified pre-update backup is mandatory;
- customer configuration and uploads are preserved;
- obsolete release-managed files are removed safely;
- production database migrations run automatically;
- Laravel runtime state is refreshed automatically;
- previously running queue workers are restarted by the deployment hook;
- internal and external health checks run automatically;
- the new release manifest is installed automatically;
- prior maintenance/worker state is restored only after successful verification.
The admin update notification is advisory only; it never downloads or installs an update for you.
39. Update Checklist
For a normal update:
[ ] Download the official ServerList release
[ ] Read the release notes
[ ] Upload the .tar.gz outside the public web root
[ ] Log in as the Linux user that owns ServerList
[ ] Confirm /var/backups/serverlist is writable
[ ] Standard deployment setup completed (or an advanced custom hook is configured)
[ ] Run scripts/update.sh with the release archive path
[ ] Wait for the updater to finish
[ ] Confirm "[OK] ServerList pre-update operational state restored."
[ ] Verify the website normally
[ ] Retain the recovery backup
If the updater reports a failure:
[ ] Do not force the site online
[ ] Record the exact error
[ ] Record the recovery backup path
[ ] Determine whether database migrations started
[ ] Recover the matching application/database state when required
[ ] Verify the restored application before leaving maintenance mode
