Changelog

What's new in CloudZH.

Every release with what changed for you. Your dashboard shows the same notes in your language behind the version badge, and installs updates with a way back.

0.56.1

Latest
  • Installer and zh in your language, certificates in domain mode: In the installation package for customers, a few helper programs did not run. Because of that, the installer, CloudZH Setup in the terminal and the zh command line always stayed in German, and in domain mode the list of certificate options was missing (installing with your own domain stopped). The package is now built so that everything works; sudo zh update fixes existing servers.
  • CloudZH Setup is checked before every version: The automatic check now also installs CloudZH with the real customer package through CloudZH Setup in the browser on a fresh Ubuntu, clicks through every step and then checks the server and the dashboard. That is how the problem above came to light.

0.56.0

  • Updates through the licence service: Servers with the customer edition now download new versions signed from license.cloudzh.app instead of GitHub. Before installing, CloudZH checks the signature and every single file; a modified or foreign package is never installed. zh update, the button under Settings → Updates, automatic updates and the way back work as before.
  • Security updates automatically: Security updates of CloudZH arrive through the licence service with Standard and with an expired licence too. The new switch «Security updates automatically» (on by default) installs them at the time of the automatic updates.
  • App Store independent of the version: New apps and improved templates arrive through the licence service without CloudZH itself needing an update. The server checks once a day, right away with zh update catalog sync.
  • zh upgrade with an archive: zh upgrade now also takes the archive from the customer portal directly and checks its signature. Only one update runs at a time.

0.55.1

  • Debian: Fail2Ban and firewall work: On a freshly installed Debian, Fail2Ban did not start because Debian keeps SSH logins only in the journal, and the firewall (UFW) stayed off after the installation. The installer now sets up both correctly; sudo zh update fixes existing servers.
  • Every version is checked before release: Before a version reaches Stable, CloudZH installs itself automatically on fresh Ubuntu and Debian systems, checks System Health and opens the main pages. That is how the Debian problem above came to light.
  • New on cloudzh.app: Guides with a picture for every step in six languages (cloudzh.app/guides), all release notes at cloudzh.app/changelog and a status page at status.cloudzh.app.

0.55.0

  • Buy a free licence without losing anything: Trial, promotion and gift licences can be bought in the customer portal («Buy this licence») and in the dashboard. Licence, key and server stay the same, and so do your remaining free days: the first payment is only taken when they end. If you already have a subscription, the licence is added to it as one more seat. Reminders come 14 and 3 days before the end; free licences no longer have a payment grace period.
  • One subscription per customer, «Change number of servers»: Add servers right in your existing subscription (immediately, prorated), remove them at the end of the period and undo it until then. If more servers are active than the new number, you choose which ones stay; without a choice, the ones with the oldest check-in are released, with an email 7 days before and after the release. A second subscription is no longer created.
  • Purchases always in your customer account: The pricing buttons on cloudzh.app lead to buying in the customer portal (sign in or create an account, the purchase is remembered for 24 hours). Earlier purchases with the same email address appear in your account automatically when you sign in, with licences, servers and invoices.
  • Refunds, disputes, revocation: A full refund of the current period (including a withdrawal in the cooling-off period) ends the subscription and the licence immediately. A payment dispute pauses the licence until it is decided. When revoking, the licence portal asks whether the Stripe subscription continues, ends at the end of the period or ends now with a prorated refund. You can cancel in the customer portal even when your licence is revoked or paused.
  • Subscriptions recognised by product details: The licence service recognises Standard and Pro by the metadata of the Stripe product, so older subscriptions stay valid after a price change. A paid invoice without a CloudZH product raises an alert on Discord instead of staying silent.
  • Not paying is never better than Standard: If a licence has expired, is revoked, paused, released or out of contact for too long, the server runs as Standard, also with trial, promotion and friend licences: additional accounts and Pro features pause, nothing is deleted, and everything is back at once when the licence is active again. Profile → Subscription shows the effective plan, the licence plan, the reason and the owner.
  • Nothing pauses silently: An off-site backup you already set up keeps running on Standard (new targets and the download stay Pro). Automatic updates and extra notification channels show «Paused, part of Pro» and report it once; on Standard you choose the channel that receives security alerts. CloudZH security updates are available in restricted mode too (except when the licence is revoked or paused).
  • Accounts on the server: «Transfer ownership» under Users & permissions and zh owner transfer <name>. Friends and admins can delete their own dashboard account under My account (can be turned off). Re-enabling accounts and opening guest accounts only works up to the account limit of the plan, the audit log keeps 12 months and anonymises deleted accounts. A restore in restricted mode does not install missing apps, zh uninstall frees the seat.
  • Customer account and privacy: Under Security you download all stored data as JSON («Download my data»), change your email address yourself (confirmation to the new address, notice to the previous one) and delete your account, optionally cancelling the subscription at the end of the period. Turning off two-factor, removing a passkey or unlinking Discord signs out all other devices.
  • Automatic deletion periods: The licence service and the customer portal delete daily what is no longer needed: customer data 12 months after the last licence ended, IP addresses after 12 months, tickets 2 years after closing, never confirmed accounts after 30 days, long inactive accounts after a warning. For «one free licence per person» only a hash of the email address remains. Links to guest tickets are no longer stored in plain text.
  • Legal texts and website: Terms, Refund Policy, Promotion Terms and Privacy Policy describe account limits, restricted mode, buying free licences, seats, refunds, the customer account, backups in Cloudflare R2 and all deletion periods. Website and customer guide updated in all six languages.
  • Setup at Stripe: Add the webhook events charge.refunded, charge.dispute.created and charge.dispute.closed. The restricted key also needs Refunds (write), Charges and PaymentIntents (read) and Customers (write). Set the metadata product=cloudzh and plan=standard or plan=pro on every CloudZH product, plus servers_per_unit=3 for Household.

0.54.2

  • Delete several backups at once in the license portal: In the snapshot list you can now select several (click a row, hold Shift for a whole range, or select all with the box at the top) and remove them in one go with «Delete selection». The bar shows how many are selected and how much space that frees. The newest snapshot stays protected as before.

0.54.1

  • English by default: Unless you pick another language, the dashboard, live demo, website, CloudZH Setup, customer portal and command line (zh, ZH Menu, installer) now always appear in English, regardless of the browser or system language. A language you pick is still remembered.
  • Complete translations: The license portal is now also translated into Spanish, French, Portuguese and Turkish, plus about 120 texts in the dashboard and command line that were still in German. If a translation is ever missing, English appears instead of German.
  • Notifications in your language: Messages to Discord, Telegram, ntfy, Gotify and email arrive in the chosen language (otherwise English), as does the Tautulli test message.

0.54.0

  • Files with clear tabs: The file manager now has «Server», «External disks» and the new «Cloud». Mount, unmount and format are under External disks → Manage disks, the number on the tab shows connected disks that are not mounted yet.
  • Cloud storage under Files → Cloud: Mounted cloud storage now has its own tab, with management and a guide on ordering storage from a provider yourself (e.g. Hetzner Storage Box, IDrive e2, Backblaze B2, Infomaniak, Wasabi) and mounting it in one click. You are the provider's customer, CloudZH does not broker storage and has no access to your files. Part of Pro.
  • Store encrypted: When mounting, CloudZH can encrypt contents as well as file and folder names on your server before anything is uploaded (rclone crypt). The provider only sees unreadable data, Plex and the other apps see everything normally under /mnt/cloud/…. Existing files at the provider stay untouched.
  • Recovery key: After setup CloudZH shows the key once, as a file with instructions for reading the files with rclone even without this server. Later only after confirming your password under Manage → «Show key».

0.53.1

  • New name «CloudZH Setup»: The easy install in the browser is now called CloudZH Setup everywhere: in the customer portal under My licences, in the assistant, in the terminal and in the guide. Commands and steps stay the same (sudo bash install.sh --web).

0.53.0

  • Manage backups in the licence portal: The «Backups» page now shows how much is used in Cloudflare R2 (snapshots and ticket attachments), with the date and size of every snapshot. Single snapshots can be deleted, the newest one always stays.
  • Configurable retention: «Keep everything» (12 hours to 7 days) and «Then one per day» (7 days to 1 year) instead of a fixed 48 hours and 90 days. The page shows beforehand how many snapshots the next cleanup removes, «Clean up now» does it right away.
  • Dashboard: The history under Operations → Backups shows how much is on the server and how much at the chosen location, including the size of backups at the destination. «Keep» now goes up to 90 backups.

0.52.0

  • Choose where backups are stored: Under Operations → Backups → Location you decide where backups live: on this server (as before), on another disk or a NAS, in S3 storage (R2, B2, Wasabi, AWS, Hetzner, Infomaniak …) or in a cloud storage from Homelab (Google Drive, OneDrive, Dropbox and more than 60 others). The chosen destination replaces the system disk: every backup goes there encrypted, is checked and deleted locally.
  • Fallback to the server: If the destination can't be reached (NAS off, wrong credentials), the backup stays on the server, you get a notification and System Health warns. The next successful backup takes the ones left behind along, «Transfer now» does it right away.
  • History, retention and restore: The history shows what is at the destination. «Restore» briefly fetches the backup (signature checked) and cleans up afterwards. Retention and delete also apply at the destination.
  • Plans: Another disk and a NAS now also work with Standard, S3 and cloud storage stay Pro.

0.51.4

  • Add indexer without outgoing links: The form now shows an indexer's address as plain text, without a link to its website. CloudZH deliberately does not point to indexer sites or recommend sources.

0.51.3

  • Ubuntu updates: correct wording and language: Buttons, confirmation and notes in System Health now say «install» consistently and are translated into every language (some appeared in German in the English interface).

0.51.2

  • Tautulli API gets turned on: «Connect apps» (or zh apps wire) now turns on a disabled API in Tautulli by itself, because «Now playing» and the Plex history under Activity need it. Tautulli is paused briefly for this, all other settings stay. The message in the dashboard points to this button.

0.51.1

  • Licence portal in English: With «EN», the whole licence portal now appears in English, including buttons, dialogs, hints and promotions (about 300 texts added).
  • Promotions: A draft with «Offer runs 7 days» now counts the days from activation. The edit dialog lets you pick an end date again. Discord only reports «sold out» when every code has really been redeemed, with the time in words. Ending again keeps the reason, and a code typed in directly for a sold-out offer also shows «Better luck next time».

0.51.0

  • All Ubuntu updates automatically: Until now only security updates were installed at night. The same run now also installs the regular Ubuntu and Debian updates. Docker stays excluded so your apps don't restart unexpectedly, and the server never restarts on its own. Turn it on or off under Settings → Automation and rollback or with zh update system on|off; it is on by default.
  • Install now: Pending Ubuntu updates can also be installed during the day with one click in System Health, with the same care as at night.

0.50.2

  • Tautulli under Activity: «Now playing» only showed «Tautulli reports error 404». The cause is either an HTTP Root in Tautulli (e.g. /tautulli carried over from QuickBox) or a disabled API, and Tautulli answers both with 404. The dashboard now picks up the HTTP Root automatically (also for Discord notifications, Seerr and Maintainerr) and, if the API is off, tells you exactly where to turn it on.

0.50.1

  • No false alarm for Ubuntu updates on the overview: «Needs attention» listed regular Ubuntu updates even when none of them were security updates. The server still installs security updates on its own every night and reports them if any stay pending. The remaining updates now only appear as info in System Health.

0.50.0

  • Offers with a fixed run time: When you create or edit a promotion, choose «Offer runs» open, 1, 3, 7, 14 or 30 days from now, or until a date. It then ends on its own.
  • End automatically: Once every code has been redeemed, the promotion ends on its own (can be turned off). The licence portal shows why and how fast everything was gone, and Discord reports «Promotion sold out».
  • «All gone» like a giveaway: The promotion page shows an «All gone» stamp, how fast everything was claimed, «better luck next time» and where the next offer is announced (Discord, X, Reddit). Anyone who clicks «Claim» too late sees «So close!» in their account instead of an error. While licences are left, the page shows a progress bar, «Only 3 left, be quick!» at the end, and refreshes every 30 seconds.
  • Publish to: «Open in Reddit» now uses the new Reddit, with «Old view» as a fallback. Texts for a single licence no longer say «First 1 people».

0.49.0

  • Cloud storage and external disks in your apps: Plex, Jellyfin, Sonarr, Radarr, SABnzbd and every other app with a data folder now see mounted cloud storage under /mnt/cloud/<name> and USB disks under /mnt/disks/<name>. For example, you can pick a Google Drive as a Plex library or as a root folder in Sonarr. Newly mounted storage appears right away without restarting the app, even after rclone restarts.
  • One-time restart: When updating to this version, CloudZH recreates installed apps with a data folder once so they see the new folders. The apps are briefly unavailable; settings and data stay. Homelab → Cloud storage and Files → Drives show the path inside the apps.

0.48.0

  • Mount cloud storage (Pro): Under Apps → Homelab → Storage, CloudZH mounts Google Drive, OneDrive, Dropbox, pCloud, Proton Drive, S3, Backblaze B2, your NAS via SMB or SFTP, WebDAV (Nextcloud) and more than 60 other storage services as a drive using rclone. One button installs rclone and FUSE, with the download checksum pinned.
  • Guided just like the terminal: The wizard asks the same questions as rclone config, one at a time, with «Back» and the default as a suggestion. For Google, Microsoft, Dropbox and others you sign in in the browser and then paste the address from the address bar, which works from any device. Alternatively use rclone authorize on your PC as usual. The dashboard never sees passwords, tokens or keys, not even when editing.
  • In the file manager and the terminal: Mounted storage appears under Files → External, with a cache for streaming, read-only mode and automatic mounting at boot. In the terminal, zh cloud lists all storage and sudo zh cloud setup starts rclone config with CloudZH's configuration. The dashboard deliberately refuses local folders, options that run programs and targets on the server itself.

0.47.0

  • Publish to in the licence portal: Every promotion now has a «Publish to» section with Discord, Reddit and X. Drafts are built from the promotion's texts (headline, intro, link, prices from the settings), can be edited before sending and are remembered in your browser.
  • Discord directly: The licence service posts as «CloudZH» to its own announcements channel (add the webhook once in the portal, with a test message). Only for live promotions, @everyone only if you choose it, no double post within 30 seconds.
  • Reddit and X without API costs: Reddit opens with subreddit, title and text filled in, X with the finished post (character counter like on X). Plus copy buttons.

