Getting started

Upgrading

This page explains how to upgrade the scalws package, what the upgrade does to running services and configuration files, and how to go back if something goes wrong.

Before you upgrade: back up

Take a backup of the configuration first:

sudo scalwsctl backup /var/backups/scalws-$(date +%F)

It copies /etc/scalws/scalws.yaml, its site files and the certificate and key files they reference into a new directory. It does not contain controller.yaml, the ACME account and certificates, or the console’s state and credentials; archive those directories as well:

sudo tar -C / -czf /var/backups/scalws-files-$(date +%F).tar.gz \
    etc/scalws var/lib/scalws var/lib/scalws-console

Note the version you are running, so you can return to it:

scalwsd --version

Details: Files and services and scalwsctl backup.

Upgrade the package

From the apt repository:

sudo apt update && sudo apt upgrade

sudo apt install scalws upgrades only ScalWS.

From the dnf repository (RHEL family, Fedora):

sudo dnf upgrade scalws

From the same repository with zypper (openSUSE Leap, SLES):

sudo zypper up scalws

From the apk repository (Alpine Linux; OpenRC services, see Alpine Linux):

doas apk upgrade scalws

From a package file, install the newer file the same way as the first one (Installation).

What happens to running services

The package scripts (preinstall.sh, postinstall.sh, preremove.sh) do the following on an upgrade, with apt, dnf and zypper:

  • Binaries, systemd unit files, shell completions and /usr/lib/sysctl.d/90-scalws-adaptive-runtime.conf are replaced. systemd re-reads the unit files and the sysctl setting is applied again.
  • Ownership is set again on /etc/scalws (root:scalws, mode 0750), /etc/scalws/scalws.yaml and /etc/scalws/controller.yaml (root:scalws).
  • scalwsd.service, if it is running, is restarted onto the new binary. The old process drains its connections and exits; the new one checks the configuration (ExecStartPre=... --check) and starts. While one has stopped and the other has not yet started, no process accepts connections. If the new version refuses the configuration, the unit does not start.
  • scalws-controller.service, if it is running, is restarted. This restarts only the controller (KillMode=process): its scalwsd instances keep serving on the old binary while the new controller adopts them. The new controller then rolls them onto the new binary by itself, one at a time, unless instances.roll_on_upgrade is false or every instance slot up to instances.max is taken. With systemd before 254 (EL8, EL9, Debian 12, Ubuntu 22.04) the restart stops the instances too and starts new ones on the new binary: a short interruption instead of the handover (systemd before 254).
  • Where SELinux is enabled (RHEL family, Fedora, openSUSE Leap 16, SLES 16), a changed SELinux policy module is loaded and the package’s files are relabelled before the services restart. Coming from an .rpm without the module, the controller’s instances run unconfined, so the package restarts them in their confined domain (they drain for up to 30 seconds).
  • scalws-console.service, if it is running, is restarted. Then the scripts run systemctl enable --now scalws-console on every install and upgrade, so the console is enabled and started even if you had disabled it; the output then says so (scalws-console was disabled and is enabled again ...) and that the console listens on port 8090. To keep it off, mask it: sudo systemctl mask --now scalws-console; a masked console is never enabled or mentioned by an upgrade. Console sessions end; history and audit log stay.
  • A unit that was not running is not started (except the console, as above).
  • The console’s credentials file is created only if it does not exist.

A failed restart does not make the package installation fail, so check the services afterwards:

systemctl status scalwsd scalws-controller scalws-console
journalctl -u scalwsd -n 50

Configuration files are kept

/etc/scalws/scalws.yaml and /etc/scalws/controller.yaml are configuration files of the package (config|noreplace):

  • On Debian and Ubuntu they are dpkg conffiles. A file you changed is kept. If the package ships a changed version of a file you also changed, dpkg asks what to do; keeping your version is the default. A file you never changed is replaced by the new packaged version.
  • On RPM systems (%config(noreplace)) a file you changed is kept and the new packaged version is written next to it as <file>.rpmnew. A file you never changed is replaced. When the package is removed, a file you changed is saved as <file>.rpmsave.

The package’s scripts edit scalws.yaml only on a first install: they add sandbox: on (sandbox.md) and, on a host without IPv6, comment out the IPv6 listeners. An upgrade or a reinstall never edits it, so an existing installation keeps the sandbox mode it has. dpkg and rpm treat a file edited that way like one you changed.

Files the package does not ship are never touched: the site files in /etc/scalws/sites.d/, the console credentials in /etc/scalws/console/, your certificates, and everything under /var/lib/scalws, /var/lib/scalws-controller and /var/lib/scalws-console.

Unit files in /usr/lib/systemd/system are replaced. Keep your changes in drop-ins (sudo systemctl edit scalwsd), which upgrades leave alone.

