With the Debian or rpm package (and the Raspberry Pi image), Warda updates itself:
once a night between 02:00 and 05:00 (each machine at its own time), it
installs the latest stable release, unless an administrator turned automatic
updates off on the System page. The same page tells the last result and
checks or updates at once. Only a release whose SHA256SUMS is signed by the
release key built into Warda (Ed25519) is installed, and the package must
match its checksum. The service itself never installs anything: it writes a
request that warda-update.service (root, run by warda-update.timer and
warda-update.path) carries out; journalctl -u warda-update tells what
happened, sudo warda update updates by hand and warda update -check only
looks. With a data directory other than /var/lib/warda, a request waits
for the next run of the timer (5 minutes).
Since 0.7.0 the updater also looks for a new version every 6 hours,
whatever the setting of the automatic updates, so that the System page
announces it the same day: each machine at minutes of its own (from
/etc/machine-id, spread over the 6 hours from midnight UTC), so that the
boxes never ask the release server together. Only the signed list of the
latest release is read then; the installation still waits for the night
(02:00 to 05:00) with automatic updates on. A check that fails waits for
the next time. warda-update.timer runs every 5 minutes (3 minutes after
the start of the machine) and decides which of these is due.
- The package is installed with
dpkg --force-confdef --force-confold: an/etc/default/wardachanged by an administrator is kept, and nothing is asked. - A dpkg locked by another one (apt, unattended-upgrades) is waited for, up to 10 minutes. That failure, like a full disk, is not held against the version: it is tried again at the next run.
- After installing, the updater waits up to 3 minutes for the new version to
run 30 seconds in a row. If it does not, the updater puts the previous
version back itself (
/usr/lib/warda/rollback), without waiting for systemd to give up. - Installed from the System page, the update shows its steps (request sent, download and checks, restart, done), a bar and a countdown on an estimate of 4 minutes (a Raspberry Pi is the slowest), then the page reloads by itself with the new version; past 10 minutes it says to wait and not to unplug the box.
- A version that did not stay up is not installed again at night; an
administrator can still install it. The rollback, whoever starts it,
writes the version it took away in
/var/cache/warda/update/rolled-back, which the next run of the updater reads. - The nightly attempt counts once the list of the releases could be read: when the release server does not answer, it is tried again at the next run (every 5 minutes in the window).
- Only an
https://update server is accepted (http://only on the machine itself,localhostor a loopback address), for the list and for the package. The list of the releases is read withlimit=20. - The helper units (
warda-update.timer,warda-update.path,warda-backup-usb.timer,warda-system.path) are turned on once, the first time the package brings them, also on upgrade; the units already turned on are listed in/usr/lib/warda/units-enabled. A unit an administrator disabled stays disabled. warda-update.serviceruns as root with a writable file system (dpkg writes/usrand/etc), and is otherwise closed: private/tmp, no home directories, no kernel modules, kernel logs, control groups, clock or host name changes, only IPv4, IPv6 and Unix sockets, no namespaces, no real-time scheduling, native system calls only.
The releases are read from GitHub first, in the public repository
warda-dns/Releases (WARDA_UPDATE_GITHUB in /etc/default/warda to
change it; set and empty, GitHub is not read), then, when GitHub fails (no
answer, an error, no release, a signature or a file refused), from the
public repository warda-dns/releases of https://gitea.tips-of-mine.com
(WARDA_UPDATE_SERVER and WARDA_UPDATE_REPO). warda update takes the
same settings as -github, -server and -repo. The signature is checked
the same way whatever the source: nothing is trusted from the host. The
System page tells where the latest release was read (Source: GitHub or
Source: Gitea), and the journal of the updater (or of the service, for
the Docker image and the archive) says which source answered and why the
other one did not. When the package cannot be downloaded from GitHub, it is
downloaded from Gitea if Gitea publishes the same version.
On GitHub the API is not used: it answers 60 requests an hour per address,
and many boxes may share one (CGNAT). The box reads
https://github.com/warda-dns/Releases/releases/latest/download/SHA256SUMS
and …/SHA256SUMS.sig (the latest release, the one GitHub marks as latest),
checks the signature, takes the version from the name of the package of
its architecture and of its format listed in SHA256SUMS
(warda_X.Y.Z_ARCH.deb, or warda-X.Y.Z-1.x86_64.rpm and
warda-X.Y.Z-1.aarch64.rpm when rpm installed Warda; one version only,
stable) and downloads it at
https://github.com/warda-dns/Releases/releases/download/vX.Y.Z/FILE.
GitHub answers these addresses with a redirect to its storage: a redirect
is followed only over https, to github.com,
objects.githubusercontent.com or release-assets.githubusercontent.com
(at most 5), any other is refused. A box behind a filtering firewall needs
github.com, objects.githubusercontent.com,
release-assets.githubusercontent.com and gitea.tips-of-mine.com on port
443.
Both public repositories must hold at least one commit (a README): the CI creates the tags of the releases on their default branch.
The Docker image and the archive are never updated by Warda. When Check
every 6 hours for a new version is on (the same setting as the nightly
updates, on by default), Warda checks every 6 hours (once a day before
0.7.0), the first time 1 to 61 minutes after it starts (task New
versions, updates.check), for a new signed stable release, and shows it on
the System page and in the summary of the services, with the command to
run in the folder of the compose file:
docker compose pull && docker compose up -d. Check now checks at once.
Only SHA256SUMS and its signature (and, from Gitea, the list of the
releases) are downloaded, from GitHub then Gitea as above; nothing is
installed. warda update -check works there too;
warda update refuses to install outside the Debian or rpm package.
Upgrading to 0.7.10#
Nothing is to do before the update, which installs itself as the others. What to know:
- No way back to 0.7.9 once 0.7.10 has started. At its first start
0.7.10 changes the database: two new tables for the
devices shared by several people,
and the table of the devices rebuilt for the kinds of
devices and the evidence of their system. The
previous version cannot open that database afterwards: it stops with
"the database was written by a newer version of Warda (schema …, this
version knows …): install that version again". So the automatic rollback
does not bring 0.7.9 back (
journalctl -u warda-rollback: "the previous version does not know the database of this one (schema …): no rollback"), and installing 0.7.9 by hand over it leaves a Warda that does not start, until 0.7.10 is installed again. A version of 0.7.10 that fails before it changed the database is still rolled back by itself. A backup made by 0.7.10 is refused by 0.7.9 too ("the backup comes from a newer version of Warda: update this one first"); a backup made by 0.7.9 is restored by 0.7.10. - In a pair, update both boxes. A secondary still on 0.7.9 refuses the configuration of a primary on 0.7.10 (it comes from a newer version) until it is updated itself.
- The terms of use are to accept again (version
2026-10-03: the anonymous statistics also tell the plan of the box): a banner for the administrators until one of them accepts, nothing locked meanwhile (see Terms of use and anonymous statistics). - The interface asked over HTTP may now lead to the name of the box,
by itself, once the box has a name with a certificate the browsers
trust;
sudo warda https-redirect offis the way out (see From HTTP to HTTPS). - The devices: a device that was a server stays a server; the others
are proposed a kind (Automatic: …). The systems told before are
kept, but Android, which is forgotten and told again from what the
device asks from then on: an iPhone shown as an Android phone corrects
itself, and an Android phone shows
Private address (…)until it is recognised again. - The statistics: at its first start 0.7.10 moves the counts by day kept under another time zone to the days of the zone of the box, when the zone was changed since they were counted (see Restarts).
Upgrading to 0.7.11#
Nothing is to do before the update, which installs itself as the others; 0.7.11 changes nothing in the database (no new table, no migration). What to know:
- The line Base list of the dashboard changes by itself once the box
has downloaded a list of
warda-listsbuilt with the two figures in its header: at its next check (within the hour), afterwarda-listsitself was updated. Until then it reads as before (see Lists). - The IPv6 DNS check: a network that showed Goes around Warda
because a router gives its own DNS server by DHCPv6 only now shows
Possible bypass; the warning of the dashboard, the action of the
security center and the warning of the device policies go for that
network. A notice
network.ipv6dnsalready recorded for such a router stays as it is in Alerts (it is not rewritten); the box then records onenetwork.ipv6dhcpfor the same router, worded as a possibility (see The states of the check). - A SIEM that reads the alerts of Warda gets a new kind,
network.ipv6dhcp, of severity 3.
Upgrading to 0.8.0#
Nothing is to do before the update, which installs itself as the others. What to know:
The terms of use are to accept again (version
2026-10-12: they name what 0.8.0 sends to the Internet): a banner for the administrators until one of them accepts, nothing locked meanwhile; the check of the exposure from outside and the checks of the addresses watched for known breaches wait for that acceptance (see Terms of use and anonymous statistics).No way back to 0.7.13 once 0.8.0 has started. At its first start 0.8.0 adds three migrations to the database: the table of the devices protected outside the home and the column
relayedof the journal, the two tables of the known data breaches, the two tables of the restricted mode. As for 0.7.10 (above), the previous version then refuses the database, the automatic rollback does not bring it back, and a backup made by 0.8.0 is refused by 0.7.13; a backup made by 0.7.13 is restored by 0.8.0.In a pair, update both boxes: a secondary still on 0.7.13 refuses the configuration of a primary on 0.8.0.
The mining pools are blocked on every box, whatever its plan, from the first start (switch Block the mining pools on Protections, on by default): a device that mines on purpose needs an allow of its pool (personal, or a rule of that device), or the switch off. With Warda Business, the company baseline rules now take the same list (see Plans).
Nothing else blocks more by itself: the automatic blocking of the learning, the restricted mode, the watch of the breaches and the protection outside the home are all off until an administrator turns them on. The exposure on the Internet runs its first check 10 to 60 minutes after the start (the check from outside once the terms of
2026-10-12are accepted).The query log: a name of the CSAM category is now journaled as
csam.invalid; the queries recorded before keep what they had.A SIEM that reads the alerts gets new kinds:
mining(6),learn.auto(2),breach(6),network.exposure(7),restricted(6),restricted.toomany(3),restricted.learned(2),bypass.mobileandbypass.sharing(4), and the block reasonsrestrictedandmining(see Alerts).The plan of the customer area: each box makes its installation identifier at its first renewal, nothing to do. A backup restored on another box no longer brings the plan: the box restored asks to take it over, confirmed in the customer area (see Backups). With warda-portal 0.8.0 a Subscription covers one box: in an account on the Subscription with several boxes, the one renewed last keeps the plan and the others keep it as a courtesy for 90 days after the upgrade of the customer area, then go to the free plan unless the customer moves the plan (the card of each box tells which). The boxes still on 0.7.x keep working; a backup of theirs restored elsewhere is now refused until it is confirmed, and their page shows the former message "The same key is used by another box".
Known breaches: until the online service has its key of Have I Been Pwned, the page says that the service is not open yet; the addresses added are kept and checked as soon as it opens.
Upgrading to 0.8.2#
Nothing is to do before the update, which installs itself as the others. What to know:
- The terms of use are to accept again (version
2026-10-13: they name the questions of the reputation of the domains): a banner for the administrators until one of them accepts, nothing locked meanwhile; the collective base (when it is on), the check of the exposure from outside, the checks of the addresses watched for known breaches and the questions of the reputation of the domains wait for that acceptance (see Terms of use and anonymous statistics). - No way back to 0.8.0 once 0.8.2 has started. At its first start 0.8.2 adds two migrations to the database: the option of the new suspicious domains, and the columns of the accounts and of the people of the directory for the sign-in. As for 0.7.10 (above), the previous version then refuses the database, the automatic rollback does not bring it back, and a backup made by 0.8.2 is refused by 0.8.0; a backup made by 0.8.0 is restored by 0.8.2.
- The reputation of the domains is on, with the suspicious domains blocked for the minors; Block for everyone the suspicious domains registered less than 14 days ago is off on a box that was already installed (on for the new installations only): an administrator turns it on. (From 0.8.5 Warda reads it again once, and turns it on unless an administrator turned it off: see Reputation of the domains.) Until the online service runs 0.8.2, it does not know the question (404): the box answers as without it and asks again 6 hours later.
- Outside the home, the names of the home network are no longer
answered (NXDOMAIN):
warda, the names of the devices, the local records and zones work at home only (see Protection outside the home). - In a pair, update both boxes: a secondary still on 0.8.0 refuses the configuration of a primary on 0.8.2. The first synchronisation once both run 0.8.2 restarts the secondary once (the configuration now holds the enrolled devices and the settings of the protections of 0.8.0), and both must run 0.8.2 for the secondary to relay the devices outside the home while the primary is down.
- The backups made from now on hold the settings of the mining pools, of the automatic blocking and of the protection outside the home (see Backups); one made before keeps those of the box it is restored on.
- The sign-in of the people of the directory (Warda Business) is off until an administrator sets it (see Sign-in of the people of the directory); the sentence that said it would come later is gone from the page.
- A SIEM that reads the alerts gets a new kind,
reputation(6), and the block reasonreputation(see Alerts).
Upgrading to 0.8.3#
Nothing is to do before the update, which installs itself as the others. What to know:
- No change of the database: 0.8.3 adds no migration. A box back on
0.8.2 (the automatic rollback), or a backup with the answer Block
page restored on 0.8.2, does not know that answer: it uses the null
address, with the warning
unknown answer to a blocked name: the null address is usedin its log. - The answer to a blocked name does not change by itself: the null
address stays, and the new answer Block page is chosen by an
administrator (Network → DNS services → Answers, see Block
page). Before choosing it: the web interface on the ports
80 and 443 (the page says when it is not), and the certificate of the
box to install on the devices (the certificate page,
http://warda/certificate), or the browsers show a security alert on the HTTPS sites first. - In a pair, update both boxes: the answer is a setting the primary gives its secondary, and a secondary still on 0.8.2 answers the null address instead. Each box makes its own authority: the devices install the certificate of both.
- A backup never holds the authority (it holds the answer chosen): a box restored on new hardware makes a new authority, to install again on the devices.
Upgrading to 0.8.4#
Nothing is to do before the update, which installs itself as the others. What to know:
The block page becomes the default answer to a blocked name (see Answers). Up to 0.8.3 the null address chosen was kept as an empty value, the same as "not chosen". So at its first start 0.8.4 reads the answer of the box again, once (then the meta
blocked_response_chosenis1), before it applies it:The box up to 0.8.3 From 0.8.4 No answer ever chosen the default: the block page (where the box can show it) Only the null address offered by default ever saved (with a change of the rate limit, for example) the default: the block page, as if never chosen The null address chosen after another answer (the last change of the answer in the administration log, dns.policy, is tonull, and an earlier one was another answer)the null address, now kept as nullThe block page, NXDOMAIN or REFUSED unchanged From then on the null address chosen is kept as such.
Where the page cannot show, the default stays the null address: the web interface not on the ports 80 and 443, or the local certificate authority not made. The page DNS services says so and why. With the
docker-compose.ymlof Warda (the network of the host,:80and:443) the default applies; a port mapping of your own is not detected (see Answers).What the household sees on a box that takes the new default: a blocked site opened in a browser shows "Blocked by Warda" instead of a page that does not load; on the HTTPS sites the browser shows its security warning first, until the certificate of the box is installed on the device (the certificate page,
http://warda/certificate). Apps fail as before. The dashboard says Block page on. The local certificate authority is made at the start (blockca/). To keep the former answer, choose Null address 0.0.0.0 / :: under Network → DNS services → Answers.No change of the database schema. A box back on 0.8.3 (the automatic rollback) reads an empty answer, and
null, as the null address, and ignores the mark, which it keeps: back on 0.8.4, the answer is not read again. A null address chosen on 0.8.3 in between is kept empty there, and is the default again on 0.8.4: choose it again.In a pair, update both boxes: the answer and the mark are settings the primary gives its secondary. A secondary still on 0.8.3 answers the null address where its primary of 0.8.4 shows the page by default. A primary still on 0.8.3 gives a configuration without the mark: a secondary of 0.8.4 reads the answer again, from the administration log the configuration carries, at the start that applies it. Each box makes its own authority: the devices answered by either install the certificate of both.
A backup made by 0.8.4 holds the answer and the mark; a backup made before is read again once restored (the restore restarts the box).
Another Warda box announcing itself as IPv6 DNS server is still told as a bypass after the update, as in 0.8.3, until an administrator confirms it on the network page (This is my Warda box: see The IPv6 DNS of the box); the other box of a pair needs no confirmation.
The block page under load (see Block page): the parts of a page get an empty answer, the pages opened have a rate of their own, the certificate page another; the box keeps up to 4,096 certificates of blocked names (16 MiB at most), where 0.8.3 kept 512.
Upgrading to 0.8.5#
What 0.8.5 changes on a box already installed (nothing is to do before the update):
- The terms of use are to accept again (version
2026-10-14: they add the look-alike names reported to the analysis service, and name the page Protection settings). Until an administrator accepts them, what the terms list waits: the collective base, the check of the exposure from outside, the checks of the known breaches, the questions of the reputation and the look-alike names reported; everything else works. - No way back to 0.8.4. At its first start 0.8.5 adds three migrations to the database (an index of the unblock requests by device and name, the table of the decisions on the alerts with the alerts of the monitored categories new until read — those kept before are marked read —, the table of the summaries of the past weeks). As for 0.8.2, 0.8.4 then refuses the database ("written by a newer version of Warda"), the automatic rollback does not bring it back, and a backup made after the update is refused by 0.8.4; a backup made by 0.8.4 is restored.
- Block for everyone the suspicious domains registered less than 14 days ago is read again once and turned on, unless an administrator turned it off (see Reputation of the domains).
- Names in the menus: the page Protections is Protection settings (menu Protection), the page DHCP is DHCP server (menu Network), in the 7 languages; the sentences under Outside the home and Look-alike names no longer show their raw key.
- Scheduled tasks that do not concern the box are no longer listed (see Scheduled tasks); the network check and the IPv6 announcements now show their runs.
- Devices: the maker of the known devices is named again from the table downloaded the first day; a virtual machine or a container may change its label ("KVM/QEMU virtual machine (…)" instead of "Private address (…)").
- Dashboard: a dashboard never customized gets the new card Exposure on the Internet; a customized one adds it with Customize.
- In a pair, update both boxes: a secondary still on 0.8.4 refuses the configuration of a primary on 0.8.5. The settings added (the automatic unblock, the logo, the mail server and the recipients of the summary, the mark of the reputation read again) go to the secondary with the configuration.
- During the beta nothing is closed: the checks of the plans by the box apply only once the subscriptions open (see Plans).
Upgrading to 0.8.6#
A version of corrections, without new function: nothing is to do before the update, which installs itself as the others. No migration: the way back to 0.8.5 stays open. What changes:
- The 15-minute unblock checks the quotas of the device and of the network before the name is unblocked (up to 0.8.5 the name was unblocked first, then blocked again an instant later when a quota was reached), and an unblock that follows an allow for good of the device is recorded without an end date, as the requests answered by an administrator.
- The unblock requests of the block pages are recorded one at a time: two pages sent together no longer pass the limit of the network (30 a day).
- A request sent to the block page from another site gets "The request could not be recorded", no longer "This page is too old".
- The CI: the tests of the Go code have 20 minutes per package (the
tests of
internal/admintake about 5 minutes and a half under the race detector, the default limit was 10), the jobtest30 minutes; the nightly security run starts at 03:05 UTC, before the build of warda-lists (03:17).
Upgrading to 0.8.7#
A version of corrections, from what a box in service showed on 2026-10-14 and 15. Nothing is to do before the update; no migration, the way back to 0.8.6 stays open. What changes:
A downloaded list that is not a list keeps the previous copy, in three more cases. On 2026-10-14 the server of the lists asked to sign in for a few hours and answered its page of login with 200: a line of it was read as a name, and the base list of the boxes became a list of one entry until the next refresh after the server was set back. Now:
- a web page is refused, by its type (
text/html) or by its first character (<); - a list of Warda (under the address of warda-lists: the base list, the
categories, stalkerware) without its header (
# Generated:) is refused; - a list of 1000 entries or more that loses more than half of them at
once keeps its previous copy; a copy so small is accepted when the
server has kept sending such copies for 24 hours (a list cleaned on
purpose, even rebuilt meanwhile), the first refusal kept beside the
copy (
list-….txt.shrink); the previous copy sent again in between makes the wait start over.
Each case is a failure of the refresh with its reason (the result
failedof the button Update the lists now, the warningblocklist download failed, keeping previous copyin the journal).- a web page is refused, by its type (
The collective base: each name is checked as the online service checks it before it is queued (the form of a registrable domain, any depth:
ec2-1-2-3-4.eu-west-1.compute.amazonaws.comis one). A name already queued that does not pass is left out, and a name the online service refuses (400 naming it,doubts[22].domain) is left out too: the next exchange sends the rest. Up to 0.8.6 one such name failed every exchange of the box, again and again (2026-10-14; warda-cloud 0.8.6 accepts these names). A name left out is logged (collective base: name … left out) and counted with the names sent.Exchange now (Collective base): the suggestions made after the exchange read the journal of a week, a while on a Raspberry Pi; they no longer stop when the page goes away (the error
suggestions not made: sqlite3: interrupted), two minutes at most.No USB drive plugged in is no longer a failure. The copy of 01:45 writes "no drive" and ends without error (the unit no longer fails every night); the System page says "No USB drive plugged in at the last copy (date): plug one into the box…", and the summary of the services no longer shows "The copy to the USB drive failed". A copy that fails with a drive plugged in is still a failure. The state written by 0.8.6 and before is read the same way.
Updates of the system (Raspberry Pi image)#
Since 0.7.0, on the Raspberry Pi image only, the System page has a card
System updates, under the updates of Warda: the updates of Raspberry Pi
OS waiting, that is every package apt-get full-upgrade would install
(name, installed version, new version; a package it would add has no
installed version), their number, the date of the last check, and the
buttons Check now and Install. unattended-upgrades still installs
the security updates every night as before (restart at 05:30 when one needs
it); this card shows and installs all the others, at the time an
administrator chooses. The image is recognised by
/etc/systemd/system/warda-os-updates.service, which only its build
installs (the kind pi of the anonymous statistics); the Docker image and
the Debian package on another machine have no such card.
- The service never runs apt: it writes
os-checkoros-upgradeinsystem-request, andwarda-system.service(root, throughwarda-system.path) carries it out, then writes the result inos-update-status.jsonin the data directory. Root refuses both words outside the image. os-check:apt-get update, thenapt-get -s full-upgrade(a simulation, which installs nothing), whose linesInst name [installed] (new …)make the list.os-upgrade:apt-get update, thenDEBIAN_FRONTEND=noninteractive apt-get -y -o Dpkg::Options::=--force-confdef -o Dpkg::Options::=--force-confold full-upgrade(a configuration file changed by hand is kept, nothing is asked), then a new check. A failure keeps its message and the last 20 lines of the output of apt (4 KB at most, any account in an address of a source left out), shown under the card; the list of the last check stays.- apt held by another program (the nightly unattended-upgrades, dpkg) is
tried again every 15 seconds for up to 10 minutes; past that, nothing is
done and the card says the automatic updates were running: try again
later (state
busy). - While a request waits or runs, the card shows "Checking the updates of
the system…" or "Installing the updates of the system…", a moving bar
and the time spent, and the page asks every 5 seconds. A check stops
after 30 minutes, an upgrade after 100 minutes (
warda-system.serviceitself after 2 hours,TimeoutStartSec=2h); a run still shown as running 5 minutes past its limit was killed and is shown as failed ("interrupted"). - When a package asks for a restart (
/run/reboot-required, the packages in/run/reboot-required.pkgs), the card says Restart needed, names them, and offers Restart the box, the same action as in Maintenance (password asked again). Nothing restarts by itself. - Checked every 6 hours (task System updates,
os.check): 6 hours after the last check or installation, whoever asked for it; the first time 1 to 61 minutes after Warda starts on a box never checked; a minute later while another action of the system waits or runs. - One request at a time: while one waits or runs, another is refused (409).
- API:
GET /api/v1/system/os-updates(right to read the system) answerssupported,pending(checkorinstall, not taken by root yet),status(checked,packageswithname,current,new;state:up_to_date,available,running,failed,busyorinterrupted(the last run stopped before its end: check again);action:checkorupgrade;started,finished,message,log,upgraded),reboot_requiredandreboot_packages. Outside the image it answers only{"supported": false, "reboot_required": false}.POST /api/v1/system/os-updateswith{"action": "check"}or{"action": "install"}(right to change the system) asks root; outside the image it answers 409. Both are written in the administration log (os.check,os.upgrade).