0.46.2

  • Fewer password prompts: After you confirm your password, the dashboard (and the license portal) won't ask again for 30 minutes instead of 5. The App Store also sets up Uptime Kuma with SQLite right away, so the database choice on first start is gone.

0.46.1

  • Installer in your language on every system: On systems with a different Python version than Ubuntu 24.04 (Ubuntu 22.04/26.04, Debian 12/13), messages of the installer and of the browser setup stayed in German because the matching agent could not find the dictionaries. They now always come from the package.

0.46.0

  • Easy install in the browser: sudo bash install.sh --web starts a setup assistant in your home network (e.g. http://192.168.1.50:8000). Everything else happens in the browser: system check, home only or your own domain (with certificate provider and token check), data folder with the free space of the disks found, paste your licence keys, install with live output and progress in percent. At the end you download the backup key, and «Open dashboard» has the setup token already filled in. In six languages. Experts still install in the terminal with sudo bash install.sh.
  • One command from your account: Under «My licences → Easy install» there is a personal command to copy (curl -fsSL https://account.cloudzh.app/i/… | sudo bash). It downloads the installer, checks its SHA-256 checksum and starts the assistant. No more copying with scp. Valid for 24 hours, up to 3 downloads, «Revoke» button.
  • Safe in your home network: The assistant only answers devices in private networks, needs the access code from the terminal (locked after 10 wrong attempts) and keeps running as its own service if the SSH window closes. Keys and tokens reach the installer only through the environment and never appear in a log. It stops by itself after the installation and removes a temporary firewall rule. If something fails, you can start the installation again right in the browser.

0.45.0

  • Add indexer: In the media library under Indexers there is now an "Add indexer" button next to "Test all". It opens your Prowlarr's full indexer list (currently around 650 entries), with search and filters for Usenet/torrent, access (public, semi-private, private) and language. Indexers you already have are marked.
  • Form from Prowlarr: After picking one you get exactly the fields Prowlarr needs for that indexer (e.g. API key, or username and password), with limits under "Advanced". "Test" checks the connection before anything is saved; "Add" creates the indexer in Prowlarr, and Prowlarr pushes it to Sonarr and Radarr right away.
  • Custom indexers: "Custom Newznab indexer" and "Custom Torznab indexer" cover anything not in the list: enter the address and API key yourself.
  • No built-in list: The selection always comes live from Prowlarr. New or renamed indexers appear with the next Prowlarr update, without a CloudZH update. Indexers that need a CAPTCHA at login can only be set up directly in Prowlarr; CloudZH points you there.

0.44.2

  • App list on the overview: On wide screens the apps now sit in several columns instead of one long row across the full width. As many full rows appear as fit without a scrollbar of their own; the rest is behind "Show … more apps". Widgets with their own scroll area no longer trap page scrolling; at the end the page scrolls on.
  • Version on app cards: Below "Image" the app's version is now shown (from the image metadata, e.g. 4.0.15.2941 for Sonarr), also in the app view.
  • Uptime Kuma 2: The App Store now installs Uptime Kuma version 2 instead of the unmaintained version 1.
  • Licence service subdomain protected: On the vendor server, installing an app with the licence service's subdomain is refused instead of installing it and leaving it unreachable.

0.44.1

  • Discord in English: Licence service alerts (new licence, tickets, codes, backup, discounts) and feedback from the dashboards now appear in English on the Discord server, matching the server's language.

0.44.0

  • Connect Discord with apps (Pro): Under Apps → Homelab → Discord, «Integrate Discord with App» guides you through the setup step by step: pick an app (Radarr, Sonarr, Lidarr, Prowlarr, SABnzbd, Tautulli or Seerr), create a webhook in Discord and paste it or reuse a Discord channel from Notifications, choose the events. CloudZH adds the webhook directly in the app and has it send a test message. You never have to open the app itself.
  • Manage: For each app you see the connected Discord channels and can test or remove them. In the app view under Apps → Installed, the «Discord» button takes you straight there. Once saved, the webhook address only shows as «Webhook …1234».
  • Discord community: At the bottom of the dashboard sidebar and on the overview of the customer account, a hint invites you to join until you have joined, choose «Already a member» or hide it. cloudzh.app also gets a «Join us on Discord» button that disappears after the first click.

0.43.1

  • Discord community: The official CloudZH server has been rebuilt, with forums for help, feature requests with voting and bug reports, plus announcements and a changelog. Every link (help menu in the dashboard, customer account, website, zh support) now goes through cloudzh.app/discord, which always points to a valid invite. The old invite had expired.
  • Licence service: Alerts such as new sales or licence letter errors can get their own Discord webhook (zh support webhook alerts), separate from dashboard feedback. Without it they go to the feedback webhook as before; backup and migration include it.

0.43.0

  • Gifts only after sign-in: Links from promotions and giveaways (/claim/…, /redeem/…) no longer show the code before you sign in. After signing in or creating an account, a popup «You received a gift» or «You won!» appears with «Redeem now» or «Close».
  • Only for you, expires after 30 days, sent by email: Once accepted, the code only works for your account (nobody else can redeem it) and expires after 30 days. It also arrives by email so you don't lose it. Open gifts appear on the overview and under «Redeem code → Your gifts», with «Redeem now» or «Decline». Expired or declined gifts free the code again.
  • Licence portal: Promotions and codes show who accepted a gift and when it expires; the counter on the website includes accepted gifts. The giveaway message, the promotion page and the Promotion Terms describe the new flow.
  • No guessing codes: Whether a code is valid only shows after clicking «Redeem», no longer while typing. The public code preview has been removed. After 10 invalid codes within 24 hours, further attempts are blocked until the next day (per account and per address); valid codes don't count.

0.42.0

  • Sales in the licence portal: Under Marketing → Discounts you create time-limited discounts, for example 30% for Black Friday or Christmas. Suggestions with the next date (Halloween, Black Friday to Cyber Monday, Christmas, New Year, Summer Sale) fill in everything. You choose whether the discount applies to the first payment, the first year or as long as the subscription runs. Stripe gets a promotion code that is only active between start and end.
  • Website and customer account show the sale: While it runs, cloudzh.app shows a banner with code and end date (with a countdown in the last 24 hours), prices appear struck through and reduced, and the buy links fill in the code. In the customer account and when buying from a trial, the discount is applied automatically. Anyone entering the code under «Redeem code» gets a hint.
  • Setup: The restricted Stripe key additionally needs Coupons and Promotion codes (write) and Products (read). At most one sale runs at a time, existing subscriptions keep their price.

0.41.0

  • Promotions in the license portal: Under Marketing → Promotions you create promotion pages directly: name, address (cloudzh.app/promotions/…), duration via quick picks, number of licenses. Texts are generated automatically and can be edited. A switch puts the page live or pauses it, without a website deploy. The list shows how many codes are still free.
  • Personal codes instead of a shared code: Every promotion has its own single-use codes. «Claim» on the website gives each person the next free code and redeems it right away in the customer account; the existing rules (one free license per person, no disposable addresses, new customers only) still apply. Existing series such as LAUNCH-6M #1–15 can be adopted.
  • Giveaways: Under Marketing → Giveaways you create a giveaway (reaction, active user, most active user or manual) and the codes are reserved. Paste the participant list, draw at random and copy the link and a ready-made message for each winner. Automatic collection through a Discord bot follows.

0.40.0

  • Sign in with Discord for your server (Pro): Under Apps → Homelab an assistant walks you through the setup step by step: create an application in the Discord Developer Portal, copy the redirect, enter the client ID and secret. CloudZH checks the details with Discord right away. Afterwards the sign-in page shows «Sign in with Discord».
  • Connected accounts only: Each person connects Discord once under Profile → Sign-in & passkeys. A second factor still applies, and admins stay bound to «home network or VPN only». Optionally limited to members of your Discord server.
  • Management: Admins see in the user list who has connected Discord and can unlink it. «Reset second factor» and a newly set password unlink Discord as well. You also find the setting under Security → Access rules.

0.39.2

  • Downgrades at the end of the period: Pro → Standard, yearly → monthly or fewer servers now start at your next renewal in the customer account, as the terms describe. Until then nothing changes: no credit, no payment, and the licence stays on its current plan. The scheduled change shows with its date next to the subscription and can be undone with one click. Upgrades (Standard → Pro, monthly → yearly, more servers) still apply right away, prorated.
  • Safe scheduling: discounts and subscription settings are kept when a change is scheduled. If an upgrade fails, the previously scheduled change stays in place. With a change to fewer servers scheduled, no further servers can be activated. During a Stripe trial only upgrades are possible.
  • Website and refunds: the section on switching plans and the refund policy now describe upgrades and downgrades precisely.

0.39.1

  • Select and delete codes: In the list under licence portal → Codes you tick codes (or all at once) and activate, deactivate or delete them together. Single codes can also be deleted on their detail page. For redeemed codes the issued licences stay with the customer; the log records what was deleted.

0.39.0

  • Codes in one place: The licence pool and «Trial licences & codes» are merged into one «Codes» page in the licence portal. When you create codes, pick the duration from ready-made entries (1 day, 1 week, 2 weeks, 1 month, 3 months, 180 days, 1 year) or type your own number of days; the list shows who redeemed each code.
  • Search in the licence portal: The search field at the top of the sidebar (key /) finds customers, licences, servers and codes by email, name, Discord name, licence ID, key ending, hostname or IP.
  • Discord in your customer account: «Sign in with Discord» on account.cloudzh.app, plus linking and unlinking Discord under Security. A new account is only created with an email address verified at Discord, an existing account is never taken over automatically, and an active second factor still applies. The Discord name shows up with the customer in the licence portal and can be searched. Set it up with zh-vps portal-discord.

0.38.5

  • Standard pauses extra accounts: when a server moves from Pro to Standard, only the owner can sign in to the dashboard. Other accounts are kept with their permissions and settings but paused (sign-in, open sessions, the live view and the terminal end). They are back as soon as you switch to Pro. Sharing Plex or Jellyfin is not affected. Users & permissions marks paused accounts, and Subscription shows how many there are.
  • A missing or damaged licence pauses no one: the pause only applies with an activated Standard licence. A paused account signing in with the right password does not count as a failed attempt and does not trigger a lockout.
  • Change plan in the customer account: the dialog now also explains moving to a cheaper plan (a credit for your next invoices instead of a refund) and what Standard means for other accounts. The website describes switching anew in every language.

0.38.4

  • License portal, deadlines as menus: Settings → Deadlines now only holds «Without contact» (7, 14, 30 or 60 days), «Payment grace period» (3, 7 or 14 days) and «Trial from CloudZH» (off, 7, 14 or 30 days), each as a menu instead of a number field. The daily trial limit only appears while trials are on. A previous value outside these steps stays selectable as «Current: …».
  • Duration when issuing: You choose a trial licence's duration (7 to 90 days) and an installation key's validity (1 to 30 days) directly in the dialog.
  • «Expires soon» as on the servers: The license portal shows the hint 14 days before the end (trial licences 3 days) and no longer for auto-renewing subscriptions. Check-in stays at 24 hours and is no longer adjustable in the interface.

0.38.3

  • Videos on cloudzh.app: A new product film (about 3:20) plays on the front page. It shows what sets CloudZH apart, the way from the order to your dashboard and the plans. Four short videos join it in the new «Videos» section and in the docs: get your licence, install CloudZH, first steps, manage your server. All play smoothly at 1440p and 60 frames per second.
  • Dashboard: The «Invitation ready» window no longer slides to the left with long links.
  • Tools: website/tools/films.py records every film frame by frame, films_publish.py puts them on the website and vertical/make_vertical.py builds the portrait version for phones.

0.38.2

  • Roadmap by quarter: cloudzh.app/roadmap/timeline shows what has shipped since the launch in Q4 2026 and what is planned for Q1 2027, Q2 2027 and H2 2027. Open it with “See the timeline” on the roadmap; the content lives in the timeline section of website/roadmap.json.

0.38.1

  • Public roadmap: cloudzh.app/roadmap shows what is being built right now, what comes next and what is planned for later, including giveaways on Discord and seasonal offers. Link in the website footer, content in website/roadmap.json.
  • Launch offer: 6 months are now 180 days; the licence pool suggests 180 days as well.

0.38.0

  • Licence pool: a new page in the licence portal holds codes in stock for giveaways and requests. Create codes in bulk (for example 20 trial licences for 6 months), see at a glance what is free, handed out, redeemed or expired, hand out the next free code to someone (with a ready-made message in English) and put unredeemed codes back into the pool.
  • Promotion pages: cloudzh.app/promotions/launch shows the launch offer with a live counter (“7 of 15 licences left”) and leads straight to the customer account, where the code is redeemed after signing in or registering. /promotions/ lists running offers, and the terms now live at /promotion-terms.
  • Trials only through codes: the self-started 14-day trial is switched off and its button in the dashboard is gone. Trial licences come through promotions and on request, still once per person and server. The website explains the new way.

0.37.0

  • Codes in batches: under licence portal → Trials & codes you can create up to 100 personal codes at once, each redeemable once and numbered (“X October #1” …). Add a note to each code right in the list (for example “sent to @name”), copy all codes or save them as CSV.
  • One free licence per person: when redeeming, variants of the same email address (name+x@…, Gmail with dots) count as the same person: one trial per person, and one free licence from codes per person, even across several accounts. Disposable and relay addresses (such as Apple Hide My Email or Firefox Relay) cannot redeem licence codes.
  • Website: short redeem links cloudzh.app/redeem/<code> open your customer account with the code. New page with the promotion terms (/promotions), and the privacy policy covers data from promotions.

0.36.0

  • Subscription in your account: under “My licences”, every licence with a subscription shows whether it renews automatically (with date and amount) or is cancelled and when it ends. Right there you can cancel at the end of the period, resume, change the payment method, upgrade to Pro or switch between monthly, yearly and household. Stripe prorates the remaining time, and the licence picks up the new plan right away; keys and servers stay the same. Cancelling and switching ask for your password.
  • Buy from the trial: under Profile → Subscription you can buy CloudZH during and after the trial (Standard or Pro, monthly, yearly or household). The trial licence becomes a paid licence: the server stays activated, apps and settings stay, and the licence email brings the key for more servers.
  • No more false alarm: subscriptions that renew automatically no longer report “Expiring soon”. Profile → Subscription and zh license status show the renewal. The trial only warns 3 days before it ends.
  • Reminder only when something ends: if a subscription is cancelled, an email with a link to resume arrives 7 days before it ends. The licence service checks subscriptions from before 0.36 with Stripe once.

0.35.0

  • Two plans: Standard and Pro. Standard ($5 a month or $50 a year) is the complete server with every app, all security features, backups and updates with rollback, and one dashboard account for you; you share Plex and Jellyfin with your family as usual. Pro ($8 or $80, as before) shares the server: accounts for family and friends, plus every extra. Household for up to 3 servers: $99 (Standard) or $149 (Pro) a year. Existing licences are Pro, and the trial has the Pro features.
  • Pro only: more accounts (friends, family, more admins), invite links and guest accounts that expire, off-site backup and backup download, automatic updates and app rollback, all notification channels with custom thresholds and quiet hours, activity and history, performance diagnosis, the AI assistant, custom apps, homelab and UniFi OS Server, your own branding (name, logo, colours, sign-in page, menu names) and priority support. Locked areas carry a “Pro” badge and lead straight to the upgrade. Security is never Pro.
  • Nothing gets lost: with Standard, existing accounts, channels, custom apps and settings stay; only new things are locked, and Pro features you set up pause until you switch to Pro. Fetching an off-site backup back always works.
  • Subscription: Profile → Subscription and zh license status show the plan. The licence portal issues licences with plan and household, switches the plan and shows monthly revenue per plan. A price change in Stripe is picked up automatically.
  • Buying in your account: Standard or Pro, monthly, yearly or household; the licence email names the plan.
  • Website: new pricing with Standard and Pro, a calmer header with a “More” menu, the language switch on the far right and a new menu on phones.

0.34.1

  • Self-healing without a click: System Health now fixes safe cases on its own, checked every 2 minutes: crashed apps, dashboard and proxy, important services, time sync, a full disk (unused Docker images only), an expiring certificate and a missing recycle bin in Sonarr, Radarr and Lidarr. A finding has to show up in two checks in a row before CloudZH steps in; during installs, updates and other tasks it waits.
  • Never automatic: apps you stopped by hand, hidden findings, Ubuntu packages, CloudZH updates, backups and app settings other than the recycle bin. If a repair doesn't help after 3 attempts (right away, after 5 and after 15 minutes), CloudZH gives up and reports the finding through your notifications, noting that the repair didn't help. The same applies when a finding comes back 3 times within 6 hours despite the repair (say, an app that keeps crashing). Services are only restarted from a fixed list (Docker, firewall, Fail2Ban, SSH, network, VPN), never rollback or package services.
  • View and switch: System Health shows a “Self-healing” section with a switch and the latest repairs; findings being worked on are marked “Being repaired automatically”. New rule under Operations → Notifications: “Self-healing fixed a problem automatically” (fixed problems go to your channels, fixed notices only to the bell). On the server: zh doctor --auto [on|off].

0.34.0

  • Certificates through 13 DNS providers or without DNS access: Besides Cloudflare, now also Hetzner, DigitalOcean, AWS Route 53, Porkbun, DuckDNS, deSEC, Netcup, IONOS, Namecheap, Infomaniak, Gandi and GoDaddy (wildcard certificate for all subdomains), or HTTP-01 with no DNS key at all (port 80 must be open). Choose during install (install.sh --ssl) or later with zh ssl provider; zh ssl status and zh ssl providers show the current state.
  • More systems: Ubuntu 22.04 to 26.04, Debian 12 and 13, Raspberry Pi and other ARM machines with a 64-bit system, Proxmox as a VM or LXC, and Windows 10/11 through WSL2 (beta, Install-CloudZH.ps1). The installer checks the system, processor and Python version up front and picks the matching agent. NAS (Synology, UGREEN, QNAP, TrueNAS, Unraid) through an Ubuntu VM; guide in docs/PLATFORMS.md.
  • Notifications: New page Operations → Notifications with Discord, Telegram, ntfy, Gotify, email and webhook. Rules for System Health, CPU, RAM, storage and temperature (limit and duration), backups, updates, licence and sign-ins, plus quiet hours and a bell in the dashboard with the latest messages. zh notify shows channels and messages, zh notify test sends a test.
  • Off-site and downloadable backups: After every run, encrypted backups are also sent to S3 storage (Cloudflare R2, Backblaze B2, Wasabi, AWS, Hetzner, Infomaniak or your own) or to a folder, such as an NFS share on a NAS, with their own retention. Unencrypted backups always stay local. Every backup can be downloaded in the browser after signing in again. zh backup offsite [status|now|test], zh backup key shows the private key for emergencies.
  • Updates with a way back: Before every update CloudZH saves a snapshot of the program, system files and database. If the new version does not start cleanly, CloudZH restores the previous one automatically and reports it. Manually: zh update rollback --list, zh update rollback. Automatic updates in a time window (zh update auto on 04:20, off by default). Apps: after an app update, “Previous version” in the app window restores the previous image and settings.
  • Free trial: 14 days with all features and no purchase, right under Profile → Subscription or with zh license trial. Once per server and hardware, with abuse protection.
  • Security: Alerts for sign-ins from a new device, repeated failed attempts and changes to two-factor, passkeys and admins. New area Security → Firewall & blocks: view and lift Fail2Ban bans, your own block list for addresses and networks, geo-blocking for the dashboard and Plex, UFW rules at a glance (zh firewall). Security → Credentials lists all app logins in one place; showing them requires password confirmation.
  • Release: Customer packages include the agent for Python 3.10 to 3.14 and for ARM; tools/release/build.py --pythons.
  • Website in six languages: cloudzh.app is now available in English, German, French, Spanish, Portuguese and Turkish (/de/, /fr/ …), with a language switch at the top right; on the first visit it follows the browser language. New at the top: “Sign in” (customer account on account.cloudzh.app) and “Buy”. No location details on the page any more. Translations in website/i18n/, check with python3 website/i18n.py missing de.

0.33.1

  • Installer in the customer portal: Under "My licences" there is now a "Download installer" button with version, size and SHA-256. Only accounts with a usable licence can download it, meaning active, about to expire or in the payment grace period. On the VPS, zh-vps installer-publish offers a package, only the customer edition with install.sh; from the PC use Deploy-CloudZHApp.ps1 -Action installer -File <zip|tar.gz>.
  • Licence emails: Purchase and code emails link to the installer in the customer portal and to the step-by-step guide instead of announcing a separate email.
  • Valid until: A date set in the license portal now lasts until 23:59:59 Swiss time. Before, it lasted until 23:59:59 UTC, so the following day was shown.
  • Extension codes now only apply to trial licences. Stripe renews subscriptions, and free days would be lost on cancellation.
  • Operations: docs/OPERATIONS.md now describes the installer workflow and monitoring with Uptime Kuma on the Lenovo.

0.33.0

  • Full code review across all parts: about 90 bugs fixed, each finding with a test. The most important ones:
  • A crafted request no longer crashes the license service or the customer portal.
  • In the customer portal, the account lock now also applies to re-confirmation and password changes, and internal support notes are no longer visible to customers.
  • The off-site backup no longer stays blocked until a restart after an early error.
  • Server and licence:
  • A clock that ran ahead no longer keeps the server in restricted mode for good.
  • zh ssh-port --finish, the firewall advice and the SSH port detection in the installer no longer lock the admin out.
  • Custom apps can no longer run as root, not even via user: 0. Links in the data or app folder that point to / or system folders are rejected; links to a second disk (e.g. /mnt) are still allowed.
  • CloudZH only reads config files in app folders when they are regular files and not links.
  • Dashboard:
  • A new admin with a start password no longer gets stuck when two-factor is required.
  • The AI assistant conversation no longer hangs after a restart.
  • The masking buttons in My account no longer break the media library.
  • The editor no longer loses text on a save conflict.
  • Several translation gaps are closed.
  • Docs:
  • New customer guide on the website ("Customer guide", 10 steps from account to running server).
  • Placeholders such as <server-ip> are explained.
  • For operations there are new docs/OPERATIONS.md and docs/PORTAL.md.
  • Product film: new frame-by-frame recording on a virtual clock (record_promo60.py), smooth at 1440p and 60 fps. First cut for Reddit (about 80 s); your own music can be added with --music.

0.32.2

  • Customer portal: grouped menu. The sidebar of account.cloudzh.app is now structured: “Overview” at the top, then “Licences” (My licences, Buy, Redeem code), “Account” (Invoices, Security) and “Help” (My requests, Discord). A counter next to “My requests” shows requests with a reply from us. On phones each group sits on its own row.
  • Licence email: “Valid until” shows the date in Swiss time, the same as the customer portal and the license portal (previously one day early for redemptions shortly after midnight). The copy of new tickets sent to support names category and priority in German.
  • License portal in English: “no expiry”, “30 days”, the category in the ticket header and status changes in the history are now translated.

0.32.1

  • Emails through Resend instead of Brevo (vendor only): Brevo adds a tracking pixel to every email and routes all links through its own addresses, including confirmation and password links; this cannot be turned off there. When a Resend key is set (zh-vps license-stripe), licence letters and all customer portal emails go through Resend without tracking and with unchanged links; Brevo stays as a fallback. No more “New sign-in” notice during the first hour after confirming an account.
  • Customer portal setup (vendor only): Deploy-CloudZHApp.ps1 -Action all now reliably runs zh-vps portal-setup first (Windows PowerShell 5.1 had broken the check). The license service no longer crashes when the portal socket is missing; it keeps running without the portal and says so. zh-vps portal-deploy and zh-vps portal-status check the sockets inside the container and no longer report a running portal as an error.

0.32.0

  • Customer portal account.cloudzh.app (vendor only): Customers sign up with their email and a bot check, set their password through the confirmation link and can turn on two-factor sign-in and passkeys. In the portal: manage licences and servers, create installation keys, redeem codes, buy a subscription (Stripe), view invoices and open support tickets, also without an account at https://account.cloudzh.app/support. Keys are always emailed by the license service; the portal never sees them. Setup: zh-vps portal-setup, zh-vps portal-turnstile, Deploy-CloudZHApp.ps1 -Action all.
  • License portal: German/English switch. New section “CloudZH.app” with tickets (replies, internal notes, canned replies), accounts (lock, reset two-factor, sign out) and a security log. New section “Marketing” for shareable, time-limited trial codes with a link and a redemption counter.
  • Friend licences: no expiry, licence key only (zh license activate, leave the installation key empty). Every activation is visible in the license portal and reported to Discord; suspend or revoke at any time. Trial licences are limited to one per account and one per machine.
  • Off-site backup: The license service and the customer portal back themselves up, encrypted, to Cloudflare R2 after every change (zh-vps backup-setup, zh-vps backup-verify, zh-vps backup-restore). The private key lives only in the password manager; a restore asks you to confirm the signing key ID.

0.31.0

  • Console in your language: The console windows for installs, updates, backups and repairs now show their messages in the dashboard language instead of always in German.
  • UniFi OS Server: inform host set automatically. CloudZH enters the server's cable address in the Network app, so UniFi devices report there and not to the Wi-Fi or a container address. Checked at every start and every 6 hours; show or change it with zh unifi inform [auto|off|<IPv4>].
  • System Health “Network connection”: Warns when the server uses Wi-Fi although a cable is connected.
  • Speed test: speed.cloudflare.com is now the default. Ookla is licensed for personal use only and is added only on request (zh diagkit ookla on).
  • License service (vendor only): Log entries older than 12 months and feedback older than 2 years are deleted automatically. Base image node:24-alpine pinned to version and digest.
  • Website: Legal texts revised after the preliminary legal check (withdrawal, warranty, liability, privacy with all recipients), “Cancel subscription” link in the footer.

0.30.0

  • Licences issued automatically after purchase (vendor only): The license service accepts Stripe events at https://license.cloudzh.app/v1/stripe/webhook (only with a valid Stripe signature). After a paid subscription it creates the customer, the licence and one installation key per server and sends the licence letter through Brevo to the address from checkout. Renewals, more or fewer servers, pauses and immediate cancellations are applied automatically too; unpaid invoices never extend a licence, only a paid invoice counts.
  • If sending fails, Stripe retries the event and the letter goes out with fresh keys. In the license portal: Stripe status, recent events, a test email and “Licence letter by email” per licence. The Stripe and Brevo keys can only be set with zh-vps license-stripe on the VPS (hidden input, separate socket), never from the dashboard; backup and move deliberately leave them out.

0.29.2

  • Command line: zh license-server status now also translates “socket present” and the line with licenses and servers.

0.29.1

  • License service runs on the VPS (https://license.cloudzh.app), move completed. Deploy-CloudZHApp.ps1 -Action license-setup also accepts the key without quotes. zh license-server move now shows two more messages translated.

0.29.0

  • License service on the VPS (provider only): sudo zh license-server move moves the license service to the VPS (https://license.cloudzh.app). Database, signing key, pepper and Discord webhook go through the admin interface (/export, /import); the service here stops only once the VPS answers with the same key ID. Customer servers notice nothing. Emergency: zh license-server move-back.
  • The license portal stays in the dashboard and reaches the VPS through its own SSH access (cloudzh-license-tunnel), limited there to a fixed bridge to the admin interface: no shell, no terminal, no forwarding. New: zh license-server tunnel-key, Deploy-CloudZHApp.ps1 -Action license-setup|license-deploy|license-status.
  • After the move, the encrypted backup fetches the license data from the VPS. New servers check in at https://license.cloudzh.app.

0.28.3

  • Support address support@cloudzh.app on the website, in the docs and in the legal texts (previously support@cloudzh.ch). Examples in the command line, ZH Menu and docs use example.com instead of a real domain.

0.28.2

  • Website on cloudzh.app: the product website is built for the new domain (website/build.py --base-url, default https://cloudzh.app) and runs on its own server. website/vps/ holds the Caddyfile, Compose, zh-vps (publish, roll back, status) and Deploy-CloudZHApp.ps1 to publish from the PC. www and demo redirect to cloudzh.app.
  • Documentation: the link in the help menu opens the docs on the website (https://cloudzh.app/#docs); the old path /docs/ redirects there.

0.28.1

  • License portal: the log now shows only the last four digits of the Discord webhook ID, no characters of the secret part. In the overview the extra lines of the tiles are no longer cut off (“0 open installation keys”).

0.28.0

  • UniFi OS Server: signing in with the UI account keeps working. UniFi OS requires a time service running in the container (NTP=yes) before signing in, but ships none. CloudZH adds a placeholder there (the clock comes from the server anyway) and checks it at every start of UniFi OS Server and every 6 hours, also after a UniFi OS Server update. Auto-update of UniFi OS Server can be turned back on.
  • System Health shows “UniFi OS Server: time check” under Versions with a fix button; zh unifi install and zh unifi update set it up right away, and so does a CloudZH update on servers with UniFi OS Server.

0.27.4

  • Clearer app installation: while pulling an image CloudZH shows one line “Layers downloaded: 3/7” instead of one line per layer; the intermediate states arrived mixed up and partly garbled in the terminal (“Extractingng”). Apps without a web interface (e.g. Recyclarr) no longer show an address after zh app <id> install.

0.27.3

  • Recyclarr installs again: Recyclarr no longer publishes a latest image, so the installation stopped with “not found”. The catalog now uses ghcr.io/recyclarr/recyclarr:8 (all feature and bug fix releases of version 8, major upgrades only on purpose). CloudZH's configuration (configs/cloudzh.yml) fits version 8. All 41 catalog images checked against their registry (tools/check_images.py).
  • Installer in English: “Website rebuilt”, “UFW active …”, “Automatic security updates active” and 17 more messages translated; errors such as “docker failed: …” are translated even with a long message. The “Synchronizing state of docker.service …” line on every update is gone.

0.27.2

  • More complete English command line: lines with long paths stayed German (e.g. “Radarr: Papierkorb /data/media/.recycle/movies vorhanden”) because paths counted as text. Also 46 missing texts translated, including “(until …)” and “Check in now” in zh license, zh website and input checks.

0.27.1

  • Change the SSH port safely: sudo zh ssh-port 2608 switches sshd, ssh.socket (IPv4 and IPv6), the firewall rules (same source as for the old port) and Fail2Ban in one go. First both ports listen; after a confirmed test in a new window the old one is closed (--finish does that later). If anything fails, everything is reverted; backup in /var/backups/cloudzh/. Recommended port 2608 (“ZH”), CloudZH never assigns it to apps.
  • Yes/no with one letter: prompts show “(y/n) [y]” in English, “(j/n)” in German and so on. One letter is enough, the full word still works.

0.27.0

  • Activity (new in the sidebar, administrators only), three tabs:
  • Live: who is watching on Plex right now (poster, episode, progress, device, Direct Play/Direct Stream/Transcoded, resolution, Home/Remote, bandwidth) and who is online in the dashboard, with device.
  • People: every account with status, devices, last action and actions of the last 24 hours; below that the Plex statistics per person from Tautulli (last seen, last watched, plays, total time).
  • History: dashboard history with filters by person and type (Media library, Apps, Sign-in, Users, System) and Plex history from Tautulli.
  • “Now playing” widget on the Overview. Existing layouts get it once below “Needs attention”; anyone who removes it does not get it back.
  • Tautulli: the dashboard reads activity, history and statistics through the Tautulli API. The key stays on the server; posters go through the dashboard, only images from the latest query, without IP addresses. After a newly generated key, the dashboard fetches it by itself.
  • Widgets only when needed: Downloads, “Now playing”, “Needs attention” and Activity disappear while they are empty and reappear as soon as something is going on. The neighbour in the same row takes over the freed width, empty rows close up. While customizing, all stay visible (dimmed with a note), and each widget can be switched to “Always show”. Empty notes are hidden outside of customizing.
  • Update channels: Stable (branch main), Experimental and Dev. Choose under Settings → Updates or with zh update channel. Dev only on the provider's server. Switching back to an older channel does not downgrade; CloudZH waits until the channel catches up (zh update --force downgrades deliberately). The version badge shows a non-Stable channel.
  • Help and feedback (speech bubble in the top right): Discord community, “Request a feature”, “Report a bug” (with optional diagnostics without addresses, names or keys), “Give feedback”, documentation and release notes. Submissions go signed through the license service to the provider's Discord channel, at most 10 per server and day, only from active licenses. Mentions and Markdown are defused. zh support; for the provider zh support webhook (hidden input, address only in the license service).
  • Customer edition: tools/release/build.py builds a release package without the license service, license portal, website, tests and project notes; web code bundled, minified and obfuscated, agent as bytecode or compiled (Cython), checksums for every file, optionally a watermark per license. The “CloudZH Release” workflow builds it manually on Ubuntu 24.04. Docs: docs/RELEASING.md.
  • Faster and leaner: queries pause in a background tab and catch up once on return; docker ps is cached for 2 seconds (sidebar, live channel and apps each made their own call until now); the app list polls less often when the live channel is available; in LAN mode Caddy now compresses (previously about 1.1 MB uncompressed on first load).
  • Bugs fixed: clicking quickly between pages could draw an older page over the new one and keep its queries running. After signing in with a second factor, earlier typos still counted towards the account lockout. “As of 5 min..” with a double dot. Note text fields were only one line high. Short translation patterns such as “{0} on {1}” produced half-translated sentences.
  • Layout reviewed (all pages, phone to desktop, light and dark, several languages): the header fits the width on phones (Light/Dark and Mask move to the profile menu there), menus in the top right no longer cut off on the left, Security in a single column on tablets and phones, rows in System Health and Performance wrap, number and unit stay together, Backups table more compact, Users table on tablets without the Permissions column, widgets with more content fade out softly at the bottom, better contrast for grey text in light mode and for “Shut down server” in dark mode.
  • Cleaned up: removed 8 unused Python functions, the old banner module, an unused endpoint (/api/files/stat), 18 unused CSS rules and duplicate routines (System Health).
  • Tests: tests/activity-test.mjs, tests/support-test.mjs, tests/test_release.py, channels in tests/test_update.py, grid in tests/grid-test.mjs; the test setup can run against the bundled customer package (CZH_TEST_WEB).

0.26.2

  • Product film on cloudzh.ch (about 4½ minutes, 1080p): a tour of every area with info banners, chapter cards and original music, recorded in the English live demo. Plays in the video section and in the film lightbox, with chapters from the recording. Tools: website/tools/record_promo.py, promo_overlay.js, promo_music.py, promo_cut.py.
  • Live demo: logo and sign-in page image can be uploaded under Appearance (kept only in the browser tab; like on the server only PNG, JPEG and WebP).
  • Added the missing translation of “Time-of-day greeting” under Appearance → Labels.
  • Start screen in other languages too: while the translation was loading, the whole page stayed invisible, including the start screen, so with an English interface the animation was often skipped. Now only the content is hidden and the start screen always plays.

0.26.1

  • Your own website on the main domain (zh website): Caddy serves a static website directly at https://<domain>, www.<domain> redirects. zh website build builds the product website from the update source (website/build.py), zh website deploy <dir> publishes a finished folder, on/off switches it, rollback brings back the previous version, status also checks whether the DNS records already point to the server. Without a website the main domain redirects to the dashboard as before.
  • Security: static files only, mounted read-only (/opt/cloudzh/site → /srv/site), switching is an atomic swap of a link, links and special files are left out when publishing, its own Content Security Policy without external sources, hidden files blocked, its own 404 page. Turning it on and off only as root on the server. After an update install.sh rebuilds an enabled website; if that fails, the previous one stays online.
  • zh disk now works: the command from 0.24 was not registered in the zh wrapper and reported "Unknown command".
  • Website cloudzh.ch: "Make it yours" section with seven looks to click through, files and drives, comparison, three steps to get started, film lightbox, new docs pages "Customizing" and "What's new", screenshots and tour on 0.26. Tests: tests/test_website.py.

0.26.0

  • exFAT disks could not be mounted (“The kernel does not support exFAT”). Cause: the agent runs hardened (ProtectKernelModules) and cannot see the folder with the kernel modules, so the pre-check thought the driver was missing. CloudZH now asks modinfo outside the sandbox and only reports a missing driver when it is definitely missing. Also for XFS, Btrfs and NTFS.
  • Format disks under Files → Drives: ext4 (recommended, only on this server) or exFAT (also readable on Windows and Mac), new partition table with one partition, then mounted automatically. With password confirmation and the disk name as a second confirmation, live console. Disks without a file system now also appear under Drives and can be set up that way.
  • Security after an independent review: only clearly identified disks (no clones, no different disk with the same identifier), right before every write another check of size, serial number and kernel sequence number (/dev/disk/by-diskseq), never a disk holding data, app data or the system, never a disk from /etc/fstab, /etc/crypttab or foreign mount units, all RAID members excluded, only one format operation at a time, other actions on the disk are refused meanwhile. exFAT names at most 11 characters.
  • Tests: driver detection, empty disks, formatting (order, GPT, permissions, mounting), clones, a swapped disk aborts before writing.

0.25.1

  • Longer splash screen. After the monogram, the “CloudZH” wordmark slides open, the ZH adds a final accent, and the progress bar appears below. The sequence takes about 2.8 seconds and always plays in full, even when the server answers sooner. With a custom name or custom logo only the monogram is shown (remembered in the browser as czh-splash-word). With “reduce motion” the splash screen disappears immediately.

0.25.0

  • Profile pictures. Every account can have its own picture: click the picture under Account (camera icon) or “Upload”. Administrators change or remove other users' pictures in the user panel (click the picture in the top left). Without a picture, the initials remain.
  • Cropping in the browser: choose an image or drag it in, move the crop (mouse, finger, arrow keys) and zoom (slider, mouse wheel, + and −), preview in three sizes.
  • A 256×256 image is saved as WebP (Safari: JPEG). Re-encoding removes EXIF data such as the location.
  • Shown in the top right, in the profile menu, in the sidebar, in the user list and in the user panel.
  • Security: the server only accepts PNG, JPEG and WebP (file signature checked, no SVG), at most 300 KB and 1024×1024 pixels. Served only to the account itself and to administrators, with Content-Security-Policy: sandbox and nosniff. Pictures are stored in the database (avatars) and are deleted with the account; every change is recorded in the audit log.
  • New: web/src/avatars.js, PUT/DELETE /api/account/avatar, PUT/DELETE /api/users/:id/avatar, GET /api/avatars/:id. Texts in six languages, demo with pictures kept in memory.
  • Tests: tests/avatar-test.mjs (signatures, dimensions, SVG/HTML, sizes), api-test (permissions, delivery, audit).

0.24.0

  • External disks in the file manager. Files now has three tabs: Internal (Data, App data, Home, System), External (mounted USB disks) and Drives (manage disks). A connected disk that is not mounted yet is shown as a number on the “Drives” tab.
  • Drives: every detected disk as a card with file system, size, connection, model and usage. Buttons *Mount*, *Unmount*, *Safely remove* (finishes writing, unmounts and powers the disk off), *Open files*, settings (name in the file manager, *mount automatically*, *read only*) and *Forget* for disks that are no longer connected. The page notices plugging in and unplugging by itself (every 8 s, only while it is visible).
  • Supported: exFAT, FAT32, NTFS, ext4, ext3, ext2, XFS, Btrfs. Disks are mounted under /mnt/cloudzh/<name>, always with nosuid,nodev,noexec. exFAT, FAT32 and NTFS belong to the app user (files 664, folders 775) so the file manager and apps can write; on Linux file systems the permissions on the disk apply, an empty new disk is taken over by CloudZH itself, otherwise via *Take over permissions*.
  • Mount automatically (on by default): when plugged in and after a server restart. If you unmount it by hand, it stays unmounted until it is unplugged and plugged in again. A different disk with the same identifier is never mounted automatically.
  • Copy and move between Data and external disks: with cut/copy and paste across the tabs or via *Copy to “Disk”* in the context menu. Permissions of the destination, no links; when moving, only what has arrived is deleted from the source. Clear messages for names that exFAT/NTFS do not allow and for files over 4 GB on FAT32.
  • zh disk (list with numbers), zh disk mount|unmount|eject <nummer|name>.
  • Hardening after an independent review: cloned system disks (same UUID as /) can never be mounted; before and after mounting CloudZH checks that the checked device is really the one mounted; disks listed in /etc/fstab or mounted under /mnt/... count as system disks; “Take over permissions” only on its own mounted disk and never beyond its file system; known disks remember serial number and PARTUUID; label and model without control characters; moving without data loss on upper/lower case collisions and skipped items; at most 128 levels when copying; “read only” does not replay a journal on ext3/4 and XFS; settings are only saved once remounting has worked.
  • Tests: tests/test_extdisks.py (detection, system disks, clones, mounting via simulated systemd, wrong device, unmounting while in use, watcher, settings, copying and moving between locations, collisions, depth), dashboard routes in tests/files-terminal-test.mjs. Demo with two simulated USB disks.

0.23.0

  • Loading animations. Opening the dashboard shows a splash screen: the ZH monogram builds itself (the H grows from the bottom and the top, the Z draws itself in the accent color), then breathes calmly above a slim progress bar until the page is ready. If the server has not answered after 6 seconds, “Connecting to the server …” appears below. The splash stays for at least about 0.75 seconds so the logo never disappears halfway through drawing.
  • Page changes: a thin bar in the accent color runs along the top edge until the page has loaded. If it takes longer than 140 ms, a page skeleton with shimmering placeholders appears instead of an empty area; afterwards the header, panels and widgets fade in one after another. Reloading the same page after an action stays calm (only the bar).
  • Steps in between: panels, dialogs, files, terminal, System Health, indexer search, quality profiles and the restart notice show one consistent loader: the Z of the monogram draws itself, holds briefly and dissolves again. Lists that are still loading (downloads, activity, indexers) show placeholder lines instead of “Loading …”. The small spinner in buttons is smoother and adapts to the button color.
  • The accent color is remembered in the browser (czh-accent) so the splash screen appears in your own color even before the appearance settings load (hex color values only, anything else is ignored). Without JavaScript, noscript.css hides the splash screen. With “reduce motion” enabled in the operating system no animations run, the logo and content appear immediately.
  • New in app.js: loader(), skel(), skelPage() (also available to files.js and terminal.js), all without inline CSS (the CSP stays at style-src 'self').

0.22.1

  • Release notes in your language. The modal behind the version in the top right shows what's new and the changelog in the selected language (German, English, Spanish, French, Portuguese, Turkish). The whole changelog is translated under changelog/CHANGELOG.<sprache>.md. If a version is missing in a language, it appears in German with a notice.
  • GET /api/changelog?lang=<sprache>; install.sh puts all languages into the dashboard image.
  • Test: tests/changelog-test.mjs checks that every translation contains the same versions, the same number of bullets and unchanged code.

0.22.0

  • Overview as a modular widget grid. Every user arranges their own overview: click “Customize” in the top right, then drag widgets, resize them using the bottom-right corner, and remove them with ×. The grid has 12 columns, widgets snap into place, gaps close automatically, and while dragging a placeholder shows where the widget will land. Neighbours in the same row move aside. Nothing is saved until you click “Done”; “Cancel” discards your changes.
  • Add widget: a two-step dialog, first the type (Notices, System, Storage, Apps, Media, Custom content), then the item. New: every installed app as its own tile (status, Open, details), notes with your own text, compact usage and free space, media library, welcome text. CPU, memory, network and uptime are now separate widgets.
  • Default per role: in customize mode, administrators can also set the default for administrators and for friends (friends as a preview with your own data). Anyone who hasn't customized sees the default; “Reset to default” deletes your own layout. Without a saved default, a built-in default applies; for administrators it is derived from the previous setting Appearance → Structure → Overview (after the update everything looks the same as before).
  • Friends: their start page is now the same grid and can be customized the same way. They are only offered what they have permissions for; administrator widgets are not available to them.
  • Keyboard control (Tab, arrow keys, with Shift to resize) and screen reader announcements. Narrow windows and phones: widgets in the same order in two or one column(s); adding and removing works there too. While you customize, the live channel does not redraw the page.
  • Appearance → Structure → Overview: instead of order and metrics, a “Customize overview” button.
  • New: web/public/grid.js (grid, no third-party packages), web/src/layout.js, GET/PUT/DELETE /api/layout. Texts in all six languages.
  • Tests: tests/grid-test.mjs (moving, inserting in a row, resizing, free spot, 2000 random moves without overlap), tests/layout-test.mjs (validation, permissions, default per role, reset, deleting an account).

0.21.0

  • Mask sensitive entries. IP addresses (IPv4, IPv6, networks with /24 etc.) and MAC addresses are blurred everywhere in the dashboard: sidebar, overview, server, VPN, users, devices, audit log, logs, consoles, System Health, dialogs. One click (or Enter) reveals the address, a second click hides it again; identical addresses on the page are revealed together. In links, rows and cards, the first click only reveals and does nothing else.
  • Eye button in the top right: show all addresses or mask them again (applies until the tab is closed), also via search (Ctrl K).
  • Selectable per browser under Account → Appearance: IP, MAC, email (email is off initially). Turning everything off hides the button.
  • Not masked: loopback (127.x, ::1), 0.0.0.0, netmasks, public DNS resolvers (1.1.1.1, 8.8.8.8, 9.9.9.9 …), version numbers and times. Input fields, editor and terminal are unchanged.
  • The address stays in the document (copy buttons, search and translation keep working). The mask protects against prying eyes and screenshots, not against someone with access to the browser.
  • Version in the top right. A small red badge with the installed version (administrators only). After an update it pulses with “New” until the release notes have been opened once. Clicking it opens the release notes of the installed version, with the full changelog below to expand. New route GET /api/changelog (administrators only, because the changelog describes hardening in detail); install.sh adds CHANGELOG.md to the dashboard image.
  • Tests: tests/mask-test.mjs (30 checks: IPv4, IPv6, networks, ports, MAC, email, exceptions such as versions, times, loopback).

0.20.0

  • License portal from home: home network detection rebuilt and robust. Cause of the block even when accessing from home: your own public address came only from a DNS lookup. If it failed, the known address was cleared for a minute, and the same happened right after every dashboard restart (i.e. after every update). As a result, the portal sometimes loaded and then blocked you on the next page.
  • Three sources: DNS of the dashboard name, the address the server itself uses to reach the internet (Cloudflare trace, fallback ipify, never through a proxy), and for IPv6 the /64 of the home network interfaces (there is no NAT with IPv6). Automatic only when the server is at home behind a router (private IPv4, default route not via a VPN).
  • When a source reports a new address, the old one is dropped immediately. If a source doesn't respond, its last confirmed value stays valid (for at most 14 days). Stored in web-data/homeip.json and /etc/cloudzh/homenet.json, so it's available right after a restart.
  • For administrators, an unknown public sender is looked up once immediately instead of being blocked (throttled: at most every 15 s, every 10 minutes per address, at sign-in only after password or passkey).
  • New: zh homenet (what is detected), zh homenet add|remove <adresse|netz> (on the server only, at most /24 or /56, with a warning if the address doesn't match the server), zh homenet auto on|off, zh license-server remote on|off (portal also from outside, still administrators with 2FA only).
  • When access is blocked, every page of the license portal shows the detected address, the known own addresses (only after the second factor) and a “Check again” button.
  • System Health: hide notices. Every problem, notice or info item has a button to hide it: “until something changes” (comes back if the finding gets worse or its title changes), 7 or 30 days. Hidden items don't count towards the status, the sidebar, the live channel, the AI assistant and “Fix problems”, and are listed under the “Hidden” filter with a “Show again” button. Applies to all administrators and devices (dashboard database), every change is recorded in the audit log. zh doctor still shows everything.
  • Hardening after an independent review: networks are validated when loading and applying (no crash on broken entries), Cloudflare IPv6 and NAT64/6to4/Teredo are never treated as your own connection, cloudzh.env rejects values containing line breaks, “Fix problems” without a selection repairs nothing instead of everything (agent: an empty list means nothing), hidden notices only with the durations offered in the dashboard, IDs without prototype matches.
  • Tests: tests/homeip-test.mjs (IPv6 networks, new address replaces old one, outages, throttling, manual list, broken file), tests/test_homenet.py (interfaces, VPN, VPS, manual list, last value), tests/health-dismiss-test.mjs.

0.19.2

  • Command line in your language: zh, the ZH Menu, the installer, zh update and the SSH greeting speak the same language as the dashboard. When an administrator picks a language in the dashboard, the command line adopts it for the Linux user with the same name and as the default for everyone without their own choice. In the ZH Menu (key L) it can be changed per user. Without a choice, the system language applies, otherwise English.
  • Translation uses the same dictionaries as the dashboard (English, Spanish, French, Portuguese, Turkish); around 250 command-line texts were newly translated. Columns, tables and borders stay aligned, colors are preserved. Output from app operations (e.g. “Connect apps”) is translated as well.
  • Yes/no questions in your own language: “Jetzt aktualisieren? (ja/nein) [ja]” in German, “(yes/no) [yes]” in English, “(oui/non)”, “(sí/no)”, “(sim/não)”, “(evet/hayır)”. The words of the language and their first letter are accepted, plus always ja/j/yes/y.
  • zh on its own clears the console (like clear, without sudo). The ZH Menu opens with zh menu.
  • Tests: language selection (own choice, default from the dashboard, system), yes/no in several languages, translation of lines with colors and columns.

0.19.1

  • Fix “Prowlarr: download client not added (HTTP 400)” when connecting the apps: when saving, Prowlarr checks whether the category exists in SABnzbd and rejects it otherwise (even with forceSave, which only skips warnings). CloudZH now first creates the prowlarr category in SABnzbd (folder /data/usenet/complete/prowlarr, separate from movies and series) and then adds SABnzbd to Prowlarr; if creating the category fails, it is added without a category.
  • Rejected entries in Prowlarr now show the app's reason in the console.
  • Test: the simulated Prowlarr rejects unknown SABnzbd categories just like the real one.

0.19.0

  • Apps connect themselves as far as possible. After every installation (in any order) and via the “Connect apps” button under Apps or zh apps wire, CloudZH adds missing connections between the apps. Anything already set up or deliberately turned off stays unchanged.
  • Tautulli: connected to Plex (address, server ID, name, its own token), no setup wizard.
  • Seerr: fully set up: the admin is the server's Plex account, Plex with all libraries, Sonarr and Radarr as default (profile “CloudZH”, root folder), Tautulli, address and language. Friends sign in with their Plex account.
  • Maintainerr: Plex, Sonarr, Radarr, Tautulli and Seerr.
  • Bazarr: Sonarr and Radarr, language profile “German + English” as default (language taken from the Plex libraries), subtitle providers that need no account (Gestdown, YIFY, TVsubtitles, SubtitleCat).
  • Lingarr: initial setup without its own login (sign-in via the dashboard), Radarr, Sonarr, English → German.
  • UmlautAdaptarr: Sonarr and Lidarr (the project doesn't support Radarr yet), in Prowlarr the HTTP proxy with tag umlautadaptarr.
  • LazyLibrarian: SABnzbd (new categories books and audiobooks), folders, API and Prowlarr (indexers are synced).
  • Kometa, SuggestArr: Plex (and Seerr) added, only the free TMDb key is missing. Sonobarr: Lidarr key. Requestrr: Sonarr and Radarr, only the Discord token is missing.
  • Prowlarr: SABnzbd as download client (for “Download” in the indexer search).
  • Separate Plex token per app: apps never get the token from the server's Preferences.xml (Tautulli warns against this, and plex.tv would otherwise register the app's version on the server). CloudZH registers a separate device per app with the Plex account (“CloudZH Tautulli”, “CloudZH Seerr” …), visible and removable in Plex under “Authorized Devices”.
  • Hardening after an independent review: values from Plex and other apps are validated before they end up in a configuration (server ID, version, tokens, API keys with a fixed character set); INI values containing line breaks are rejected; files in the app folder are read without following symlinks, non-blocking (FIFO) and only up to 1 MB; atomic_write sets permissions and owner via the descriptor instead of the name; agent requests no longer follow redirects; error messages containing keys don't end up in the log; files are only written while the app is stopped, and not at all if the Docker state is unclear.
  • App notes in the App Store say what happens automatically and what is still missing. The button is now called “Connect apps” and appears as soon as two of the involved apps are installed.
  • Tests: tests/test_connect.py (all connections against simulated apps, Plex and plex.tv; a second run changes nothing; your own settings are kept; symlinks, FIFO, line breaks, redirects).

0.18.3

  • License portal: the owner license no longer appears under “To do” as “License without customer” (it doesn't need a customer); the “without customer” filter and the counter now match.
  • License portal: logo in the top left like in the dashboard (ZH monogram in the accent color) instead of the old Z symbol.

0.18.2

  • Downloads show the actual message: instead of “Problem, see Sonarr/Radarr”, the Downloads tile and Media library → Downloads now show the messages from the Radarr and Sonarr queue, translated into plain sentences (e.g. “The release name does not match the title (found by ID only). Manual import required.”, incomplete release, missing write permissions, download folder not found). Unknown messages appear in the original.
  • “Import” button (administrators only) for downloads that have finished but are waiting for a manual import. Typical case: German releases with a German title that Radarr only found via the IMDb or TMDb ID. A preview shows the file, size and quality; nothing is imported until you confirm. CloudZH fetches the candidates from Radarr/Sonarr itself (no paths from the browser) and only imports files that belong to the same title, have no permanent rejection (e.g. sample) and are not an unwanted quality (disc image, remux, cam recording). Audit entry media.import.
  • Recycle bin in Radarr, Sonarr and Lidarr: “Connect media apps” sets one up if none is configured (/data/media/.recycle/movies, tv, music, emptied after 7 days). Without a recycle bin, the apps permanently delete a replaced file immediately, for example a good MKV when switching to a worse release. Your own recycle bin stays unchanged.
  • System Health, new “Media library” section: missing recycle bin (fix via button, repair media-wire), movies as disc images (ISO/BR-DISK, Plex doesn't play them) and titles that don't use the profile of the “CloudZH” quality preset. The last two checks run in the dashboard, because only it knows the quality preset (zh doctor only shows the recycle bin).
  • Fix fallback quality: releases with BR-DISK, remux, cam recordings etc. were offered as “other quality” because Radarr only rejected them due to the profile. They now count as “rejected for another reason” (friends can't download them).
  • Independent review by a second agent, findings fixed: for movies only the largest matching file (otherwise each import replaces the previous one), never files without a title match, season packs in Sonarr can only be imported once (lock per download ID, button only on the first entry), lock released before the check and after errors, the media-wire repair only reports success if the recycle bin is actually set afterwards, live updates take the media library checks into account.
  • Tests: tests/test-arr.mjs (messages, import preview and import against simulated Radarr, disc images in the fallback quality, media library checks), tests/test_setup.py (recycle bin, health check, repair), tests/security-test.mjs (friends may not import). Live demo with a pending import and a recycle bin notice.

0.18.1

  • Home network detection via your own domain (Hairpin NAT) now also works with VPN: the public address of your connection is looked up with public DNS servers (Cloudflare, Quad9, Google). Previously the dashboard asked the server's DNS, which answers the CloudZH names for VPN devices from /etc/hosts with 10.8.0.1; your own address stayed “unknown” and the license portal blocked you even at home. If nothing is found, CloudZH tries again after a minute.

0.18.0

  • Performance diagnosis under Operations → Performance (and zh perf): measures for a few seconds the CPU (programs, system, waiting on disks), kernel pressure values (PSI), memory and swap, the load on each disk, network and ping to the router and to the internet, plus CPU, reads and writes per container (cgroup v2) and the processes causing load. From this it determines the bottleneck (CPU, disk, memory, internet line, home network) with findings and concrete measures. “Live” measures again every 10 seconds. Detects a saturated line (bufferbloat, compared with the speed test), Hairpin NAT (the dashboard address points to the public IP in the home network, with a hosts entry as a fix) and measurements taken without load.
  • “Relieve SABnzbd” via button (Performance or zh perf --fix): at most 30 connections per main server (backup servers with priority are kept), direct unpack off, pause downloading during post-processing, verify and unpack with nice/ionice, optional speed limit based on the last speed test (90 %), CPU weight 256. Fixed values only, password confirmation, audit.
  • CPU weight in the catalog (cpu_shares): SABnzbd 256, Tdarr 128. Existing installations get it the next time the agent starts, without restarting the app (docker update, persisted in compose.yml). New SABnzbd installations start with gentle settings. Note: older CloudZH versions don't know cpu_shares; after rolling back to a version before 0.18, remove the entry in /opt/cloudzh/apps/sabnzbd/compose.yml (and tdarr).
  • System Health reports bottlenecks lasting more than 5 minutes (CPU, disk, memory) and SABnzbd settings that put load on the server, each with an “Open performance” button. Deliberately no automatic repair: “Relieve SABnzbd” changes user settings and restarts SABnzbd.
  • “Server commands” under Operations: restart and shut down immediately, in 5/15/30/60 minutes or tonight at 04:00, cancel a scheduled action; warns about running operations (installation, update, backup). Shutting down requires typing the server name. After a restart, the page waits and reloads itself. Maintenance via button: restart all running apps (manually stopped ones stay off), dashboard and proxy, failed services, clean up Docker, truncate logs, proxy/certificate, time. Plus all zh commands with search and copy. Ubuntu security updates point to the button in System Health.
  • Command line and ZH Menu: zh perf [--live|--fix], zh reboot [--in <min>] [--cancel|--status], zh poweroff [--in <min>]; in the ZH Menu: performance diagnosis, live performance, relieve SABnzbd, schedule restart, cancel and shut down.
  • Overview: links “Performance diagnosis” (CPU) and “Server commands” (uptime). AI assistant with a new read tool “Measure performance”. Texts in six languages.
  • Security: sabnzbd.ini is read without following symlinks or FIFOs and with a size limit, and written via rename (the app folder belongs to the container). The Hairpin finding is passed to the AI assistant without domain and IP. zh reboot falls back to systemd if the agent doesn't respond, and asks for confirmation when operations are running (--force).
  • Tests: tests/test_perf.py (parser, evaluation, plan and changes to sabnzbd.ini, CPU weight, parameter validation for restart), API tests for permissions and password confirmation.

0.17.1

  • License portal, diagnostics for “only from the home network or via the VPN”: the block page now shows the browser's detected address and the address CloudZH knows from DNS as your own connection. This makes it immediately clear why a request counts as “outside” (e.g. mobile data instead of Wi-Fi, or the dashboard name in DNS doesn't point to your own connection).

0.17.0

  • TRaSH Guides recommendations: after installing Radarr, Sonarr or SABnzbd, CloudZH applies once: naming for Plex (TMDb or TVDB ID), renaming, video analysis, “Propers and Repacks” via custom formats, import and re-searching on failure. In SABnzbd: block dangerous file types (abort job), propagation delay 5 min, .nzb backup, direct unpack off, pause during post-processing, low CPU and disk priority, sorting off. For existing installations: the “TRaSH recommendations” button under Apps or zh apps tune.
  • Quality → “TRaSH Guides”: a third mode alongside the CloudZH preset and your own profile. Profiles 1080p, 4K, Remux 1080p, Remux 4K, original language, “Prefer German” (German profiles) or “German only”. For this, CloudZH controls Recyclarr (its own file configs/cloudzh.yml, sync immediately and then daily); custom formats and scores come from the TRaSH Guides. If the sync fails, the previous state is kept.
  • Note on “German only” in the CloudZH preset: the profile language also rejects movies whose language is detected incorrectly; better use “TRaSH Guides” with “Prefer German”.
  • Catalog: notes added for Radarr, Sonarr, SABnzbd and Recyclarr.
  • Independent review by a second agent (symlinks, YAML, keys in the log, API fields checked against the source code of Radarr, Sonarr and SABnzbd): no critical findings. Fixed: old state of the Recyclarr file on errors, waiting for SABnzbd after a fresh installation, double management with your own recyclarr.yml, limited output, unknown fields from older app versions.
  • Tests: tests/test_trash.py (simulated Radarr, Sonarr and SABnzbd, Recyclarr file, symlinks, fallback), tests/test-arr.mjs extended with TRaSH mode; live demo with Recyclarr and button.

0.16.2

  • New signing key for the license service (f0494603c2800b4e). The previous key b40b4adbdbb3ac39 was exposed and is no longer accepted; license files signed with it are invalid. After the update, zh license refresh (or the next daily check-in) fetches a new license file.

0.16.1

  • zh license-server rotate-key: new signing key for the license service, e.g. if the old one was exposed. The old one is archived; customers, licenses and activations are kept.
  • zh license-server export-secrets: signing key and pepper as text for your password manager (the pepper is binary, cat only showed gibberish).
  • A new license takes over the server if its previous license was revoked or has expired. Previously, activation reported “still active with another license” until the vendor released the server manually.
  • Tests: key rotation on the running license service, export, takeover after revocation.

0.16.0

  • Files (Server → Files): file manager directly in the dashboard, no FileBrowser container. Locations: Data (/srv/data), App data (only the folders that belong to the apps), the Linux user's home and System (/, read-only). List and tile view, sorting, multi-select (click, Ctrl, Shift), context menu, keyboard shortcuts (arrows, Enter, Backspace, Del, F2, Ctrl+A/C/X/V, Ctrl+F, Alt+←/→), editable path bar, preview pane, search in the folder and below (also with * and ?).
  • Upload files and entire folders via button or drag and drop, in 8 MB chunks with progress, speed, time remaining, cancel and retry; large files are no problem. On name conflicts: keep both, replace or skip (also “for all”). Download individually or as a ZIP (folders, multi-select), with resume, and preview for images, videos and audio.
  • Copy, cut, paste, move by dragging (Ctrl = copy), rename, new folder and new file, trash per location (30 days, restore to the original location), delete permanently, create ZIP, extract ZIP and TAR, editor for text files (line numbers, Ctrl+S, detection of external changes), properties with folder size and permissions editor, repair permissions (owner cloudzh, missing group permissions, e.g. for “Permission denied” in Sonarr or Radarr), “Open in terminal”.
  • Security: each location operates with the permissions of its Linux user (the agent switches filesystem identity per access), paths are opened step by step without following symlinks, archives are checked against Zip Slip, previews are never rendered as HTML. Administrators only, audit log; permanent deletion, changing permissions and emptying the trash require password confirmation. zh files off disables the file manager server-wide.
  • Terminal (Server → Terminal): a real shell in the browser (xterm.js, bundled locally) as your Linux user; sudo asks for the Linux password just like over SSH. Multiple sessions as tabs; sessions keep running when you switch pages or reload and show their history when you return. Search in the history, font size, full screen, copy with Ctrl+Shift+C, clickable links, extra keys (Esc, Tab, Ctrl, arrows) on phones. Colors matching the dashboard, light and dark.
  • Terminal security: administrators with a second factor only, new sessions only after password confirmation, by default only from the home network or VPN, connection via WebSocket with a one-time ticket and origin check. Each session is its own systemd unit (cloudzh-term-…), disconnected sessions end after 30 minutes, signing out ends your own sessions. New: zh terminal status|on|off|remote on|off|user <name>|close-all.
  • “Install security updates” button in System Health (under “Updates and patches” and on the finding, password confirmation, live console). It runs unattended-upgrade just like Ubuntu does at night: only packages from the security channel, packages with configuration prompts are skipped, nothing is removed, no automatic restart, Docker and apps stay unchanged. Runs as its own systemd unit outside the agent's sandbox so kernel or sudo updates don't get stuck half-installed, and keeps running even if the dashboard reloads. Beforehand, CloudZH checks that package management is clean and that there is enough free space. zh doctor --fix --apt uses the same settings.
  • Folders that the file manager creates or copies keep the SGID bit inherited from the parent folder (umask per thread instead of chmod; the agent's sandbox forbids chmod with SGID). The file manager doesn't change the permissions of an SGID folder.
  • Independent security review by a second agent, findings fixed: Home in the file manager now follows the terminal's rules (2FA, home network/VPN only, writing with password, disappears with zh terminal off), root's supplementary groups are dropped on identity switch, at most 12 concurrent file streams. “Install security updates” button: the settings “no restart, remove nothing” now reliably apply, even if /etc/apt/apt.conf.d asks for something else (its own main file, which apt reads last).
  • The installer remembers the Linux user who installed CloudZH (TERMINAL_USER) for Terminal, Home and System. Older installations automatically use the user from the cloudzh group.
  • Live demo with Files (sandbox file system) and Terminal (sandbox shell), translations in all six languages. Tests: tests/test_files.py (file manager with real identity switching, symlinks, Zip Slip, upload, terminal) and tests/files-terminal-test.mjs (real agent and dashboard: upload, download with range, ZIP, WebSocket ticket, origin, permissions).

0.15.5

  • Home network detected when accessing via your own domain (Hairpin NAT): if you open app.<domain> at home, many routers (e.g. Swisscom Internet-Box) route you back via the public address of your connection. CloudZH treated such requests as “from outside”, so the license portal and the “Administration only from home network or VPN” rule blocked you even at home. Your own public address now counts as the home network. It comes from the DNS of the dashboard name (never from the request); Cloudflare proxy, private and shared addresses (CGNAT) are not adopted. As a result, guests on the guest Wi-Fi of the same router also count as home network; sign-in, second factor and password confirmation still apply.
  • Test: tests/homeip-test.mjs.

0.15.4

  • zh update: the “Jetzt aktualisieren?” prompt only accepted exactly “ja”; “j” aborted the update without a message. Now ja, j, yes and y (upper or lower case) are accepted, and an abort is reported.

0.15.3

  • License check enabled: the signing key of the license service licenses.cloudzh.ch (key ID b40b4adbdbb3ac39) is now included. From this version on, every server needs an activation (zh license activate or My account → Subscription), otherwise restricted mode applies. Running apps are never affected.

0.15.2

  • Preview under Appearance: the logo was too large for the narrow sidebar of the preview and overlapped the content. Monogram and wordmark are now smaller there, and the sidebar is slightly wider.

0.15.1

  • Fix Plex installation “Operation not permitted: 'media'”: the setup wizard created media folders with the SGID bit (mode 2775). The agent unit runs with RestrictSUIDSGID=yes; its seccomp filter rejects every mkdir with the SGID bit with EPERM, even if the folder already exists. Affected were Plex (library folders) and “Connect media apps” (root folders). New folders are now created with 775 and inherit the SGID bit from the parent folder; the unit's hardening stays unchanged.
  • A regression test simulates the seccomp filter and verifies that the agent never sets SUID/SGID bits.

0.15.0

  • Licensing: CloudZH can check a license (off as long as no signing key is configured). License key CZL-XXXXX-XXXXX-XXXXX-XXXXX (90 bits of randomness, check character against typos) plus an installation key CZI-XXXXX-XXXXX-XXXXX per server, usable only once. The license service stores keys only as HMAC. Details: docs/LICENSING.md.
  • Signed license file: each server has its own key pair, checks in daily (signed) and receives a license file signed with Ed25519. Copies on other servers are invalid.
  • Restricted mode instead of shutdown: without a valid license, updates, new apps and new users are blocked; Plex, apps, VPN, backups and sign-in keep working. Payment grace period of 7 days; without contact to the license service, 14 days of normal operation.
  • Subscription page under My account: status, term, Activate, Check now, Release server. Banner for the payment grace period, missing contact and restricted mode. Command line zh license, installer with --license and --install-key.
  • License portal (vendor only, zh license-server enable): customers, issue licenses, extend (+1 month/+1 year), change subscription type and seats, assign, transfer, unassign, pause, revoke, reissue keys, create and withdraw installation keys, release servers, goodwill extensions, flags (hardware change, possible copy), monthly revenue, immutable log, license letter for download. Only for administrators with a passkey or two-factor, only from the home network or VPN, changes require password confirmation.
  • System Health checks the license and the license service; backups include the license data (encrypted only).
  • Detect copies: if two fingerprints of the same activation alternate, only one server keeps the license and the copy runs in restricted mode. Many check-ins per day are flagged. In the portal: “Confirm” (hardware change) or “Lift” (suspicion).
  • Restricted mode also applies to invitation links (creating and redeeming, without revealing license details to guests). Updates of app images and restoring backups remain deliberately allowed.
  • Hardening after an independent review: requests bound to their purpose, timestamps stored only after success, a clock turned back has no effect, “expired” takes precedence over “offline”, broken license files don't unlock updates, older license files don't overwrite newer ones, rate limit with fixed time windows and a cap across all addresses, converting an owner license sets the seats to the active servers. Best pass keys to the installer at the prompt or via the environment.

0.14.0

  • Live updates without reloading: the dashboard keeps a connection to the server open (Server-Sent Events, /api/events). When something changes, the open page quietly redraws itself: new or stopped apps, finished installations, findings in System Health, an available update, new users and invitations, downloads and new titles in the media library, changed appearance. Scroll position, tabs, search and filters are preserved. This also applies to changes from another tab, from your phone or via zh on the command line.
  • Nothing gets lost: while a dialog is open, something is being typed or text is selected, the page waits. With unsaved input (e.g. under Rules or Settings) it doesn't redraw at all but shows “Show new data” at the top. The tab that triggers a change doesn't receive it twice.
  • Operations from other devices: if someone starts an installation, an update or a repair on another device, the operation appears in the console bar at the bottom right.
  • Sessions take effect immediately: signing out in one tab, “Sign out all devices”, deactivation or changed permissions take effect in all open windows immediately (sign-in or new navigation), not only on the next click.
  • New version without polling: after an update the dashboard restarts, the browser reconnects by itself and detects the new version immediately. The reload is “soft”: the page, scroll position and an open app detail are kept, followed briefly by “CloudZH has been updated”.
  • Live dot next to the page title: green = live, grey = disconnected. Without a connection, the previous polling continues as before. Hidden tabs disconnect after 30 seconds and catch up on everything when you return.
  • Security: the channel only reports topics (“apps”, “users” …), never content or secrets; the page fetches the data through the usual permission-checked interfaces. Friends only receive topics they are allowed to see. At most 8 connections per account and 200 in total; sessions are checked every 30 seconds without extending them. A shared watcher queries the agent once for all windows and only runs while someone is connected. Cache-Control: no-transform so that Caddy (encode zstd gzip) doesn't buffer the stream.
  • Tests: tests/events-test.mjs (39 checks: sign-in, role filter, own tab, watchers for apps and operations, changes from another process, permission change, session end, heartbeat, limits).

0.13.3

  • Fixed failed motd-news.service: CloudZH hides the Ubuntu news in the SSH greeting by removing the execute permission from 50-motd-news. However, the Ubuntu timer still started motd-news.service twice a day, the service failed every time and System Health reported “1 service failed”. The installer now also disables the timer and resets the failed state.
  • Not every failed service is a malfunction: System Health distinguishes important services (CloudZH, Docker, SSH, firewall, Fail2Ban, VPN, UniFi OS Server, network, time) from other Ubuntu services. Only important ones count as a problem and turn the server card red; others appear as a notice (“Does not affect CloudZH or the apps.”), and the repair button remains.
  • Translations: “1 Dienst mit Fehler”, “1 Sicherheitsupdate offen” and similar singular texts stayed in German or were assembled incorrectly (“servicee”); they are now complete sentences. “Vor 10 Std 27 Min.” (last backup) is translated. For patterns of equal length, the more specific one wins.

0.13.2

  • No more “failed service” after every update: zh update exited with exit code 1 under the update service despite succeeding (last line [ -t 1 ] && …), systemd set cloudzh-update.service to “failed” and System Health asked for a repair. The update now exits cleanly with 0. As a safeguard, the agent resets such a failed state itself if the log shows a successful update (at startup, when querying the log and in System Health). The first update to this version still runs with the old zh; the safeguard catches that.
  • The page reloads itself after an update: every response carries a build ID (X-CZH-Build, GET /api/version), scripts and styles are loaded with ?v=<Build>. When the browser detects a new version, it reloads as soon as no dialog is open and nothing is being typed. No more Ctrl+F5 needed. After an update, the dashboard and proxy are only recreated if their image has changed.
  • New console window: after successful completion the console stays open for 60 seconds (countdown on “Close”, “Keep open” stops it); on errors it stays open. Minimizing turns it into a tab in a bar at the bottom right, one click brings it back. Multiple operations run independently side by side, and confirmation dialogs no longer close a console. Running operations reappear in the bar after reloading the page, including a running update. After an update, the console counts down 60 seconds until reloading (“Reload now” or “Later”).
  • Full code review, fixed bugs include:
  • Dashboard: crafted addresses, a broken cookie or JSON null crashed the process or returned error 500 on every page. The login lockout could be bypassed with parallel requests. New administrators and deactivation require password confirmation. The account lockout only counts failed attempts from outside; in the home network the lockout applies per address. Welcome text for friends only after sign-in.
  • Proxy: apps no longer get to see the dashboard's session cookie; Caddy authenticates itself to the dashboard with a secret key (/etc/cloudzh/proxy.env, generated during the update); containers in the Docker network no longer count as home network.
  • Interface: pages attached new event handlers on every visit (filters in System Health, double saving under Appearance), confirmations couldn't be triggered again after an error, Escape left dialogs hanging, duplicate messages when copying and after installations, command palette on the process page.
  • Translations: “Löschen …” was translated as “Deleting …” (now “Delete …”), “Suche …” the other way round as “Search …” (now “Searching …”), uptime sentence in all languages, numerous texts that had stayed in German (titles, episodes, process dialog, priority …).
  • Agent and zh: zh app unifi-os … found no command, repairs with && in the ZH Menu aborted, apt waits for a lock instead of aborting, the LAN IP is no longer cleared during a brief network outage, the installer no longer hangs forever without output, the agent is replaced atomically during an update, zh update detects failed updates and offers them again, help extended.
  • Tests: tests/server-test.mjs, tests/e2e-run.mjs, tests/test_caddy.py, tests/test_update.py; pytest tests runs again.

0.13.1

  • New logo: a monogram of Z and H (the Z stands in front of the H, the diagonal crosses the crossbar) as logo and favicon, plus the wordmark “CloudZH” in Outfit as the branding logo. Replaces the previous Z symbol in the sidebar, at sign-in, in the preview under Appearance and on the project page.
  • Red = accent color: the Z and “ZH” always use the accent color set under Appearance, also in dark mode. The favicon is generated from the accent color. Sidebar in the accent color: logo in white. A custom logo or custom name under Appearance still takes precedence.
  • Logo files (SVG and PNG, light, dark, monochrome) with instructions under docs/brand/, README with the logo in the header.
  • Wordmark in the sidebar, at sign-in and on the project page as tall as the monogram. On hover the logo no longer changes color; it only gets slightly lighter.

0.13.0

  • User management rebuilt: metrics (accounts, active in the last 7 days, without second factor, needs attention), search by name, email and note, filters (administrators, friends, attention, without 2FA) and multi-select for sign-out, require password change, deactivate, activate and delete. Tabs Users, Invitations, Activity and Rules.
  • Change usernames: administrators can rename any account, with a live “available” check while typing. Sessions, passkeys and permissions are kept. The old name is blocked for other accounts for 30 days, as is the name of a deleted account. System names such as root, admin or cli are reserved. Friends can rename themselves under My account (can be turned off, adjustable waiting period, default 7 days). Command line: zh rename-user <alt> <neu>.
  • Invitation links: friends choose their own username and password, no initial password needed anymore. Per link: permissions, apps, validity (1 to 30 days), number of accounts (1 to 20) and account lifetime. The link is shown only once, only its hash is stored. Revocable at any time; links of an administrator who is demoted, deactivated or deleted expire automatically.
  • Detail view per user: profile (username, display name, email, internal note, expiry date), permissions with templates (“View only”, “View and request”, “Everything for friends”), security (reset password, require password change, lift lockout after failed attempts, 2FA status with passkeys, sign out devices individually) and activity history.
  • Expiry date for guest accounts: after it, sign-in is no longer possible; the account remains. zh enable-user <name> re-enables deactivated or expired accounts in an emergency.
  • My account: manage your own display name and email; the display name appears in the greeting and the profile menu.
  • Security: renaming and role changes require a fresh password confirmation. When checking names, friends only see “not available” (no conclusions about previous names), with a limit per account. Control and bidi characters are removed from display names. The protection of the last administrator also holds with simultaneous requests. New tests in tests/users-test.mjs (77 checks).

0.12.0

  • AI assistant: next to the language selector in the top right, a lifebuoy button. It opens a panel in which an assistant investigates problems on its own: it checks System Health, apps, logs, storage and downloads, names the cause and suggests a solution as a card (“Run” or “Skip”). The action only runs after you click, and the assistant then verifies the result. Longer operations show the familiar console. Answers come in the dashboard's language.
  • Your own key, free choice of provider: Anthropic (Claude, suggested Haiku 4.5), OpenAI, Google Gemini, OpenRouter or your own endpoint in the home network (Ollama, LM Studio). “Test connection” fetches the available models. The provider bills the costs directly; CloudZH shows the usage and limits messages per day and month. Not a premium feature.
  • Ask button on findings in System Health and under “Needs attention” opens the assistant with the finding as the question.
  • Deliberately restricted: the AI can only use fixed tools (reading without confirmation, acting only after a click, repairs with password). No shell, no files, no configuration or secrets, no user, security, VPN, update or license settings. It only knows the user documentation, not the security concept or internals. CloudZH itself answers questions about vulnerabilities or workarounds with a refusal. Secrets are removed before sending, and the key is stored encrypted on the server. “Explain only” mode turns off all actions. Details in docs/SECURITY.md.
  • zh ai status|on|off|forget-key: the server owner can lock the assistant; the dashboard then can't turn it back on.
  • Live demo with a simulated assistant (walkthrough: question, check steps, suggestion, repair, verification).
  • Tests: tests/ai-test.mjs (flow with a simulated AI in Anthropic and OpenAI format, limits, reauth, lock, no secrets at the provider, in the log or in the database), tests/test-sanitize.mjs, tests/test_docs.py.

0.11.3

  • Real app logos instead of two letters: in the App Store, in the Homelab tab, for installed apps, in the overview, in the app detail, in search (Ctrl K) and in the installation windows. 79 logos for all 41 apps in the App Store and 38 of 39 apps in the Homelab tab (OpenWISP doesn't have a free logo yet).
  • Logos are stored locally in the dashboard (WebP, around 0.6 MB in total); nothing is loaded from outside. Where a logo has its own variant for dark interfaces, it switches with the theme; logos without enough contrast get a matching tile in the respective mode.
  • Custom apps still show two letters, even if their id matches a catalog app.
  • Sources: dashboard-icons (Apache-2.0) and selfh.st/icons (CC BY 4.0), maintained with tools/icons/fetch.py, attribution in tools/icons/NOTICE.md.

0.11.2

  • Overview ordered by importance: what needs attention is at the top, followed further down by what you look at less often. New order: Needs attention → Apps and downloads → Metrics (CPU, memory, network, uptime) → Storage and activity. Previously the metrics were always at the very top.
  • New “Needs attention” block: collects apps with a malfunction or stopped apps, missing second factor, CloudZH update as well as problems and notices from System Health in one place, malfunctions first, each with a matching button (Open, Update, System Health). If nothing is pending, it only shows a narrow green “All good” line. Replaces the previous notice about system updates.
  • Apps list: apps with problems are at the top; at most 8 are shown, the rest via “Show more apps”.
  • Appearance → Structure → Overview: instead of two columns, a single order from top to bottom (move, hide, show again). Half-width blocks sit side by side in pairs, on phones stacked in the same order. Saved settings from 0.11.1 are carried over, hidden blocks stay hidden.

0.11.1

  • New “Homelab” tab under Apps (next to Installed and App Store): around 40 more apps for servers and home networks, selected from awesome-selfhosted, awesome-homelab and selfh.st/apps. Grouped into Network & devices (including TP-Link Omada, UniFi Network Application, Grandstream, OpenWISP, NetAlertX, UpSnap), Cameras & smart home (Frigate, Home Assistant, Zigbee2MQTT, evcc), Monitoring & alerts, Remote access, Media add-ons, Files, Everyday & friends and Local AI. Each card shows load, requirements (host network, USB stick, graphics, own ports), notes and a link to the project page; recommendations can be filtered, search works as in the App Store.
  • “Not self-hostable” section: UniFi Protect/Access/Talk, cloud-only management (Aruba Instant On, Zyxel Nebula, Netgear Insight, Meraki) and VM-only appliances.
  • If an app is available as a verified template in the App Store (same id), it disappears from the Homelab tab; the apps added in 0.10.0 (Immich, Paperless-ngx, Vaultwarden, Kometa, Tracearr …) therefore don't appear there. List in web/public/homelab.json, all texts in six languages.

0.11.0

  • Setup wizard during installation: the installation dialog now asks for everything needed up front. Apps describe their form in app.yml (block setup); the procedures behind it are built into the agent.
  • Connect Plex with one click: “Connect with Plex” opens the official Plex sign-in (PIN flow as with Seerr and Tautulli). CloudZH then connects the new server to the account itself and sets up the server name, libraries (movies, series, optionally music, selectable paths), metadata language, home network and its own connection via the subdomain. No token to type, no claim code to copy. The account token stays only in the dashboard's memory.
  • SABnzbd: enter Usenet server, port, SSL, user, password and connections directly during installation.
  • Media apps connect themselves: after installing Sonarr, Radarr, Lidarr, Prowlarr or SABnzbd, CloudZH creates the root folders, adds SABnzbd as download client and connects Prowlarr with Sonarr, Radarr and Lidarr, in any order. For existing installations: the “Connect media apps” button under Apps or zh apps wire.
  • Fixed: the Plex notice showed plex.DEINE-DOMAIN instead of the real domain, and notices with an inserted server IP stayed in German in other languages.

0.10.0

  • App Store with 41 apps: 17 new apps, selected from the community-scripts.org catalog and implemented as our own Docker templates (no third-party install scripts).
  • Movies, series & music: UmlautAdaptarr (German releases with umlauts), Profilarr (quality profiles), Lingarr (translate subtitles), Sonobarr (music discovery for Lidarr)
  • Requests & friends: SuggestArr (suggestions from watch history to Seerr), Guardian (allowed devices per friend in Plex)
  • Books & audiobooks: ReadMeABook (audiobook requests all the way to Audiobookshelf)
  • Maintenance & statistics: Tracearr (streams, history, shared accounts), Kometa (Plex collections), Tdarr (space-saving transcoding)
  • New category Personal cloud: Immich (photos from your phone), Paperless-ngx (documents), Syncthing (folder sync), Vaultwarden (password manager)
  • System & monitoring: ntfy (push to your phone, locked without an account), Backrest (encrypted backups with restic)
  • Media server: Feishin (music player in the browser for Navidrome)
  • Random passwords per installation: new placeholders {{SECRET}} and {{PASSWORD}} for database and initial passwords, plus {{URL}} (the app's address) and {{LAN_IP}}. The dashboard shows initial passwords and admin tokens on the app.
  • Initial files and data folders for catalog apps: files copies an initial configuration into the app folder once (e.g. Kometa, UmlautAdaptarr), data_dirs creates folders in the data folder and assigns them to the cloudzh user (e.g. photos, documents, sync, transcode). Existing files are never overwritten.
  • Initial setup via xml_set can now also set nested entries (e.g. gui/address).
  • Deliberately not included yet: DNS filters such as AdGuard Home (need port 53 and an adjustment to systemd-resolved), Calibre-Web (Kavita covers reading), LibreSpeed (OpenSpeedTest is available).

0.9.3

  • Media library with tabs: “Downloaded”, “Missing”, “Downloads” and, for administrators, “Indexers”. The counters are shown directly in the tab.
  • Missing: a list of all movies without a file and series with missing episodes (per season), with the note “Not released yet”, “Downloading” or “Not monitored”. Two buttons per title:
  • Search immediately triggers a search across all indexers in Radarr or Sonarr and then shows whether something was found and the download is running.
  • Availability queries all indexers and shows what's out there: matching releases (“Download best”), releases in a different quality and rejected ones with the reason (wrong language, size, blocked …). For series, per season.
  • Suggesting a different quality: if the search finds nothing in the configured quality, CloudZH suggests the available qualities (e.g. “720p · 3 releases · 2.1 – 4.4 GB → Download in 720p”), closest first. The preset stays; with upgrades, Radarr later replaces the file with the desired quality. Friends with the “add” permission may download matching releases and other qualities; releases rejected for other reasons only administrators.
  • Search all missing (admin) starts the search for all missing, monitored titles.
  • Quality preset (“Quality” button in the media library, admin): resolution (720p, 1080p, 4K, 720p to 1080p, 1080p to 4K, any), language for movies (any, original, German only, English only) and upgrades, separately for movies and series. For this, CloudZH creates the “CloudZH” profile in Radarr and Sonarr and uses it for all new titles, including requests from friends. Cam recordings, disc images, remux and Raw-HD are never included. Alternatively, an existing profile (e.g. from Recyclarr). Optionally apply it to all existing titles. Previously, CloudZH simply took the first profile (usually “Any”).
  • Indexers (Prowlarr): list with status (ready, blocked until, test failed), queries, grabs, errors and response time, enable and disable, “Test all”. Plus a search engine across all indexers (category all, movies, series); “Download” sends a release via Prowlarr to its download client. Keys and download links stay on the server. For this, Prowlarr is also detected on existing installations.
  • Downloads additionally show quality, indexer and the error message from Sonarr/Radarr.
  • New entries in the audit log: media.search, media.grab, media.quality, indexer.toggle, indexer.grab.
  • Test tests/test-arr.mjs (mock Radarr and Prowlarr): profile setup, search, fallback quality, permissions, no keys in the browser.

0.9.2

  • Translation gaps closed: greeting (“Good morning”), CPU line (cores, threads), network and Wi-Fi line, temperatures, activities (“added: …”), services (“up 23 d · starts automatically”), passkeys (“last used …”), update status, media library text for friends and other texts now appear in all five foreign languages. Lines with “ · ” are translated part by part instead of a short pattern swallowing the whole line.
  • Outside German, the keyboard shortcut in the sidebar is called “Ctrl K”.
  • “Speicher” is now translated as “Storage” (storage view, System Health, friends card, instead of “Memory”). In return, the memory column for services and processes is called “RAM”.
  • Live demo: language files are also found in a subfolder, demo texts (sign-in, welcome for friends, notice bar) match the language, storage view from 0.9.1 with simulated disks.
  • README as project page updated to 0.9.x: languages, new header, storage view, SSH greeting, zh info, zh storage, English screenshots, demo tour with language switching.

0.9.1

  • Storage on the overview: per file system (system, data) a colored bar broken down into movies, series, music, books, audiobooks, podcasts, downloads, apps (settings), Docker (images), backups and system, plus the free space. Below it, all disks with type (NVMe, SSD, HDD, USB), model, size, temperature and mount points. The agent calculates folder sizes in the background with low priority (every 30 minutes, “Recalculate” button).
  • zh storage shows the same on the command line, and zh status has a “Storage” section with the breakdown. In the ZH Menu under Overview → Storage.
  • Friends only see the usage and breakdown of the data storage, no devices or paths.

0.9.0

  • Dashboard in six languages: English, Español, Deutsch, Français, Português (Brasil), Türkçe. Switch in the top right via the language code (e.g. “EN”), also on the sign-in page. Without a saved choice, the browser language applies, otherwise English; the browser remembers your choice. Messages from the server, System Health and the security check are translated too (around 2000 texts in web/public/i18n/, tools in tools/i18n/).
  • New header in the top right: “Update” (only when a new version is available, starts the update), account, light/dark, divider, language.
  • Search in the sidebar below the CloudZH lettering (Ctrl K still works).
  • Flush sidebar: no more margin around the page, the sidebar background and divider reach all the way to the bottom even on long pages, logo, search and menu items are aligned.
  • Compact SSH greeting as default: compact lettering with a profile on the right, everything within 80 characters. The large logo is available with MOTD_STYLE=wide.
  • Uptime units adapt to the language.

0.8.3

  • SSH greeting tidied up, in UniFi style: notice box, CloudZH lettering with a profile on the right (product, version, host, IP, dashboard, uptime, time synchronization), status with colored dots (agent, dashboard, proxy, apps, VPN, UniFi), bars for CPU, RAM and data, followed only by notices that require action (Ubuntu updates, firmware, restart, new Ubuntu version, stopped apps). The remaining Ubuntu messages (system information, ESM advertising, duplicate firmware, release upgrade) are hidden. Narrow view with MOTD_STYLE=compact in /etc/cloudzh/cloudzh.env.
  • Colored command line for all users: prompt ▌benutzer@cloudzh:~$ (root in red with #), red error code after failed commands, colors for ls, grep, ip, diff and man pages. Turn off per user: touch ~/.cloudzh-noprompt.
  • zh info like info on UniFi devices: model, version, hostname, IP and MAC address, dashboard, uptime, time synchronization and status. Also in the ZH Menu under Overview.

0.8.2

  • SABnzbd reachable via the subdomain: SABnzbd rejected requests via sabnzbd.cloudzh.ch with “External internet access denied” because the proxy passes on the public IP. CloudZH now sets inet_exposure = 4 (access is protected by the dashboard's admin sign-in). Existing installations are adjusted automatically when the agent starts (the app is briefly stopped and started again).
  • System Health: “1 problem” instead of “1 problems”. The counters (problems, notices, OK) are clickable and filter the list below; plus a filter bar (All, Problems, Notices, Info, OK).
  • Apps: the app name and a new “Open” button lead directly to the app's web interface.
  • Export logs: app logs as a .log file (with the active search filter), audit log as CSV for Excel. The audit table no longer wraps action and IP.
  • zh doctor and the ZH Menu now also use singular and plural correctly.

0.8.1

  • Project page and live demo for GitHub Pages (site/): English product page and the real dashboard with simulated data (site/demo/mock-api.js). The demo's App Store comes directly from catalog/, screenshots are generated by site/tools/screenshots.py. Published automatically via GitHub Actions on every push to main.
  • New README in English with screenshots, quick start, commands and architecture.
  • Folders with English names: systemd/, fail2ban/ and motd/ are now under system/. Documents are called docs/ARCHITECTURE.md, docs/SECURITY.md and docs/CUSTOM-APPS.md, the project log is at docs/PROJECT_LOG.md. The installer cleans up the old document names under /opt/cloudzh/docs.
  • Dashboard: optional base path (only for the demo in a subfolder, unchanged in production).

0.8.0

  • ZH Menu back in the two-column design (zh menu): sections on the left, actions on the right, colored status header with bars, description and matching command below. All functions from 0.6 and 0.7 are included: System Health with “Fix all problems” and “Fix single problem”, install app (with subdomain), update, edit configuration, uninstall, manage system service, end process, htop, speed test. A “Health” dot in the status header shows the status.
  • Six languages in the ZH Menu: English (default), Español, Deutsch, Français, Português, Türkçe. Choose with the L key or under System → Language, saved per user in /etc/cloudzh/zh-menu.json. Command output (zh status, zh doctor) stays in German for now.
  • Diagnostic kit included by default: the installer sets up mtr, iperf3, dig, smartctl, sensors, ethtool, iw, htop, ncdu and the Ookla Speedtest CLI (checksum pinned). New command zh diagkit (status) and zh diagkit install (complete). Its own “Diagnostic kit” section in the ZH Menu: speed test, history, ping and traceroute, DNS lookup, network adapters, disk health (SMART), sensors, disk usage, iperf3 server. System Health reports an incomplete kit.
  • Sidebar tidied up: only 9 main items in three groups (Server, Administration, Account); groups can be collapsed (the state is saved, the group of the open page always stays open). Related pages are tabs at the top of the page: Apps (Installed, App Store), Operations (Services & functions, Backups, Logs), Settings (General, Appearance), My account (Profile, Sign-in & passkeys, Devices & sessions, Subscription).
  • zh no longer needs a preceding sudo (it obtains the permissions itself), and the menu shows commands without sudo accordingly.

0.7.0

  • System Health (dashboard under Administration, ZH Menu item 2, sudo zh doctor): continuously checks CloudZH (dashboard, proxy, updates, last update), apps (status, unexpected crashes, restart loops), failed system services, time synchronization, Ubuntu updates and security patches, pending restart, kernel, disk space and inodes, old Docker images, journal size, load, memory, out-of-memory (OOM), temperature, DNS, internet, certificate, Docker and Compose version, UniFi version and backups.
  • Self-healing via button or sudo zh doctor --fix: only predefined, safe repairs (restart dashboard/proxy, start crashed apps, restart failed services, enable time sync, delete unused Docker images, truncate journal, reload proxy, create backup). Ubuntu security updates only on the command line: sudo zh doctor --fix --apt.
  • Speed test with history: prefers the official Ookla Speedtest CLI (sudo zh speedtest install, checksum pinned, license for private use only), otherwise speed.cloudflare.com. Server, provider and link to the result at Ookla.
  • The server card takes System Health into account (red for problems, orange for notices).
  • Fixed: the “Security score” tile was distorted. Notices that require action are orange everywhere.
  • ZH Menu: “Updates and backups” merged, with speed test and Ookla installation there.

0.6.0

  • ZH Menu (sudo zh menu) in the style of HP switch menus: title bar, numbered menus with submenus, tables with an action bar (“Aktionen-> Zurück Starten Stoppen …”, a letter runs the action directly), description of the selected entry and key help at the bottom. Sections: status and counters, manage apps (start, stop, restart, update, logs, edit configuration, uninstall), App Store (install, details), users, security and VPN (add and remove VPN devices), UniFi OS Server, backups, updates, system (all system services, processes, logs, command line, restart). The CloudZH lettering in the main menu.
  • Greeting on SSH sign-in: CloudZH lettering with version, dashboard address, IP and connection type, agent, apps, uptime and storage. Ubuntu advertising and help text are off.
  • New commands: zh store, zh app <id> install|remove|update|edit|logs, zh service <name> start|stop|restart|status|logs.
  • Services & functions in the dashboard with tabs: overview, all system services (start, stop, restart, log, filter, search) and processes (live, by CPU or memory, mapped to app or service, terminate or force). Protected services (SSH, network, systemd) can't be controlled; firewall, Fail2Ban, Docker and agent can only be restarted. Every action requires the password and is recorded in the audit log.
  • Account as its own section on the left: profile, sign-in & passkeys, devices & sessions, subscription (coming soon). Settings now only contain server topics, Security only server security.
  • Colored server card in the bottom left: green online, orange when something needs doing (update, stopped app, missing second factor), red for malfunctions, each with a notice and a click to the matching page. IP highlighted, uptime in color, connection shown as “Wi-Fi” or “LAN” instead of the interface name.

0.5.2

  • Profile menu in the top right: clicking the avatar and name opens the menu with Manage account, Change password, Two-factor and passkeys, Subscription (coming soon) and Sign out. At the top it shows whether the second factor is active. Operable with mouse and keyboard (arrow keys, Esc); on phones only the avatar.

0.5.1

  • Settings: two-factor and passkeys show the actual status (“Active”, number of passkeys) instead of “Scheduled” and lead directly to Security → Sign-in.
  • Headers of the settings tiles are back at the top (no empty space next to tall neighbouring tiles).
  • During an update, the installer no longer waits 10 seconds for a setup token.

0.5.0

  • Menu on the command line: sudo zh without a command opens a full-screen menu with a status header (CPU, RAM, data, uptime, services), nine sections, a description and the matching command for each action. Operated with arrow keys or mouse, confirmation for sensitive actions, selection lists for apps, users and VPN devices, logs in the pager.
  • Colored output in zh, in the installer and for UniFi/VPN, with the same meaning as in the dashboard: steps blue, commands orange, success green, warning yellow, error red.
  • New commands: zh status (redesigned), zh check (security check), zh services, zh apps, zh app <id> start|stop|restart, zh logs update.
  • Configurable password policy under Security → Access rules: minimum length (10 to 64), upper and lower case letters, digit, special character, allow or forbid the username. Default: 10 characters with all four character types, username allowed. While you type, the dashboard shows live which rules are met.
  • Initial passwords for friends always contain all character types.
  • zh update check no longer shows log markers in the terminal; Docker states in German.
  • The VPN setup installs qrencode so that zh vpn add shows the QR code directly in the terminal.

0.4.0

  • Security as its own section:
  • Security check with a score and traffic light: SSH, firewall, open ports, Fail2Ban, certificate, updates, Docker, backups, VPN, 2FA for admins. Each item with a concrete measure (command to copy or button).
  • Two-factor sign-in with an authenticator app (QR code), 10 recovery codes, protection against code reuse.
  • Passkeys (fingerprint, face recognition, security key) for signing in without a password, in domain mode.
  • WireGuard VPN: set up with sudo zh vpn install, add devices in the dashboard and connect via QR code, either home network only or all traffic.
  • Access rules: “Administration only from home network or VPN” and “Second factor required for administrators”. Emergency: sudo zh security-reset, sudo zh reset-2fa <name>.
  • Appearance: accent color (palette or custom), light/dark default, sidebar, corners, density, heading font, rename and hide menu items, arrange overview tiles, logo and sign-in page image, names and texts, date format. With live preview.
  • Services & functions: system services with status, uptime, memory and autostart, plus the most important functions at a glance.
  • App Store: new categories “Network & VPN” (UniFi OS Server, WireGuard VPN, OpenSpeedTest) and “System & monitoring”; Lidarr under “Movies, series & music”.
  • Console with colors by meaning (steps, commands, downloads, extracting, success, warnings, errors) and highlighted paths, addresses and versions.
  • The name in the top left leads to the overview. Texts reviewed (singular/plural, spelling, consistent terms).
  • Independent security review, all findings fixed (details in docs/SECURITY.md): passkey as a real second factor, lockouts per account instead of global, X-Forwarded-For only from Caddy, limit on open passkey requests, user verification required, update log moved to /var/log/cloudzh-update, DNS in the VPN.
  • The dashboard container's health check uses the configured port.

0.3.0

  • Updates from the Git repository: once sudo zh update setup (repo, branch, read token), then sudo zh update via SSH or the “Update now” button under Settings → Updates (with password confirmation and live console). The overview shows “Update available”.
  • The button only starts the permanently installed cloudzh-update.service; the server defines the repo and command, not the dashboard.

0.2.1

  • Bug fixed: when updating from 0.1, the dashboard stayed on the old port 8080 while Caddy looked for it on 8780 (HTTP 502). The installer now starts docker compose in a clean environment.
  • General installation guide (docs/INSTALLATION.md) without personal data, example settings under config/, app overview docs/APPS.md.

0.2.0

  • “Catalog” is now called App Store: categories, search and filters, installed apps with “Manage”.
  • New apps: Seerr, Maintainerr, Wizarr, Notifiarr, LazyLibrarian, Kavita, UniFi OS Server.
  • Live console for installing, updating and removing.
  • Overview with CPU model, clock speed, load per thread, RAM with cache and swap, network with totals and Wi-Fi signal, disk read and write rates, temperatures and uptime in days, hours, minutes and seconds.
  • UniFi OS Server as a native app: sudo zh unifi install|update|remove|status (official Ubiquiti program, version and SHA-256 directly from Ubiquiti).
  • Dashboard moved internally from port 8080 to 8780 so the UniFi devices can use port 8080.
  • sudo zh cloudflare-token; the installer verifies the Cloudflare token directly with Cloudflare.
  • media/books folder for e-books.

0.1.0

  • First version: dashboard, agent, catalog with 15 apps, users and permissions for friends, media library, encrypted backups, Caddy with wildcard certificate, Fail2Ban, UFW.