New defaults in the packaged configuration are not merged into a file you changed. Compare your file with the commented example in /usr/share/doc/scalws/examples/scalws.yaml after an upgrade, then validate it:

sudo scalwsctl check

Site files on older installations

Installations that predate site files have no include: line, and scalwsctl site add and scalwsctl migrate stop with:

/etc/scalws/scalws.yaml has no `include:` for site files; add `include: sites.d/*.yaml` and create /etc/scalws/sites.d

The package creates /etc/scalws/sites.d (root:scalws, mode 0750). If it is missing, create it:

sudo install -d -m 0750 -o root -g scalws /etc/scalws/sites.d

Then add the line at the top level of /etc/scalws/scalws.yaml (under scalws-controller: the file named by controller.config, which is the same file by default):

include: sites.d/*.yaml

Check and reload:

sudo scalwsctl check
sudo scalwsctl reload

The rules for site files and the directory are in Sites and include.

Roll the instances onto the new binary

Under scalws-controller, the restarted controller adopts the running instances, which still run the previous scalwsd (their /proc/<pid>/exe is the deleted file that controller.webd_binary named). It then rolls them onto the binary on disk by itself. It creates a new generation that is a copy of the current one. The configuration file is not read again, so edits you have not applied stay unapplied. The instances are replaced one at a time: a new instance becomes active before an old one drains, so capacity does not drop.

The first new instance needs a free slot: the controller rolls only while fewer instances run than instances.max. When every slot is taken (for example min: 1, max: 1, or two instances with max: 2), it does not roll, because it would have to stop a serving instance before the new binary has proved it can start. It logs a warning instead (not rolled: instances.max leaves no spare slot). Raise instances.max by one, or roll them yourself with sudo scalws-controller reload (which replaces an instance in place, so capacity dips by one while it does).

scalws-controller status shows "binary": "replaced" for an instance that still runs the old file and "binary": "current" for one that runs the new file. It also shows the phases and the active generation:

sudo scalws-controller status

If the new binary cannot become ready, the controller goes back to the older generation (see below) and the old instances keep serving from the old, deleted file. An old instance that crashes meanwhile is replaced by an instance started from the new file.

To turn the automatic roll off, set roll_on_upgrade: false in the instances section of /etc/scalws/controller.yaml. The controller then only logs a warning that names the instances. Roll them yourself with a reload, which also retries a roll that went back:

sudo scalws-controller reload
sudo scalws-controller status

This reload reads the configuration file again, so it applies your pending edits too. Each instance’s version is the first line of its status view:

sudo scalwsctl --socket /run/scalws/web-0/admin.sock status

If an instance of the new generation fails to start while an older one still serves, the controller returns to the older generation by itself and reports it as last_rollback in status. Check the instance log in /var/lib/scalws-controller/logs/web-<n>.log.

scalwsctl reload does the same while the controller runs. See scalws-controller.

The standalone scalwsd.service is not affected by this: it still restarts with the short gap described above.

Rollback

Going back to an earlier configuration

On scalwsd.service, scalwsctl rollback re-applies the configuration before the active one, or --generation G. It uses the configurations the running process keeps in memory (at most 10, since it started), so after an upgrade, which restarts the process, it cannot reach configurations from before the upgrade. It also does not change the file on disk: the next reload reads the file again. To return to the configuration of your backup:

sudo scalwsctl restore /var/backups/scalws-2026-10-05            # dry run: what would change
sudo scalwsctl restore /var/backups/scalws-2026-10-05 --apply
sudo scalwsctl reload

scalws-controller has no rollback command. Restore the files from a backup (or restore an entry of the console’s history) and run sudo scalws-controller reload; this makes a new generation with the earlier content. The generations it applied are kept in /var/lib/scalws-controller/generations/<n>/scalws.yaml, readable by root, with the site files expanded into them, which helps to compare what changed.

Going back to an earlier package version

Install the earlier version again, from the repository if it still offers it, or from the package file:

apt list -a scalws                        # versions the repository offers
sudo apt install scalws=<version>         # apt asks you to confirm the downgrade

With dnf:

dnf --showduplicates list scalws          # versions the repository offers
sudo dnf downgrade scalws-<version>

With zypper:

zypper search -s scalws                   # versions the repository offers
sudo zypper install --oldpackage scalws-<version>

The package scripts restart the running services as on an upgrade. A downgrade also replaces the binary, so under scalws-controller the restarted controller rolls the instances back onto the earlier binary by itself, when a slot is free as described above. Otherwise, or with roll_on_upgrade: false, run sudo scalws-controller reload to put them there.

Every section of the configuration rejects unknown keys, so a configuration that uses settings added in the newer version is refused by the older one. Restore the backup you took before the upgrade first, then downgrade.

See also