This guide installs webdekeepalive.py on a Raspberry Pi (tested setup: Raspberry Pi 3, Raspberry
Pi OS Lite, Bookworm or newer) in the home directory of the user that runs it, sets up the
configuration, a weekly systemd timer per account (Sundays, every account at its own time) and an
Uptime Kuma heartbeat, and shows how to update it with git pull.
The examples use the user pi and the directory ~/python/webdekeepalive, i.e.
/home/pi/python/webdekeepalive. Use your own user name; the commands below take it from $USER
and ~ automatically.
Contents
- Prepare the Raspberry Pi
- Download with git
- Python environment
- Prepare the WEB.DE accounts
- Account files
- Global configuration
- Uptime Kuma push monitor
- Test by hand
- Install the systemd timer
- Test the systemd service
- Daily operation
- Updates with git pull
- Upgrading from version 0.9 (cron)
- Troubleshooting
- Uninstall
Log in to the Pi (e.g. ssh pi@raspberrypi.local) and install the required packages:
sudo apt update
sudo apt install -y git python3 python3-venv
python3 --version # must be 3.9 or newerSet the time zone, it decides when the weekly runs start:
sudo timedatectl set-timezone Europe/Berlin
timedatectltimedatectl must show System clock synchronized: yes and NTP service: active. The Raspberry Pi
has no hardware clock and gets its time from the network after every boot. With a wrong date the
TLS certificate check of the IMAP server fails.
mkdir -p ~/python
cd ~/python
git clone https://github.com/drhdev/webdekeepalive.git webdekeepalive
cd ~/python/webdekeepaliveThe repository content is now in ~/python/webdekeepalive. All following commands are run in this
directory unless stated otherwise.
The virtual environment keeps the dependencies (requests for the heartbeat) separate from the
system Python:
cd ~/python/webdekeepalive
python3 -m venv .venv
.venv/bin/pip install -r requirements.txtDo this once per account in the WEB.DE web interface:
- Log in to WEB.DE webmail
- Settings → POP3/IMAP (or E-Mail programs): allow access via IMAP (and SMTP if you want report mails) and save
- If your account offers or requires app-specific passwords (security settings), create one
for
webdekeepaliveand copy it, it is only shown once. Otherwise the normal WEB.DE password is used. - Wait about 15 minutes until the change is active
Server data (defaults in the script): IMAP imap.web.de:993 (SSL), SMTP smtp.web.de:465 (SSL)
or 587 (STARTTLS).
Create one file per account in secrets/. The file name without .env is the account name used
in the log, on the command line and in heartbeat messages.
cd ~/python/webdekeepalive
cp secrets/user1.env.example secrets/user1.env
nano secrets/user1.envThe minimum is:
ACCOUNT_ID=user1
ACCOUNT_EMAIL=your.name@web.de
ACCOUNT_PASSWORD=PASTE_PASSWORD_HERE
SCHEDULE=Sun 10:00| Key | What to enter |
|---|---|
ACCOUNT_ID |
Short name for logs and messages, default: file name |
ACCOUNT_EMAIL |
The WEB.DE address, also the IMAP user name |
ACCOUNT_PASSWORD |
WEB.DE or app-specific password from step 4. Files from version 0.9 with ACCOUNT_SMTP_PASS keep working. |
ACCOUNT_IMAP_HOST, ACCOUNT_IMAP_PORT |
Only change them for other providers |
SCHEDULE |
When the weekly login runs, e.g. Sun 10:00; every run starts at a new random time up to 90 minutes later. Give each account its own time, see below. Read by the install script (step 9), default Sun 11:00. |
HEARTBEAT_URL |
Optional own Uptime Kuma monitor for this account, see step 7 |
MAIL_SEND |
true sends a short report mail after every run (also when the login failed for network reasons). With Uptime Kuma you usually do not need it. |
MAIL_SMTP_HOST, MAIL_SMTP_PORT, MAIL_TO_EMAIL, ACCOUNT_FROM_NAME |
Report mail settings, defaults: smtp.web.de, 465, the account address, no name |
TEMPLATE_SUBJECT, TEMPLATE_BODY |
Mail templates, \n is a line break. Placeholders: {account} {email} {time} {status} {message} {log_excerpt} {hostname} |
Rules for the file: one KEY=value per line, no spaces needed around =, comments only on their
own line. Everything after = belongs to the value, so a password may contain #, = or spaces.
In nano: save with Ctrl+O, Enter, quit with Ctrl+X. Repeat for every account
(secrets/user2.env, ...).
Different times per account: all accounts log in on Sunday, but each at its own time, so WEB.DE does not see logins of several accounts from the same IP within seconds. Recommended for two accounts:
| Account | SCHEDULE |
Actual login |
|---|---|---|
user1 |
Sun 10:00 |
between 10:00 and 11:30, different every week |
user2 |
Sun 17:30 |
between 17:30 and 19:00, different every week |
Check a value with systemd-analyze calendar "Sun 17:30" (it shows the next date). A weekly login is
plenty to keep the accounts active.
Then protect the files:
chmod 700 secrets
chmod 600 secrets/*.envcd ~/python/webdekeepalive
cp webdekeepalive.config.sample webdekeepalive.config
chmod 600 webdekeepalive.config
nano webdekeepalive.configEvery option is explained in the file, the defaults fit the weekly runs. Usually you only change:
[LOGGING]
level = INFO
[HEARTBEAT]
enabled = true
url = https://uptime.example.com/api/push/AbCdEf1234?status=up&msg=OK&ping=Retry behaviour (section [IMAP]): network problems such as a WLAN or DNS hiccup are retried 4
times with pauses of 30, 60 and 120 seconds. A rejected password is never retried, because repeated
failed logins can get the account blocked.
The heartbeat reports a failed login and a run that did not happen at all (Pi switched off, SD
card broken, timer disabled). After each run the script calls the push URL with status=up and a
message like OK: 1/1 accounts logged in in 4s, or with status=down and the reason, e.g.
FAILED 1/1 in 215s: user2. If no push arrives within the heartbeat interval, Uptime Kuma marks the
monitor as down by itself.
Every account runs on its own (step 9), so one monitor per account is the clearest setup: each
monitor then shows exactly one account. The global URL in webdekeepalive.config gets a push from
every account run; it is useful as a single "keep-alive is running at all" monitor.
- Open Uptime Kuma and click Add New Monitor
- Monitor Type:
Push - Friendly Name:
WEB.DE keep-alive (Raspberry Pi) - Push URL: Uptime Kuma shows a URL like
https://uptime.example.com/api/push/AbCdEf1234?status=up&msg=OK&ping=. Click Copy. Keep this URL private, anyone who has it can report to the monitor. - Heartbeat Interval:
648000seconds (7.5 days) for the weekly run. Older Uptime Kuma versions limit the interval; if the value is refused, update Uptime Kuma. - Retries:
1 - Heartbeat Retry Interval:
21600seconds (6 hours) - Notifications: enable the channels that should alert you (e.g. Telegram, e-mail). If none exist yet, create one under Settings → Notifications first.
- Click Save
The monitor shows Pending until the first push arrives.
Why these values: each account runs once a week with a random delay of up to 90 minutes, and a run
takes seconds (or a few minutes with network retries). So two pushes of the same account are 7 days
plus or minus 1.5 hours apart. Interval plus retry interval (here 7.75 days) is clearly longer, so you
get no false alarms, but a missing run is reported on Monday. With Retries 1, Uptime Kuma
first switches to Pending and only alerts after the retry interval. For the global monitor (pushes
from all accounts) the same values work.
Paste the copied URL unchanged into webdekeepalive.config:
[HEARTBEAT]
enabled = true
url = https://uptime.example.com/api/push/AbCdEf1234?status=up&msg=OK&ping=The script replaces status, msg and ping on every call and masks the URL in the log.
Create one push monitor per account with the same settings (e.g. WEB.DE user1, WEB.DE user2) and
enter its URL in the account file:
HEARTBEAT_URL=https://uptime.example.com/api/push/User1TokenIt reports OK: login successful, 123 message(s) in INBOX or FAILED: <reason> for this account.
If you use only per-account monitors, set enabled = false in [HEARTBEAT] of
webdekeepalive.config.
Run these steps as your normal user in ~/python/webdekeepalive.
a) Reach Uptime Kuma from the Pi: send a test push with the URL from step 7 (replace the parameters at the end):
curl "https://uptime.example.com/api/push/AbCdEf1234?status=up&msg=manual-test"The answer must be {"ok":true} and the monitor turns green.
b) Dry run: reads all files and shows what would be done, without logging in, sending mail or calling the heartbeat:
.venv/bin/python webdekeepalive.py --dry-run -vCheck that there is no Invalid account file error and one would log in line per account.
c) One real run for a single account:
.venv/bin/python webdekeepalive.py user1 -v
echo "exit code: $?"Expected: [user1] login successful, N message(s) in INBOX, a FINAL_STATUS | user1 | SUCCESS
line and exit code 0. The heartbeat (and the report mail, if enabled) arrives.
The repository contains a service and a timer template in deploy/systemd/
(webdekeepalive@.service, webdekeepalive@.timer). Every account gets its own instance, e.g.
webdekeepalive@user1.timer, which runs only secrets/user1.env. The install script fills in your
user name and directory, copies the templates to /etc/systemd/system/, writes the SCHEDULE of
every account file into its timer, sets chmod 600 on all configuration files, makes
time-sync.target wait for a synchronised clock and enables one timer per account:
cd ~/python/webdekeepalive
./deploy/install-systemd.shRun it as your normal user (not with sudo), it asks for the sudo password itself. At the end it
shows the schedule and the next start time of every account:
user1: Sun 10:00 (plus up to 90 minutes random delay)
user2: Sun 17:30 (plus up to 90 minutes random delay)
NEXT LEFT LAST PASSED UNIT ACTIVATES
Sun 2025-01-05 10:41:17 CET 2 days left - - webdekeepalive@user1.timer webdekeepalive@user1.service
Sun 2025-01-05 18:12:55 CET 2 days left - - webdekeepalive@user2.timer webdekeepalive@user2.service
What the service does (see deploy/systemd/webdekeepalive@.service):
- runs
.venv/bin/python webdekeepalive.py <name>as your user in~/python/webdekeepalive - starts only after the network is up and the clock is synchronised
- if another account is running at that moment (both timers catching up after a reboot), waits for
it (up to
lock_wait, 15 minutes) instead of logging in at the same time - stops a run that hangs for more than 30 minutes (
TimeoutStartSec); the script then reportsdownto the heartbeat - runs with low CPU and disk priority and may only write to
logs/
Each timer starts its account weekly at its SCHEDULE plus a new random delay of up to 90 minutes
(RandomizedDelaySec), and catches up on a missed run after the Pi was switched off. To change a
time, edit SCHEDULE in the account file and run ./deploy/install-systemd.sh again. Run it again
as well after adding an account file.
Start a run for one account now and follow it:
sudo systemctl start --no-block webdekeepalive@user1.service
journalctl -u 'webdekeepalive@*' -fCtrl+C ends the journalctl view, not the run. Without --verbose the journal only shows warnings
and errors; the full log is in the log file:
tail -f ~/python/webdekeepalive/logs/webdekeepalive.logAfter the run:
systemctl status webdekeepalive@user1.service # "Deactivated successfully" / status=0/SUCCESS
systemctl list-timers 'webdekeepalive@*' # LAST shows the run, NEXT the next one
grep FINAL_STATUS ~/python/webdekeepalive/logs/webdekeepalive.log | tailIn Uptime Kuma the monitor shows the message OK: .... Repeat for the other accounts.
| Task | Command |
|---|---|
| When are the next runs? | systemctl list-timers 'webdekeepalive@*' |
| Result of the last run | systemctl status 'webdekeepalive@*.service' |
| Results per account | grep FINAL_STATUS ~/python/webdekeepalive/logs/webdekeepalive.log | tail -20 |
| Full log | less ~/python/webdekeepalive/logs/webdekeepalive.log |
| Run one account now | sudo systemctl start --no-block webdekeepalive@user1.service |
| Stop a running run | sudo systemctl stop webdekeepalive@user1.service (reports down to the heartbeat) |
| Pause one account | sudo systemctl disable --now webdekeepalive@user1.timer |
| Resume | sudo systemctl enable --now webdekeepalive@user1.timer |
| Change a time | edit SCHEDULE in secrets/<name>.env, run ./deploy/install-systemd.sh |
| Add an account | create secrets/<name>.env with its own SCHEDULE, .venv/bin/python webdekeepalive.py --dry-run -v, run ./deploy/install-systemd.sh |
| Remove an account | sudo systemctl disable --now webdekeepalive@<name>.timer, then delete secrets/<name>.env |
With level INFO a run writes about 5 lines per account. The log file is rotated at 1 MB and keeps
2 old files, so it never uses more than 3 MB. To write nothing at all to the SD card, set
file_enabled = false in [LOGGING]; the full log then goes to the journal
(journalctl -u 'webdekeepalive@*'). Passwords and heartbeat URLs are masked in the log.
Your configuration (webdekeepalive.config, secrets/*.env) and the logs are not part of the
repository, git pull never changes them.
cd ~/python/webdekeepalive
git pull --ff-only
.venv/bin/pip install -r requirements.txt
.venv/bin/python webdekeepalive.py --dry-run -vThen check what changed:
git log --oneline ORIG_HEAD..HEAD # new commits
git diff --stat ORIG_HEAD HEAD # changed files- New options in
webdekeepalive.config.sample: missing options in yourwebdekeepalive.configuse their defaults, so nothing breaks. To adopt a new option, compare the files and copy what you need:diff webdekeepalive.config.sample webdekeepalive.config - Files in
deploy/changed: install the units again with./deploy/install-systemd.sh git pull --ff-onlyrefuses to merge if you changed tracked files yourself. Show them withgit status, then keep a copy and reset them, e.g.git stash, pull again,git stash pop.
To go back to the previous version: git checkout ORIG_HEAD right after the pull, or
git log --oneline and git checkout <commit>. Back to the latest version:
git checkout main && git pull --ff-only.
Version 1.0 runs every account from its own weekly systemd timer instead of a cron line.
- Remove the old cron lines:
crontab -e, delete thewebdekeepalive.pylines, save - Update the code (step 12) and install the new dependencies (step 3)
- Your
secrets/*.envfiles keep working; add aSCHEDULEline with a different time per account (step 5). The keysACCOUNT_RETRY_*,ACCOUNT_JITTER,ACCOUNT_EMAIL_DELAY,LOG_DIR,LOG_LEVEL,LOCK_USEandLOCK_DIRare no longer used (the log says so once per run); delete them or move the values towebdekeepalive.config. Remove inline comments after values (KEY=value # comment), they would become part of the value. - Create
webdekeepalive.config(step 6) and continue with step 7 - Delete old cron output files, they may contain SMTP protocol traces:
rm -f cron_*.out
Changes in behaviour: exit codes are now 0 all OK, 1 all failed / configuration error, 2 some
accounts failed, 3 already running. The report mail is sent after the IMAP logout and only once.
| Symptom | Cause and fix |
|---|---|
Invalid SCHEDULE from the install script |
Check the value with systemd-analyze calendar "Sun 10:00" |
status=203/EXEC in systemctl status |
.venv missing or moved: repeat step 3, then ./deploy/install-systemd.sh |
Read-only file system in the journal |
logs_dir in webdekeepalive.config points outside logs/. The service may only write to logs/; keep the default. |
Invalid account file 'x.env': ... |
The reason is in the message; fix the file and run --dry-run -v |
login rejected: authentication failed |
Wrong password, IMAP access not enabled (step 4), or the change is not active yet. Not retried on purpose. |
retrying in 30s warnings, then success |
Short network problem, nothing to do |
gaierror / Network is unreachable until the end |
No network or DNS on the Pi: ping -c3 imap.web.de |
CERTIFICATE_VERIFY_FAILED |
Wrong clock: timedatectl (step 1) |
Report mail ... failed |
SMTP not enabled or wrong MAIL_SMTP_PORT; the keep-alive itself still counts as OK |
Another instance is still running after waiting 900s |
Another account's run hangs: systemctl status 'webdekeepalive@*.service' |
Files with credentials are readable by other users |
chmod 600 webdekeepalive.config secrets/*.env |
| Uptime Kuma stays Pending | No push yet. Test with curl (step 8a) and check [HEARTBEAT] enabled = true. |
| Uptime Kuma shows Down with a message | The message says which account failed; details in logs/webdekeepalive.log |
| Uptime Kuma shows Down without a message | No push within the interval: Pi off, timer disabled (systemctl list-timers) or no network |
| Run starts at an unexpected time after a reboot | Expected: Persistent=true catches up on a missed Sunday, and the service waits for the clock to be synchronised |
Exit codes: 0 all accounts logged in, 1 all failed / configuration error / stopped, 2 some
accounts failed, 3 another instance is running. systemctl status shows any code other than 0
as failed.
sudo systemctl disable --now 'webdekeepalive@*.timer'
sudo rm -r /etc/systemd/system/webdekeepalive@.service /etc/systemd/system/webdekeepalive@.timer \
/etc/systemd/system/webdekeepalive@*.timer.d
sudo systemctl daemon-reload
rm -rf ~/python/webdekeepaliveDelete the Uptime Kuma monitor and, if you created them, the app-specific passwords in the WEB.DE security settings. Without a regular login the accounts will expire again after some months.