Skip to content

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

Unreleased

Highlights: Apache Solr runs on Debian, Ubuntu and RHEL 10 and supports Solr 9.11. Hosts that deploy the OWASP Core Rule Set with apache_httpd need apache_httpd__mod_security_coreruleset_version in their inventory, since the role no longer picks a release on its own and verifies the download against a checksum.

Breaking Changes

  • role:apache_httpd: The role no longer hands everything below the document root to the web server user, so a hole in a web application can no longer rewrite the code of every site on the host. The roles that install an application set the owners they need. For content placed by hand that Apache has to write, give the writable directories to apache (www-data on Debian and Ubuntu) yourself. Remove apache_httpd__skip_document_root_chown from your inventory.
  • role:openvpn_server: The role requires OpenVPN 2.7 and installs or upgrades it from the OpenVPN repository, which the openvpn_server playbook enables with the new repo_openvpn role. The upgrade restarts the OpenVPN service from within the package and drops every client, so run it in a maintenance window and restart the service once more afterwards, as the message at the end of the run says. The server refuses client certificates with an RSA key below 2048 bits, a SHA-1 signature or without the TLS Web Client Authentication key usage, and no longer accepts several clients with the same certificate; set openvpn_server__duplicate_cn: true where clients share one. Clients that only speak TLS 1.2 and carry the tls-cipher line of the former example client config must drop that line. Remove openvpn_server__dh and openvpn_server__dh_skip_deploy from your inventory.
  • role:apache_httpd: apache_httpd__mod_security_coreruleset_version has no default anymore and accepts only the OWASP Core Rule Set releases the CRS project supports with security fixes, currently 4.25.2, 4.29.0 and 4.30.0. On hosts with apache_httpd__skip_mod_security_coreruleset: false, set it in the inventory, otherwise the run aborts.
  • role:apache_solr: Solr listens on 127.0.0.1 only and gets 180 seconds to stop gracefully, as upstream ships it, instead of listening on all addresses and being killed after 15 seconds. Set apache_solr__http_bind_address: '0.0.0.0' for a Solr that other hosts have to reach.
  • role:bind: named validates DNSSEC by default, as the bind package does, and follows the system-wide crypto policy. Forged or broken answers for signed zones are answered with SERVFAIL instead of being passed on. The forward, static-stub and stub zones in bind__zones are excluded from validation; list other internal zones below a signed domain or TLD in bind__dnssec_validate_except, or set bind__dnssec_validation: false. On RHEL 8 the role fails if it has zones to exclude, since BIND 9.11 cannot; set bind__dnssec_validation: false there (#355, #356).
  • role:system_update: On Debian and Ubuntu, the system update no longer updates the database of an AIDE installed by hand, since it also accepted changes that were pending before the update. On such hosts the daily AIDE mail now lists the files each update changed. Deploy the aide role to have its database updated after updates again.
  • role:grav: The grav:cron tag is gone. Run the role with --tags grav to deploy the timers and their services, or with --tags grav:state to enable or disable the timers.
  • role:firewall: With firewall__firewall: 'fwbuilder', the default, the run aborts on a host that has neither /etc/fwb.sh nor firewall__fwbuilder_repo_url, before the role stops any firewall. Until now fwb.service failed there and the host ran without a firewall. Deploy /etc/fwb.sh, set firewall__fwbuilder_repo_url, or set firewall__firewall to the firewall the host uses.
  • role:chrony: The role takes effect on Debian and Ubuntu, where chronyd reads /etc/chrony/chrony.conf and ignored the /etc/chrony.conf the role deployed, so these hosts synchronised with the distribution's default pools until now. As on the Red Hat family, chronyd uses only the sources from chrony__ntp_pools and chrony__ntp_servers, without the distribution's pools, DHCP sources or /etc/chrony/sources.d. Without either of them, chronyd synchronises with ntp.metas.ch.
  • role:monitoring_plugins: The source install downloads the Python dependencies on the Ansible controller, which therefore needs pip for the Python that runs Ansible and access to PyPI; the targets no longer need Internet access.
  • role:kernel_modules: The tun kernel module is blocked by default (CVE-2026-81000, RHSB-2026-011). This stops OpenVPN, WireGuard in userspace, rootless Podman and Docker networking and libvirt VM networking after the next reboot, which the role requests on hosts where tun is loaded. Before running the role, add kernel_modules__modules__host_var: [{name: 'tun', enabled: true}] to the inventory of every such host. Rootful Docker and Podman with bridge networking are not affected.
  • role:grafana: grafana__users_case_insensitive_login is gone; remove it from your inventory. Grafana has ignored the setting since v11.0.0 and always matches logins case-insensitively.
  • role:system_update: system_update__pre_update_code and system_update__post_update_code now also run in the daily security lane on Rocky, around the transaction that installs the hot-fixes, where until now only the weekly lane ran them. Set system_update__security_pre_update_code: '' and system_update__security_post_update_code: '' to keep the security lane free of it, or set either to a codeblock of its own to have the two lanes do different things.
  • role:wordpress: The vHost file is named after the host of wordpress__url, for example wordpress.example.com.80.conf, instead of wordpress.conf. Remove the old file with rm -f /etc/httpd/sites-{enabled,available}/wordpress.conf and reload httpd, otherwise Apache may keep serving the site from it.
  • role:wordpress: The WordPress core, wp-config.php and wp-content/mu-plugins belong to root, so a vulnerable plugin can no longer modify them; plugins and themes can still be installed from the web interface. The core is updated by wordpress-core-minor-update-<instance>.timer (minor releases) and --tags wordpress:update instead of by WordPress itself. After a permalink change in the web interface, add the displayed rewrite rules to .htaccess by hand.
  • role:wordpress: The REST API is restricted to logged-in users by the Disable WP REST API plugin, which replaces Disable REST API (disable-json-api) and also blocks the routes of plugins installed later. A front-end feature that calls the REST API without a login, such as some contact forms, needs an exception in code.
  • role:wordpress: Application passwords are switched off, since they bypass a second factor. Set wordpress__application_passwords_enabled: true for integrations that use them, such as the WordPress mobile app.
  • role:wordpress: WordPress honours X-Forwarded-For only from the proxies in wordpress__trusted_proxies and ignores X-Forwarded-Host, which any client could set before. Behind a reverse proxy, list its IP address.
  • role:wordpress: wordpress__url must include the scheme, for example https://wordpress.example.com. The role sets the site address (home and siteurl) to it on every run, so the login cookie of an https:// site carries the Secure flag, and an address changed in the WordPress settings is set back.
  • role:icinga2_agent: If the agent cannot get a PKI ticket from the Icinga2 master, the run aborts and names the cause and the fix. Until now the role set the agent up anyway, which also replaced the signed certificate of an agent that was already connected with an unsigned one. If you sign agent certificates on the master by hand, or do not set icinga2_agent__icinga2_api_user_login, set icinga2_agent__skip_pki_ticket: true.
  • role:dnf_makecache: dnf_makecache__service_enabled and dnf_makecache__service_state are gone; remove them from your inventory. The role only manages dnf-makecache.timer now, since dnf-makecache.service cannot be enabled at boot and only runs when the timer triggers it. dnf_makecache__service_enabled never had an effect, but a run against an unchanged host reported a change for it. A host that set dnf_makecache__service_state: 'started' no longer runs dnf makecache on every run of the role. Use dnf_makecache__timer_enabled and dnf_makecache__timer_state for the periodic cache refresh.
  • role:kibana: The session cookie always carries the Secure flag, also behind a reverse proxy that terminates TLS, where Kibana left the flag off. A Kibana that browsers reach over plain HTTP no longer logs anyone in until kibana__xpack_security_secure_cookies: false is set. Remove xpack.security.secureCookies from kibana__raw if you set it there.
  • role:icingaweb2: The session and remember-me cookies always carry the Secure flag, also behind a reverse proxy that terminates TLS and talks plain HTTP to IcingaWeb2, where IcingaWeb2 left the flag off. An IcingaWeb2 that browsers reach over plain HTTP no longer logs anyone in until icingaweb2__cookie_secure: false is set.
  • role:apache_httpd: Every entry in apache_httpd__htpasswd__*_var needs the path subkey, because the username and the path together identify an entry. Until now, entries with the same username but a different path were collapsed into one, so only the last file got the user; a user listed with different paths in group and host variables is now written to both files. On entries that relied on the default, set path: '/etc/httpd/.htpasswd' (RedHat) or path: '/etc/apache2/.htpasswd' (Debian and Ubuntu), otherwise the play fails with an error naming the entry.
  • role:postfix: On RHEL 10 the role deploys the compatibility level the distribution ships (3.8) instead of the RHEL 8 / 9 value it applied everywhere. Postfix now matches TLS fingerprints with SHA-256 instead of MD5, evaluates the relay restrictions before the recipient restrictions, and uses the neutral wording in its postscreen log lines. Re-generate any peer fingerprint pinned as MD5 in a TLS policy table, and check log parsers keyed on the old postscreen wording. Set postfix__compatibility_level: '2' to restore the previous behaviour. RHEL 8, RHEL 9 and Debian are unaffected.
  • role:login: The default umask in /etc/login.defs is back to the 022 the distributions ship, instead of the 027 set since v7.0.0, so files that users create in a login session are readable by other local users again. Set login__login_defs_umask: '027' to keep the stricter value.
  • playbook:crypto_policy, playbook:kernel_modules, playbook:selinux: These playbooks run postfix, mailto_root and schedule_reboot before their own role, so that a change needing a reboot can request one. mailto_root__from and mailto_root__to are therefore mandatory for them; a host set up with setup_basic already has both. To keep a playbook as it was, set <playbook>__skip_postfix, <playbook>__skip_mailto_root and <playbook>__skip_schedule_reboot to true, for example crypto_policy__skip_schedule_reboot: true.
  • role:fail2ban: Removed apache-404-matomo filter and jail. The apache-404 filter now matches all supported LogFormats including matomo and vhost_common. Remove apache-404-matomo entries from fail2ban__filters__*_var and fail2ban__jails__*_var in your inventory and use apache-404 instead.
  • role:fail2ban: Rename fail2ban__jail_apache_404_ignoreregex to fail2ban__filter_apache_404_ignoreregex in your inventory. The regular expressions land in the apache-404 and apache-404-matomo filters, which both jails share, so the old name pointed at a jail that never carried the setting. The value itself is unchanged.

Added

  • role:collabora: Add support for Collabora Online Enterprise 24.04.19, 26.04.3 and 26.04.4.
  • role:collabora: Add support for Collabora Online Enterprise 25.04.13.
  • role:collabora: Add support for Collabora Online CODE 26.04.5.
  • playbook:setup_basic, role:monitoring_plugins: On the Red Hat family, psi=1 is put on the kernel command line, so the psi-* monitoring plugins report pressure stall information instead of finding none; each host reboots once at its maintenance window, and setup_basic__skip_bootloader skips it.
  • role:apache_httpd: lfops__trusted_proxies lists the reverse proxies in front of a host, and Apache then logs the client from X-Forwarded-For instead of the proxy in the access and the error log.
  • role:apache_httpd: Creates a self-signed placeholder for every certificate in apache_httpd__placeholder_certificates__*_var that does not exist yet, so a TLS vHost starts before its certificate is issued; the playbooks fill the list from acme_sh__certificates.
  • acme_sh can run as the last role of every playbook with apache_httpd, so a fresh host gets its Let's Encrypt certificates in a single run; enable it with the playbook's acme_sh skip variable (apache_httpd and the setup_* playbooks with apache_httpd).
  • role:repo_openvpn, playbook:repo_openvpn: Add a role and playbook that deploy the OpenVPN 2.7 release repository of the OpenVPN community on RHEL 8, 9 and 10, where EPEL ships outdated OpenVPN versions.
  • role:openvpn_server: Add meta/argument_specs.yml declaring the user-facing variables, so role-entry validation catches type mismatches and invalid values before any task runs.
  • role:apache_solr: Supports Solr 10, deployed as a single instance without ZooKeeper, as with Solr 9.
  • role:apache_solr: Supports Debian 12 and 13, RHEL 10 and Ubuntu 22.04, 24.04 and 26.04, with the Java the Solr version needs installed from the distribution.
  • role:bind: Add meta/argument_specs.yml declaring the user-facing variables, so role-entry validation catches type mismatches and invalid values before any task runs.
  • role:duplicity: The backup includes the data of the applications LFOps deploys by default: /data, /srv, /var/lib/grafana, /var/lib/icinga2 (including the Icinga2 CA), /var/lib/shiny-server, /var/lib/turn, /var/mail, /var/named, /var/solr/data, /var/spool/mail and /var/www (without the repository mirrors). Hosts without these directories are not affected. On hosts with large data, for example VM images in /data, check the backup size or set the path to state: 'absent'.
  • playbook:setup_basic: Installs AIDE on every host, which checks file integrity twice a day and after every boot; skip it with setup_basic__skip_aide.
  • role:aide, playbook:aide: Add a role and playbook that install AIDE on Debian 12 and 13, RHEL 8, 9 and 10 and Ubuntu 22.04, 24.04 and 26.04 as the CIS benchmarks recommend, leaving aidecheck.service failed on any finding and keeping the database in step with system_update and unattended-upgrades.
  • role:lynis, playbook:lynis, playbook:setup_basic: Add a role and playbook that install Lynis on every setup_basic host and audit it once a day for the lynis-logfile monitoring plugin, with findings accepted through lynis__skip_tests instead of a hand-edited /etc/lynis/custom.prf.
  • role:repo_monitoring_plugins: --tags repo_monitoring_plugins:remove removes the repository and its signing key.
  • role:grafana: grafana__preinstall_auto_update controls whether Grafana updates its preinstalled plugins on every start.
  • role:icingaweb2: icingaweb2__cookie_path sets the path of the session and remember-me cookies, for example /.
  • role:collabora: Add support for Collabora Online CODE 26.04.4.
  • role:wordpress: Entries in wordpress__plugins accept enabled: false, which keeps a plugin installed but deactivated.
  • role:system_update: The role's inventory variables are type-checked when it starts, so a mistyped value fails the run right away instead of surfacing further in as a confusing error.
  • role:wordpress: Several WordPress instances can share a host as pseudo hosts in the inventory, under different host names as well as under different paths of one host name, such as https://example.com/blog.
  • role:fail2ban: The wordpress-login filter and z10-wordpress-login jail ban IPs with too many failed WordPress logins, on the host whose Apache logs the visitor's address.
  • role:rstudio_server, playbook:rstudio_server: Add a role and playbook to install RStudio Server Open Source, the browser-based R development environment. Users sign in with their account on the host and have to be a member of a group to be let in at all, the PAM profile covers directory users where the vendor's covers local ones only, and the R sessions can be given a memory and process budget.
  • role:shiny_server, playbook:setup_shiny_server: Add a role and playbook to install Shiny Server Open Source and serve several tenants from one host, each with its own hostname, password file, R worker and system account, behind an Apache httpd reverse proxy that also passes the authenticated user into the application. Shiny Server itself listens on the loopback only, because it authenticates nobody and hands every client header to the application.
  • role:r, playbook:r: Add a role and playbook to install R and pandoc, point R at the Posit Public Package Manager so that CRAN packages arrive as prebuilt binaries instead of being compiled on the host, and install the CRAN packages an application needs.
  • role:borg_local, role:icinga2_master, role:nextcloud, role:schedule_reboot, role:tools: icinga2_master__downtime_api_user creates an Icinga2 API user that may only schedule and remove downtimes, and the roles that set a downtime around a backup, a Nextcloud update or a reboot use it unless their own *__icinga2_api_user_login is set.
  • role:crypto_policy, role:kernel_modules, role:selinux: A change that only takes effect after a reboot requests one at the maintenance window instead of being left to the operator to notice: a switched crypto policy, a blocked kernel module that is still loaded, and switching SELinux on or off. Where the reboot mechanism is not deployed, the role reports the pending reboot as before. lfops__reboot_now performs it in the same run.
  • Every playbook prints the manual steps a run leaves to the operator as one block directly above the PLAY RECAP, collected from all roles of the play instead of scattered over its output. The roles keep printing their message where it occurs as well, so a role used outside this collection still reports it.
  • role:bootloader: New role that manages the kernel command line, for parameters that only take effect at boot time such as psi=1. Options are applied to every boot entry of the host, on the Red Hat family with grubby and on Debian and Ubuntu through a GRUB drop-in of its own. A changed command line requests a reboot at the maintenance window instead of rebooting right away, or applies it during the run when lfops__reboot_now is set, and a --check run reports what it would change without touching the host.
  • role:fail2ban: The fail2ban:configure tag deploys the actions, filters and jails without touching the packages.
  • role:fail2ban: Add meta/argument_specs.yml declaring the user-facing variables, so role-entry validation catches type mismatches and invalid values before any task runs.

Changed

  • role:apache_httpd: Apache answers requests for PHP files that do not exist with 404 itself instead of passing them to PHP-FPM, so scanners no longer tie up pool workers or fill the error log.
  • playbook:setup_basic: Checks the variables of all its roles, the compiled firewall in the Firewall Builder repository and the reachability of the Icinga2 master before it changes anything on the host, so a missing prerequisite no longer aborts the run halfway through, after SSH was already hardened.
  • Handlers that a role notified before a later task failed run anyway, so a changed configuration reaches the running service; until now it stayed inactive, also across later runs, which reported no change (all playbooks).
  • playbook:acme_sh: No longer runs the apps role, since the acme_sh role installs curl, openssl and tar itself.
  • role:acme_sh: Installs a certificate again when the installed file differs from the one acme.sh issued, which replaces a placeholder that an aborted run left behind.
  • role:apache_solr: Downloads Solr from the Apache CDN, which is much faster than the Apache archive, and falls back to the archive for releases the CDN no longer carries.
  • role:apache_solr: The run aborts for a user whose password equals the username, since Solr 9.11 and newer reject such logins.
  • role:apache_solr: A role holding the all permission is allowed every request, also one that a more specific permission of another role matches first.
  • role:apache_solr: The Solr program files belong to root, as with Solr's own installation script, and files that Solr creates are no longer readable by other users.
  • Downloads from the Internet, such as release tarballs, GPG keys, git clones, GitHub release lookups and package installations, are retried up to three times, so a brief outage of a download source or package repository no longer aborts the run (all roles).
  • role:apache_httpd: Bump the OWASP Core Rule Set to 4.30.0.
  • role:apache_httpd: The OWASP Core Rule Set is downloaded on the Ansible controller, so the target no longer needs access to GitHub.
  • role:monitoring_plugins: On Linux, the role no longer stops the Icinga2 agent while it deploys the plugins, so a run no longer interrupts the monitoring of the host.
  • role:icinga2_agent: The role runs icinga2 node setup and restarts the agent only when the agent needs a new certificate or its settings changed, instead of on every run.
  • LFOps requires community.general 7.0.0 or newer (still below 9.0.0), which ansible-galaxy collection install linuxfabrik.lfops pulls in, while a manually maintained collection list has to be raised.
  • plugin:bitwarden_item: The lookup syncs the Bitwarden vault once per Ansible run instead of every 60 seconds, which makes runs with many lookups considerably faster, since each sync makes bw serve list the whole vault. Before it creates a missing item, it syncs again, so an item created elsewhere during the run is not created a second time.
  • role:icingaweb2_module_generictts: Downloads the module from Linuxfabrik, who maintain it since Icinga archived the original repository. The tarballs of v2.1.0 are identical.
  • role:duplicity: /var/lib/aide is backed up by default, so that the AIDE database can be compared with a copy outside the host. Hosts without AIDE are not affected.
  • role:monitoring_plugins: The source install removes plugins that an earlier run deployed and the checked-out version no longer carries.
  • role:monitoring_plugins: The source install deploys the dependency versions pinned in the monitoring-plugins lockfiles and, for a release, the Linuxfabrik library release they pin, instead of the newest versions of both.
  • playbook:icinga2_agent, playbook:setup_basic, playbook:setup_icinga2_master: The Monitoring Plugins repository is only registered for monitoring_plugins__install_method: 'package'.
  • role:fail2ban: The portscan jail no longer bans TCP scans that send no plain SYN, such as FIN, NULL, Xmas and ACK scans, since they find no open port on a stateful firewall.
  • role:grafana: Grafana no longer updates its preinstalled plugins on every start, so datasources such as InfluxDB and Prometheus no longer disappear from the web interface when the plugin download server is unreachable.
  • role:grafana: grafana.ini follows the file that current Grafana packages ship, so deploying it only changes the settings LFOps manages. As a side effect, recording rules time out after 30 seconds instead of 10.
  • plugin:bitwarden_item, module:bitwarden_item: A run against a vault that contains no items at all aborts instead of creating the first one, because bw serve briefly reports an empty vault after every sync (bitwarden/clients#23283).
  • role:repo_postgresql: The PostgreSQL version repositories take precedence over the distribution's packages of the same name, so on RHEL 10 an install or update no longer switches a PostgreSQL server from the PGDG build to the AppStream build, which uses a different file layout.
  • role:apache_httpd: Responses of type text/markdown are compressed like HTML, so the Markdown versions of pages that CMSs such as Grav hand to AI agents no longer go out uncompressed.
  • role:grav: The README lists setting session.secure as a manual step behind a reverse proxy that terminates TLS, where Grav sends its session cookies without the Secure flag.
  • role:gitlab_ce: gitlab_ce__rb_external_url supports https:// behind a reverse proxy that terminates TLS, and the README recommends it there. With http://, GitLab's session cookie goes out without the Secure flag.
  • role:grafana: The login cookie carries the Secure flag when grafana__root_url is an https:// URL. grafana__cookie_secure overrides this.
  • playbook:setup_basic: The mail and reboot roles run before the security roles, so a first run against a fresh host files the reboot request that a changed crypto policy, SELinux state or kernel module blocklist needs. Until now the reboot mechanism was deployed further down the playbook and such a change could only be reported to the operator.
  • role:network: The reminder that NetworkManager may have to be restarted by hand is printed only when a connection profile actually changed, instead of on every run.

Removed

  • role:github_project_createrepo: github_project_createrepo__webserver_user is gone, since the web server no longer gets an ACL entry; remove it from your inventory.

Fixed

  • role:icingaweb2_module_grafana: graphs.ini no longer keeps the graphs of monitoring plugins that were removed or renamed upstream.
  • role:uptimerobot: Alert contacts past the first 50 are found, so alert_contacts of a monitor can name them and uptimerobot_alert_contact_info lists all of them.
  • role:uptimerobot: Port monitors with sub_type https, ftp, smtp, pop3 or imap are created instead of rejected by UptimeRobot, a changed sub_type takes effect on an existing monitor, and a port monitor with a sub_type no longer reports a change on every run.
  • role:php: --tags php:ini also deploys the PHP-FPM pools, so a changed php__ini_memory_limit__*_var, php__ini_max_execution_time__*_var and the like take effect in PHP-FPM, not only on the command line.
  • role:chrony: Without chrony__ntp_pools or chrony__ntp_servers in the inventory, chronyd synchronises with ntp.metas.ch, the time server of the Swiss Federal Institute of Metrology, instead of running without a time source. If both are set to [], the role aborts.
  • role:icingaweb2: PHP gets a memory_limit of 256M instead of 128M, so the CSV and JSON exports, such as History > Event Overview, handle about twice as many rows before they break off with "Allowed memory size exhausted". Override it with php__ini_memory_limit__group_var / php__ini_memory_limit__host_var.
  • role:nextcloud: The README documents the app states correctly. state: 'present' installs an app but leaves it disabled; use state: 'enabled' to switch on an app, including the apps the role disables by default, such as activity, notifications and systemtags.
  • role:icingaweb2_module_grafana: With JWT authentication, the Grafana graphs in IcingaWeb2 no longer switch to the Grafana login after 30 seconds. The token stays valid for 3 days; adjust with icingaweb2_module_grafana__auth_jwt__expires.
  • playbook:uptimerobot: The playbook runs as a normal user on the Ansible controller, without --become. Until now it aborted because it tried to write /var/log/linuxfabrik-lfops.log on the controller, and with --become it could not find the API key in ~/.uptimerobot.
  • role:repo_epel: On RHEL 10 hosts with repo_epel__mirror_url set, EPEL is installed from the mirror. Until now dnf failed to download the EPEL metadata, which also broke every other dnf call on the host.
  • role:php: Apache starts after PHP-FPM at boot, so the first PHP requests after a reboot no longer fail.
  • role:firewall: With firewall__fwbuilder_repo_url, a repository without a compiled firewall for the host aborts the run before the role stops any firewall. Until now the role stopped a running firewalld, iptables, nftables or ufw first and left the host without a firewall.
  • role:acme_sh: On Debian and Ubuntu, certificates are installed with systemctl reload apache2 instead of systemctl reload httpd, which does not exist there; certificates installed before keep the old command until they are issued again.
  • role:mount: A freshly created filesystem is relabelled for SELinux after mounting, so confined services such as Apache httpd can access it without a manual restorecon.
  • role:mirror: Repairs the ACL mask of mirror__base_path when a chmod narrowed it to r-x, which made reposync fail with Permission denied on every new repository.
  • role:mirror: Runs on minimal installations such as Rocky 10, where it aborted for lack of setfacl, since the role installs acl, createrepo and git itself instead of the mirror playbook running the apps role.
  • role:openvpn_server: The role runs on a minimal RHEL 10 installation, where it aborted for lack of openssl while generating Diffie-Hellman parameters, which OpenVPN 2.7 no longer needs.
  • role:apache_solr: Passwords no longer show up in the output of a run, and a user without state no longer aborts it.
  • role:apache_solr: The role runs without EPEL on RHEL and no longer restarts Solr on every run.
  • role:apache_solr: A role with several permissions takes effect, where Solr discarded it as invalid so far.
  • role:apache_solr: Users can log in on hosts without xxd, such as a minimal RHEL 9, where the role wrote an empty password hash.
  • role:apache_httpd: On Debian and Ubuntu, the first run against a fresh host no longer fails reloading Apache, since the role points PidFile to where apachectl looks; a server started by an earlier version of the role is restarted once.
  • role:apache_httpd: Apache reloads after the OWASP Core Rule Set is updated, instead of applying the previous rules until its next reload.
  • role:apache_httpd: The OWASP Core Rule Set deploys on Debian and Ubuntu, where the run failed until now, and on Ubuntu 22.04, whose ModSecurity 2.9.5 is too old for it, the run aborts with a message saying so.
  • playbook:redis, playbook:setup_mastodon: On Debian and Ubuntu, the playbooks no longer abort with "'redis__skip_repo_redis' is undefined" or "'setup_mastodon__skip_repo_redis' is undefined" unless the skip variable is set in the inventory.
  • role:grafana_grizzly, role:monitoring_plugins_grafana_dashboards: On Grafana 13.1 and newer, dashboards that the roles add or update stay in their folder, instead of landing in the root, where viewers and the graphs embedded in IcingaWeb2 got "403". A run also moves back the dashboards that earlier runs left in the root.
  • role:aide: The AIDE check no longer fails on hosts with fwupd, where it reported /etc/fwupd/fwupd.conf as changed after the first start of the fwupd daemon.
  • role:aide: The AIDE check no longer fails on hosts with an EFI system partition, where it reported the files below /boot/efi as changed a while after the database was created.
  • role:system_update: The security lane installs hot-fixes that need a newer package from BaseOS or AppStream, such as the kernel on Rocky 8.3, instead of failing on every run.
  • role:system_update: On Fedora 42 and later, where /usr/local/sbin is a link to /usr/local/bin, the role no longer deletes the update-and-reboot script right after deploying it, so the weekly update runs again.
  • role:monitoring_plugins: A run against an unchanged host no longer reports a change for the legacy dependency list of the source install.
  • roles: Tasks that run on the Ansible controller no longer escalate via sudo when the inventory sets ansible_become: true, where they failed without passwordless sudo on the controller or ran as root and left root-owned files in /tmp.
  • plugin:bitwarden_item, module:bitwarden_item: A failed sync of the Bitwarden vault, such as an "HTTP Error 400: Bad Request" or a timeout of bw serve, is tried again after 10, 30 and 60 seconds instead of aborting the run right away.
  • role:aide: Before it creates the database, the role also waits for running dnf-automatic jobs on the Red Hat family and for the update jobs of the system_update role on every platform, not only for the apt jobs on Debian and Ubuntu. An update during the initialisation left files in the database that the first check then reported.
  • playbook:setup_basic: With setup_basic__skip_duplicity or setup_basic__skip_glances, the playbook no longer builds the Python venv of the skipped role, which could abort the run with a pip error on hosts that do not back up with duplicity.
  • role:kernel_settings: sunrpc.* settings, such as the sunrpc.tcp_slot_table_entries the mariadb_server role sets, survive a reboot. Until now the sunrpc module was not loaded again after a reboot on hosts without NFS, so TuneD could not apply the setting and the next run of the role failed in tuned-adm verify.
  • role:repo_baseos: The Rocky Linux security repository works on Rocky 8 releases before 8.5, where dnf failed to download its metadata.
  • role:monitoring_plugins: The source install deploys the OID lists and MIBs of the snmp plugin, which until now failed with "No such file or directory" on every host installed this way.
  • role:bind: A secondary zone with type: 'slave' is saved to its file again, so the secondary answers it after a restart without waiting for the primary.
  • role:bind: Reverse lookups for private and special-use addresses, such as 10.0.0.0/8 or fd00::/8, are answered locally, as BIND does by default, instead of waiting for the forwarders, which also no longer see the internal addressing.
  • role:kernel_settings: The role works with fedora.linux_system_roles 2.5.0 and later, which a fresh installation of LFOps pulls in. Until now the run aborted with "kernel_settings_transparent_hugepages must be null, one of always, madvise, never" unless kernel_settings__transparent_hugepages__*_var and kernel_settings__transparent_hugepages_defrag__*_var were set.
  • role:system_update: The AIDE database is only updated after an update if a check right before the update comes out clean, instead of relying on the last scheduled check, so changes made since then are no longer accepted along with the update; a check that cannot run at all is reported in a mail of its own.
  • role:fangfrisch: --tags fangfrisch:state no longer aborts on an undefined variable.
  • role:firewall: Hosts in one run with different firewall__fwbuilder_repo_url values each deploy /etc/fwb.sh from their own repository, instead of all from the repository of the first host.
  • role:firewall: firewall__firewall: 'iptables' no longer aborts when there is no iptables file in the inventory's host_files, which the README describes as optional.
  • role:firewall: A host switched away from fwbuilder or iptables stops, disables and masks that firewall instead of keeping it running next to the new one, and no longer reports a change on every run.
  • module:nextcloud_occ_app: An occ app:list output or installed_apps_json that is valid JSON but not an object aborts with a clear message instead of a Python traceback.
  • module:nextcloud_occ_system_config: Setting a key that does not exist yet to an empty value (value: '') creates it. Until now the module reported no change and left the key missing.
  • module:uptimerobot_mwindow_info: Monthly maintenance windows on day 1 to 7 of the month are reported with their day numbers instead of weekday names, e.g. 1-15 instead of mon-15.
  • role:system_update: The daily security lane on Rocky refreshes the AIDE database after installing hot-fixes, like the weekly lane, so the next AIDE check no longer fails on every file a hot-fix touched.
  • role:lvm: On Debian and Ubuntu, mounting an LV no longer fails on restorecon, which only runs where SELinux is enabled.
  • role:lvm: The role installs the tools for XFS and ext2/3/4, so creating the default XFS file system no longer fails on hosts without mkfs.xfs, such as those deployed from a Debian cloud image.
  • role:lvm: mount_owner, mount_group and mount_mode apply to the mounted file system from the first run on. Until now they only took effect on the second run, which therefore reported a change.
  • role:lvm: Removing an LV (state: absent) no longer aborts with 'dict object' has no attribute 'size'.
  • role:lvm: Removing a VG (state: absent) no longer aborts with could not find 'pvs' key when the entry lists no pvs.
  • role:lvm: Shrinking an LV works. It needs force: true in addition to shrink: true; with shrink: true alone the run aborted.
  • role:lvm: The role installs lvm2, so it also works on hosts installed without LVM, such as those deployed from a cloud image.
  • role:lvm: Creating or resizing a PV no longer fails on RHEL 8 with SyntaxError: future feature annotations is not defined.
  • role:network: Hosts without network_connections or network_state no longer run the upstream network role at all, which occasionally hung the play for good after it had finished.
  • role:kernel_settings: The role no longer aborts on Ubuntu 22.04 with Verification failed, current system settings differ from the preset profile.
  • role:tools: The role no longer aborts on Ubuntu with No package matching 'cloud-utils-growpart' is available.
  • role:python_venv: The role no longer aborts on Debian and Ubuntu with Failed to import the required Python library (packaging).
  • playbook:setup_basic: The play no longer aborts on Debian and Ubuntu with No package matching 'network-scripts' is available or '__yum_utils__package' is undefined, since it runs the network and yum_utils roles on the Red Hat family only.
  • role:monitoring_plugins: The plugin icons for IcingaWeb2 are no longer missing when the directory ansible-playbook runs in contains .svg files.
  • role:monitoring_plugins: The source install deploys only the modules of the Linuxfabrik library, as the one-line installer does, removes the documentation and development files earlier runs placed next to them, and removes plugin assets the checked-out version no longer carries.
  • role:monitoring_plugins: The source install no longer reports a change on every run once the plugins have run.
  • role:monitoring_plugins: The source install no longer clears the setuid bit of the distribution's check_icmp and check_dhcp on every run.
  • role:monitoring_plugins: --tags monitoring_plugins:remove no longer aborts on Debian and Ubuntu, and also removes the version lock of the SELinux package, the SELinux policy module, the Debian conffiles and every file a release of the plugins ever installed.
  • role:monitoring_plugins: The source install sets nagios_run_sudo and, for Monitoring Plugins releases after 8.0.0, loads the SELinux policy module, so plugins run through sudo under enforcing SELinux on RHEL 8 and 9.
  • role:monitoring_plugins: The source install of a release before 8.0.0 no longer fails on the missing logging sudoers file.
  • role:fail2ban: An empty fail2ban__jail_portscan_allowed_ports exempts no port, so the portscan jail bans every denied connection attempt instead of none.
  • role:fail2ban: The portscan jail no longer bans a server that a local proxy talks to because the firewall logged a late TCP packet or an ICMP error from it, for example the final FIN of a half-closed connection.
  • role:grafana: The from_name of grafana__smtp_config is used as the sender name of emails, instead of the value of skip_verify.
  • module:bitwarden_item: The module works with the Mitogen strategy, where it aborted with MODULE FAILURE on every run, for example when the grafana role stores its service account tokens.
  • plugin:bitwarden_item, module:bitwarden_item: Running against several hosts in parallel no longer creates duplicates of a Bitwarden item, whether the item is new or has existed for a long time, so the next run no longer aborts with "Found multiple Bitwarden items".
  • role:wordpress: The installation no longer aborts at wp core download when Ansible connects as root without privilege escalation.
  • role:wordpress: A second run no longer reports the wp-config.php constants, wordpress__plugins and wordpress__theme as changed.
  • role:wordpress: The WXR file in wordpress__wxr_export is imported when the role installs WordPress; the import never ran before.
  • role:wordpress: Ansible's temporary directory for apache is /usr/share/httpd/.ansible/tmp instead of a path with two trailing spaces.
  • role:apache_httpd: The wordpress vHost blocks direct calls to the PHP files below wp-includes/ and wp-admin/includes/, whose rules never matched.
  • role:postfix: postfix__compatibility_level takes effect on Debian and Ubuntu as well, and defaults to the level the distribution ships, so Debian 13 and Ubuntu 26.04 run at 3.9 instead of 3.6 (#364).
  • role:mariadb_server: On RHEL 10 with a selinux-policy-targeted older than 42.1.18-4.el10_2.3, MariaDB runs confined in mysqld_t again, so web applications such as WordPress or Nextcloud reach its socket. Until now it ran in initrc_t there, and PHP-FPM failed to connect until the SELinux policy was updated and MariaDB restarted.
  • role:monitoring_plugins: A package install that fails no longer leaves the Monitoring Plugins unlocked, so a later system update cannot move them past monitoring_plugins__version. The lock that existed before the run is set again.
  • role:monitoring_plugins: A run against an unchanged host no longer reports changes for the package versionlock (#353).
  • role:collabora: A run against an unchanged host no longer reports changes for the coolwsd log file and the ownership of /etc/coolwsd.
  • role:collabora: The role runs on RHEL 10, since it no longer installs the distribution's mythes and hunspell dictionary packages, which Collabora does not need next to its own dictionary packages. Packages already installed are left in place (#373).
  • playbook:kvm_host: The playbook deploys the EPEL repository, and CRB on Rocky 9 and newer, so it no longer fails to install genisoimage on RHEL 9 and 10 hosts that did not have EPEL set up already (#375).
  • playbook:chromium_headless, playbook:icingaweb2_module_pdfexport, playbook:repo_epel: On Rocky 9 and newer, these playbooks enable the CRB repository together with EPEL, like every other playbook that deploys EPEL, since EPEL packages depend on packages from CRB.
  • role:repo_icinga: On Fedora the role deploys Icinga's public repository instead of failing on a release package that Icinga no longer publishes (#360).
  • role:repo_postgresql: The role no longer aborts on RHEL 10 right after deploying the repository (#370).
  • role:repo_collabora_code: The role deploys the repository on RHEL 10 instead of failing on a missing template (#377).
  • role:lvm: growpart: true works on minimal installations, where the role failed because nothing installed growpart (#365).
  • role:icinga2_agent, role:icinga2_master: Icinga 2 starts after SSSD at boot as intended, so its early sudo calls no longer fail with problem with defaults entries; the ordering pointed at a unit that does not exist and never took effect (#357).
  • role:grafana: With grafana__auth_jwt: true, the run no longer aborts at generate JWT RSA private key with Cannot detect the required Python library cryptography on hosts that lack it, because the playbooks deploying Grafana install python3-cryptography first.
  • role:clamav, role:sshd: --tags clamav:configure, --tags clamav:state and --tags sshd:state no longer abort on an undefined variable, so a restart skipped with lfops__skip_restart_handlers can be caught up with --tags <role>:state as the README describes.
  • role:php: A playbook that includes PHP, such as setup_nextcloud, no longer aborts at Get PHP version when it is run with another role's tags, for example --tags apache_httpd, against a host that has no PHP installed yet.
  • role:kdump: kdump__service_enabled: true turns kdump on on RHEL 10 as well instead of leaving it off without an error, and a kdump that is supposed to run fails the run when its service cannot be managed (#359).
  • role:repo_mariadb: On RHEL 10 the role aborts for MariaDB versions older than 10.11, which MariaDB publishes no RHEL 10 packages for, instead of deploying a repository that answers 404 and breaks every dnf transaction on the host.
  • role:repo_epel: The role no longer aborts on RHEL 10, AlmaLinux 10 and CentOS Stream 10.
  • role:chrony: chronyd on RHEL 10 no longer logs Could not open keyfile on every start, since the deployed chrony.conf loads no key file on any release.
  • role:nextcloud: nextcloud-update sets the Icinga downtime again, taking the API user from icinga2_master__downtime_api_user (see Added) instead of from the system_update__icinga2_api_user_login removed in v8.0.0.
  • role:borg_local, role:schedule_reboot, role:tools: The Icinga downtime around a backup or a reboot is set again when the deploying playbook does not run icinga2_agent itself, such as bootloader, system_update or tools, and the inventory only sets the mandatory icinga2_agent__icinga2_master_cn.
  • role:fail2ban: The apache-botsearch, apache-fakegooglebot, apache-nohome and apache-noscript jail templates can be deployed again. Using one of them aborted the run.

Security

  • role:openvpn_server: The server negotiates TLS 1.2 only with forward secrecy and checks client certificates against OpenSSL security level 2 (#358).
  • role:apache_httpd: The OWASP Core Rule Set archive is checked against a SHA-256 checksum before it is deployed, so a tampered or corrupted download aborts the run.
  • role:monitoring_plugins: The source install checks every pinned Python dependency against the checksums in the lockfile instead of installing whatever PyPI serves, and puts the sudoers drop-ins in place only once visudo accepts them.
  • role:github_project_createrepo: The service can only write to the repositories it maintains instead of to everything below github_project_createrepo__base_path, where it could replace other files such as a repository signing key. The role removes the ACL entries it granted before.
  • role:kernel_modules: Blocks further rarely used kernel modules by default that unprivileged users can get loaded and that are prone to local privilege escalations, among them ah6, pppoe and sctp_diag from RHSB-2026-011. This stops Bluetooth, L2TP/IPsec, PPPoE, PPTP and IPsec AH; set enabled: true for the modules a host needs. The role README lists them all.
  • role:wordpress: --tags wordpress:export writes to /backup/wordpress-export/<instance>, readable by apache and root only, instead of to /tmp.
  • role:wordpress: The database and admin passwords no longer show up in the process list during the installation.
  • role:wordpress: WP-CLI is verified against its published checksum, and an installed WP-CLI that differs from the current release is replaced.
  • role:wordpress: wp-config.php, which holds the database password and the salts, is no longer readable by every local user.
  • role:apache_httpd: The wordpress vHost sends X-Content-Type-Options: nosniff and Referrer-Policy: strict-origin-when-cross-origin.
  • role:apache_httpd: The wordpress vHost refuses to run PHP files below wp-content/uploads, so an upload flaw in a plugin no longer leads to code execution.
  • role:repo_collabora_code: dnf verifies the signatures of the Collabora packages, as Collabora's own installation instructions do, where the repository file had switched the check off.

v9.0.0 - 2026-09-09

Highlights: Valkey gets its own role and playbook instead of being installed under the Redis name, which is what RHEL 10 hosts need now that Red Hat ships no Redis at all; those hosts have to be moved over. On RHEL 8, a MariaDB package upgrade no longer cuts applications on the same host off from their database. Apache no longer loads mod_info, which served the complete configuration including other modules' credentials. A broken PHP-FPM configuration aborts the run instead of taking the service down on the restart. Sudo rules deployed by freeipa_server can carry their commands again. The Bitwarden lookup can be told to abort instead of silently generating a new password, for runs against hosts whose credentials must already exist. The Grafana graph configuration for the Monitoring Plugins is no longer deployed on every ordinary run and has to be requested explicitly by its tag. Apache serves HTTP/2 to every client that offers it over TLS, which in a typical setup is the reverse proxy in front of an application; the hop from that proxy to the backend is unchanged. LibreNMS keeps its RRD updates in RRDCached and writes them out every 30 minutes, taking a large share of the poller's disk I/O off the host.

Breaking Changes

  • role:icingadb, role:icingaweb2, role:icingaweb2_module_reporting, role:icingaweb2_module_x509, role:mariadb_server: The MariaDB tasks move from ansible.mysql to its MariaDB counterpart ansible.mariadb, so the deprecation warning printed on every run is gone and the roles keep working once ansible.mysql drops MariaDB support. ansible-galaxy collection install linuxfabrik.lfops pulls the new collection in as a dependency; a manually maintained collection list has to add it. If you run LFOps in the Execution Environment, pull the current image (podman pull ghcr.io/linuxfabrik/lfops_ee:latest), because an EE ships the collections it was built with and an older one aborts these roles with couldn't resolve module/action.
  • role:php: The session cookie is marked Secure, so browsers only send it back over HTTPS. A site served over plain HTTP can no longer log anyone in, because the browser accepts the cookie and never returns it: set php__ini_session_cookie_secure__group_var: 'Off' for such a host, or php_value_session_cookie_secure: 'Off' for the affected pool alone. HTTPS hosts are unaffected, including behind a reverse proxy that terminates TLS, and nobody is logged out by the change: a running session resumes and keeps its existing cookie until the application regenerates the session ID.
  • role:php: The session cookie carries SameSite=Lax from PHP 7.3 on, where PHP so far emitted no attribute at all and left the decision to the browser. The cookie is no longer sent on cross-site POSTs, in iframes or on XHR, which is what stops a foreign page from acting under a visitor's session. An application whose identity provider returns through a cross-site POST, as SAML HTTP-POST binding and the OIDC form_post response mode do, loops on login until it is set back, for that pool alone via the new php_value_session_cookie_samesite: 'None' and php_value_session_cookie_secure: 'On' subkeys of php__fpm_pools__*_var (browsers require Secure for None), or host-wide via php__ini_session_cookie_samesite__group_var. An identity provider under the same registrable domain is unaffected.
  • role:redis: redis__conf_daemonize and redis__conf_supervised are gone; remove them from your inventory. Neither ever reached the running service: a Redis supervised by systemd never daemonizes, and every packaged unit either overrides both on its ExecStart line or depends on the supervised auto the role deploys. The deployed redis.conf keeps the values it had, so nothing changes on a host that used the defaults.
  • role:librenms: librenms__fqdn and librenms__config_app_url are replaced by librenms__url, which takes the URL of the instance including the scheme, for example https://librenms.example.com. Set it in place of the two, using the URL your users open in the browser even when Apache httpd on the host serves plain HTTP behind a TLS-terminating proxy.
  • role:librenms: LibreNMS trusts no reverse proxy any more, where it previously trusted one running on the LibreNMS host itself. It therefore ignores the X-Forwarded-* headers of such a proxy, and logs, access control and the detected protocol use the proxy's address instead of the client's. Hosts with a proxy in front of LibreNMS list it in librenms__config_app_trusted_proxies; ['127.0.0.1'] restores the previous behaviour.
  • role:php: The PHP-FPM pool configuration changed for existing hosts. Sessions now live in a per-pool directory (the default www pool moves from /var/lib/php/session to /var/lib/php/session/www), so logged-in users are signed out once after the upgrade. memory_limit, max_execution_time, max_input_vars, post_max_size, upload_max_filesize, session.save_handler and session.save_path are now enforced as php_admin_value, so applications can no longer change them at runtime via ini_set(). A pool that stores its sessions in redis or memcached sets php_admin_value_session_save_handler accordingly. soap.wsdl_cache_dir moves from the shared /var/lib/php/wsdlcache to a per-pool directory below it. On Debian the pool socket now belongs to root and grants the web server access through a POSIX ACL entry, where it used to be owned by the web server user; anything of your own that checks the socket's ownership rather than connecting to it needs adjusting. Worker processes recycle after 500 requests (pm.max_requests) instead of running indefinitely, and a worker still serving a single request after 60 seconds is killed (request_terminate_timeout, previously off). Hosts with legitimately long-running web requests raise php__fpm_pool_conf_request_terminate_timeout__group_var.
  • role:keycloak: Rename keycloak__state to keycloak__service_state, the name every other LFOps role uses. The value reloaded is gone: Keycloak's systemd unit has no ExecReload, so a reload never worked; use restarted instead.
  • role:keycloak: The role installs the OpenJDK its Keycloak version needs (OpenJDK 17 for Keycloak 24, OpenJDK 21 for 25 and newer) instead of relying on the apps role, which setup_keycloak no longer runs. Hosts that used apps__apps__*_var through this playbook to install further packages have to run the apps playbook for them.
  • playbook:setup_keycloak: All skip variables are named setup_keycloak__skip_<role> now. Rename keycloak__skip_kernel_settings, keycloak__skip_policycoreutils, keycloak__skip_repo_mydumper, mariadb_server__skip_python and mariadb_server__skip_repo_mariadb accordingly.
  • role:php: On RedHat, every host running this role gets the lfops_php_fpm_slowlog SELinux policy module, which grants the httpd_t domain the sys_ptrace capability and ptrace on itself. Without it the PHP-FPM slowlog stays empty, because the master is not allowed to ptrace the worker whose backtrace it is supposed to write. The module is deployed regardless of whether the slowlog is switched on, the permissions apply to the whole httpd_t domain and therefore to Apache httpd as well, and compiling it installs make and selinux-policy-devel on the host. The php and icingaweb2 playbooks run the policycoreutils and selinux roles for this; set the playbook's __skip_selinux variable (for example php__skip_selinux: true) to leave the host's policy untouched.
  • role:mariadb_server: The InnoDB buffer pool grows from 128 MiB to 512 MiB, so a database with more than a trivial amount of data is served from memory instead of from disk. Every host running this role therefore uses roughly 384 MiB more RAM after the next restart of the service.
  • role:mariadb_server: The InnoDB redo log grows from 32 MiB to the 96 MiB MariaDB itself ships, so a write-heavy server no longer stalls waiting for a checkpoint on a redo log sized for much smaller workloads. InnoDB resizes the log itself when the service next restarts, also after an unclean shutdown, but the data directory needs 64 MiB more free space for it; check that on hosts that are tight before deploying. Set mariadb_server__cnf_innodb_log_file_size__group_var: '32M' (or the __host_var) to keep the previous size.
  • role:mariadb_server: innodb_snapshot_isolation now defaults to OFF. Turning it on requires support from the application: a transaction in REPEATABLE READ that modifies a row another transaction changed after its snapshot was taken is aborted with ER_CHECKREAD. The application has to catch that error and retry the transaction, otherwise the write fails under concurrent load. To restore the previous behaviour on hosts whose application is known to handle it, set mariadb_server__cnf_innodb_snapshot_isolation__group_var: 'ON' (or the __host_var).
  • role:collabora: collabora__coolwsd_ssl_settings_ssl_verification and collabora__coolwsd_welcome_enable reach the deployed coolwsd.xml again, and SSL verification of the WOPI host now defaults to strict. Both variables were only wired into a few old templates, so on newer versions the value came from the package instead of from the inventory, and most packages ship verification off. A host whose WOPI host presents a self-signed or otherwise untrusted certificate needs collabora__coolwsd_ssl_settings_ssl_verification: false, otherwise its documents stop loading.
  • role:apache_httpd: mod_info is no longer enabled, so /server-info stops serving the complete Apache configuration, including the credentials of other modules. Hosts that need the endpoint re-enable the info module in their inventory via apache_httpd__mods__group_var / apache_httpd__mods__host_var.
  • role:monitoring_plugins: A source install now places the notification plugins in /usr/lib64/nagios/plugins, next to the check plugins, and removes the /usr/lib64/nagios/plugins/notifications directory it used before. This is where the shipped Icinga command definitions and the rpm/deb packages have always expected them. Adjust any command definition of your own that points into the notifications subdirectory.
  • role:redis: RHEL 10 is no longer supported, since Red Hat ships no Redis there. On RHEL 10 the role used to install Valkey under the Redis name, which aborted the run when the configuration file was deployed. Move those hosts to the valkey role: put them into the lfops_valkey inventory group and rename their redis__* variables to valkey__*. All other platforms are unaffected.
  • role:collabora: Drop support for EOL Collabora 23.05. Upgrade to 24.04 or newer.
  • role:icingaweb2_module_grafana: The graph configuration for the Linuxfabrik Monitoring Plugins is only deployed when the role is called with --tags icingaweb2_module_grafana:monitoring_plugins_graphs, matching the icingaweb2_module_director:basket tag. Run the role with that tag to update /etc/icingaweb2/modules/grafana/graphs.ini. The icingaweb2_module_grafana__skip_monitoring_plugins_graphs_config variable is gone; remove it from your inventory.

Added

  • role:fail2ban: The apache-404-matomo filter and jail work like apache-404 but for the matomo LogFormat, where the virtual host precedes the client IP in the log line.
  • role:fail2ban: The apache-404 filter accepts fail2ban__jail_apache_404_ignoreregex, a list of regular expressions whose matching log lines are excluded from the 404 count, so known missing resources like /favicon.ico or /assets/style.css no longer trigger a ban.
  • role:php: The [global] section of the PHP-FPM configuration can be set from the inventory, so the log level and the reload after repeated worker crashes are configurable; the reload is on by default after ten crashes within a minute.
  • role:fail2ban: The apache-404 filter and jail ban IPs that cause excessive HTTP 404 errors in the Apache access log, configurable via fail2ban__jail_apache_404_bantime, fail2ban__jail_apache_404_findtime and fail2ban__jail_apache_404_maxretry.
  • role:apache_solr: The maximum size of the Java heap can be configured via apache_solr__heap.
  • role:apache_solr: The Java Security Manager can be switched off via apache_solr__security_manager_enabled, for instances that have to follow symlinks pointing outside of Solr's own directories.
  • role:apache_httpd: The GELF access log carries the request protocol as its own _http_version field, so the share of traffic on HTTP/2 can be graphed per vHost in Graylog. The text log formats already contained it as part of the request line and are unchanged, because fail2ban and the Matomo log importer parse them positionally.
  • role:librenms: librenms__scheduler_service_enabled and librenms__scheduler_service_state start, stop or disable the timer of the LibreNMS scheduler on its own.
  • role:librenms: The librenms:cron, librenms:logrotate and librenms:state tags deploy the scheduled jobs, deploy the logrotate configuration and manage the service state without touching the rest of the installation.
  • role:librenms: The session cookie is marked as secure on hosts whose librenms__url is an https:// URL, so a browser only sends it over HTTPS. LibreNMS reports the missing flag as a failure in its own validation. Set librenms__config_session_secure_cookie to override.
  • role:librenms: LibreNMS stores its RRD files through RRDCached, which cuts the disk I/O of the poller by roughly a third.
  • role:librenms: The librenms:rrdcached tag deploys and configures RRDCached without touching the rest of the installation.
  • role:php: PHP-FPM pools are now fully configurable, each with its own user and group, process-manager tuning, timeouts and php_admin_value overrides. Every pool gets an isolated session directory, its own error and slow logs, and its own socket, so several applications can share a host without sharing a PHP process, a session store or a memory limit. One pool template now serves both distribution families.
  • role:php: Add meta/argument_specs.yml declaring the user-facing variables, so role-entry validation catches type mismatches and unknown variables, and an explicit vars/Ubuntu.yml.
  • role:apache_httpd: apache_httpd__mod_http2_protocols sets the protocols offered server-wide, the conf_protocols vHost key overrides it for a single vHost, and the remaining apache_httpd__mod_http2_* variables size the HTTP/2 worker pool and its per-connection buffers.
  • role:keycloak: The Keycloak log file is rotated, with keycloak__logrotate for the number of rotations kept and the keycloak:logrotate tag to deploy the configuration on its own. Until now the log grew unbounded, since Keycloak has no built-in rotation for its file log handler.
  • role:keycloak: Add keycloak__limit_nofile, keycloak__transaction_default_timeout and keycloak__transaction_setup_timeout for values that were hardcoded in the systemd unit and in keycloak.conf.
  • role:selinux: A policy module can be defined inline through the content_te subkey of selinux__modules__*_var, instead of pointing src at a directory on the Ansible controller.
  • role:openvpn_server: Add openvpn_server__service_state to start, stop, restart or reload the OpenVPN service independently of whether it is enabled at boot.
  • role:valkey: Add a role and playbook to install and configure Valkey, listening on TCP port 6379 on the loopback interfaces by default. Valkey is taken from the distribution repositories (EPEL on RHEL 8, AppStream on RHEL 9 and 10, the distribution's own repository on Debian 13 and Ubuntu 24.04 / 26.04), and the configuration template matching the installed version is deployed. Debian 12 and Ubuntu 22.04 ship no Valkey and are not supported.
  • playbook:setup_icinga2_master, playbook:setup_mastodon, playbook:setup_moodle, playbook:setup_nextcloud: These stacks install Valkey on RHEL 10 and Redis everywhere else, so they can be deployed on RHEL 10 again. Both servers speak the same protocol on the same port, so the applications are configured identically either way. Override setup_*__skip_redis / setup_*__skip_valkey (setup_icinga2_master__redis__skip_role / setup_icinga2_master__valkey__skip_role) to force a specific server or to run neither.
  • role:files: A file can opt out of the backup copy that is written before it is overwritten, via the backup subkey of files__files__*_var.
  • role:collabora: The collabora:configure tag deploys coolwsd.xml and the logrotate configuration without touching the packages.
  • role:docker: The address pools docker assigns container network subnets from (default-address-pools) can be configured.
  • role:collabora: Add support for Collabora Online CODE 26.04.1, 26.04.2 and 26.04.3, and Collabora Enterprise 24.04.18, 25.04.12 and 26.04.2.
  • role:monitoring_plugins: Deploy the bash completion file for source installs.
  • role:kvm_vm: VMs can now also be installed from an ISO or install tree instead of a prepared cloud image.
  • role:files: The files:directories, files:files and files:symlinks tags manage one kind of file system entity each, so a single directory or symlink can be deployed without touching the rest.
  • plugin:bitwarden_item: The lookup can be told not to create secrets, so a lookup that finds no matching item aborts the run instead of silently generating a new password. Set LFOPS_BITWARDEN_LOOKUP_ITEM_CREATE=false, or create = false in the [bitwarden_item_lookup] section of your ansible.cfg; the default is the previous behaviour.

Changed

  • role:php: A run aborts when a pool's request_terminate_timeout is not above its max_execution_time, instead of deploying a pool whose longer execution time is capped by PHP-FPM without saying so. Setting either to 0 still switches that limit off.
  • role:php: The logrotate configuration for the per-pool PHP-FPM logs on Debian is deployed by the php:logrotate tag instead of php:fpm.
  • role:redis: Redis also listens on the IPv6 loopback [::1]:6379, where it previously answered on 127.0.0.1 only, so clients that resolve localhost to ::1 are no longer refused. Hosts without an IPv6 loopback are unaffected: the address is marked optional, so Redis logs a warning and carries on instead of aborting.
  • role:apache_httpd: Restarting Apache takes about 5 seconds instead of 13 on a host that holds long-lived connections, such as a proxy for WebSockets, because systemd no longer waits out Apache's own shutdown escalation. Apache refuses new connections for the whole of that wait, so this shortens the outage. The hard stop leaks about three semaphores per restart (ipcs -s), which a reboot clears; raise apache_httpd__systemd_timeout_stop_sec to trade restart speed back for a longer graceful window.
  • playbook:setup_librenms: The skip variables of the playbook are all named after the playbook, setup_librenms__skip_php for example, instead of after the librenms role.
  • playbook:setup_librenms: The playbook no longer runs the apps role, since the librenms role installs git itself.
  • role:librenms: The http_fping SELinux policy module carries the rules the LibreNMS documentation now lists, so pinging a device from the web interface also works where fping uses an ICMP socket or binds a source address.
  • role:librenms: PHP GMP is installed, so rates derived from 64-bit interface counters stay exact instead of silently losing precision in float arithmetic.
  • role:librenms: The httpd_can_sendmail SELinux boolean is enabled, and httpd_can_network_connect_db in addition when the database is on another host.
  • role:librenms: The SELinux file context of /opt/librenms/cache is set.
  • role:librenms: ImageMagick is no longer installed, LibreNMS does not use it.
  • role:librenms: The http_fping SELinux policy module is deployed by the selinux role, so a playbook run that skips that role no longer installs it.
  • role:librenms: The role no longer makes the RRD, log, cache and storage directories group-writable, LibreNMS grants the access it needs itself while installing.
  • role:apache_httpd: Restarting Apache no longer takes 90 seconds on a host that holds long-lived connections, such as a proxy for WebSockets. The server now waits 3 seconds for running requests to finish instead of waiting for the last connection to close by itself and being killed by systemd. Apache stops accepting new connections for the whole of that wait, so this shortens the outage rather than extending it. Hosts with legitimately long-running requests raise apache_httpd__conf_graceful_shutdown_timeout.
  • role:apache_httpd: HTTP/2 is enabled and is the preferred protocol on every connection that terminates TLS, while a client that does not offer it is still served HTTP/1.1 and cleartext HTTP/2 (h2c) is not offered; on RedHat the mod_http2 package is installed for this.
  • role:keycloak: keycloak__https_cipher_suites, keycloak__https_protocols, keycloak__log and keycloak__proxy_trusted_addresses are YAML lists instead of comma-separated strings. A comma-separated value already in an inventory keeps working, Ansible splits it into the same list.
  • role:keycloak: The Keycloak tarball is downloaded on the Ansible controller and copied to the target from there, so a target without internet access can be installed. The controller has to reach github.com.
  • role:keycloak: --tags keycloak:configure deploys the configuration and rebuilds the server, but no longer starts the service or bootstraps the admin account. Use the keycloak tag for a full run and keycloak:state for the service state.
  • role:selinux: A policy module is only recompiled and reinstalled when its source changed, so a run against an up-to-date host no longer reports a change for every module it manages.
  • role:monitoring_plugins: A source install also deploys the *-logging.sudoers companion, which keeps the plugin calls out of the authentication log. Without it every check costs five entries there, and a monitored host runs dozens of checks a minute. A host running sudo-rs, Ubuntu 26.04 for example, does not get the file and loses it again if it had one, because sudo-rs knows none of its settings and warns about each of them on every sudo call by any user.
  • A service that depends on a kernel setting deployed by the kernel_settings role now starts after TuneD, so the setting is in place before the service reads it. Until now such a service could come up while TuneD was still applying the profile and then run with the old value until its next restart, while sysctl and tuned-adm verify already reported the new one (roles graylog_datanode, graylog_server, mariadb_server, mongodb, redis).
  • A repository file that carries mirror credentials is deployed with mode 0600 instead of 0644, so an unprivileged dnf or zypper no longer lists those repositories (all repo_* roles).
  • role:collabora: A host running a Collabora version the role has no configuration template for aborts with that version and the list of supported ones, instead of failing on a missing file.
  • role:collabora: The localhost WOPI host is an ordinary entry of collabora__coolwsd_storage_wopi__* instead of being hard-coded in the template, so it can be dropped with state: 'absent' like any other host.
  • role:php: The PHP-FPM configuration is checked with php-fpm --test before the service is restarted, so a broken pool or ini aborts the run with the error message instead of taking PHP-FPM down on the restart.

Fixed

  • role:php: A run limited to --tags php:fpm deploys the pools with the configured memory_limit, max_execution_time and post_max_size again, instead of writing them empty. php-fpm accepts the empty values without complaint, and as php_admin_value they override what php.ini sets.
  • role:nextcloud: Long web requests are no longer killed after 60 seconds, so assembling a large chunked upload completes again. The role raises max_execution_time to 3600, but PHP-FPM has terminated a request after 60 seconds since the pool rework, and its limit fired first.
  • role:monitoring_plugins_grafana_dashboards: The Grafana dashboards are collected in an empty directory on the controller. That directory was reused across runs, so the dashboard of a plugin that upstream renamed or removed kept being deployed, and a downgrade to an older Monitoring Plugins version still rolled out the dashboards of the newer one.
  • role:fail2ban: The apache-404 filter no longer produces false positives on the linuxfabrikio log format when a later field (such as bytes received %I) happens to contain 404.
  • role:librenms: The Python packages LibreNMS requires are installed, so its own validation no longer reports command_runner and psutil as missing.
  • role:librenms: An update of LibreNMS that changes the units of its scheduler takes effect, because systemd is told to read them again.
  • role:librenms: The poller works on a host whose database is not local, because the Python modules it imports are installed by the role instead of arriving through the MariaDB role.
  • role:librenms: A second run of the role updates an existing installation instead of aborting at the git checkout.
  • playbook:setup_librenms: A fresh installation no longer aborts while starting PHP-FPM.
  • playbook:setup_librenms: The SELinux file contexts for /opt/librenms are applied.
  • role:apache_httpd: Enabling an Apache module restarts httpd instead of reloading it, so the module actually takes effect. A reload loads the module but skips its initialization, which left HTTP/2 configured but silently inactive on RHEL 8 (#339).
  • role:kvm_vm: Two VMs created from the same inventory host no longer get the same MAC address, which made the second one fail with The MAC address ... is in use by another virtual machine. The generated MAC follows the VM name now. Hosts that leave kvm_vm__name at its default keep the MAC they had; on a host that sets it, a VM created from now on gets a different MAC, so check DHCP reservations and firewall rules keyed on it before recreating such a VM. Running VMs are not touched.
  • role:keycloak: A run against an unchanged host reports no changes any more. The tarball is only downloaded and extracted when the installed version differs from keycloak__version, and kc.sh build only runs when the installation or keycloak.conf actually changed, which also takes minutes off an ordinary run.
  • role:php: The PHP-FPM slowlog holds the backtrace of a slow request on RedHat, instead of staying empty while php-fpm logs failed to ptrace(ATTACH) child <pid>: Operation not permitted (1).
  • role:openvpn_server: A new server certificate, a changed server.conf or a regenerated Diffie-Hellman file restarts OpenVPN. Until now the files were written to disk while the running service kept its old configuration, so a renewed certificate only took effect at the next reboot. The certificate revocation list and the client configs still apply without a restart, since OpenVPN re-reads them per connection.
  • role:apache_httpd: Set apache_httpd__mod_ssl_ssl_use_stapling to off by default because Let's Encrypt does not provide an OCSP URL-endpoint.
  • plugin:bitwarden_item, module:bitwarden_item: A vault that is not unlocked is reported with the bw serve endpoint it was read from and the status it actually has, plus the hint that bw serve keeps the session it was started with. The previous message pointed at bw login and bw unlock, which do not reach a running bw serve.
  • plugin:bitwarden_item: Error messages no longer carry a doubled period in the middle.
  • role:rocketchat: The environment file no longer sets MONGO_OPLOG_URL, which Rocket.Chat has ignored since 5.0.1. A host without a MongoDB replica set also gets a usable environment file again, instead of one whose MongoDB URL and port ended up on the same line.
  • role:rocketchat: The container image is pulled from Docker Hub directly instead of through registry.rocket.chat, whose pull rate limit is shared by everyone using it, so image pulls and podman auto-update no longer fail with toomanyrequests.
  • role:system_update: A requested reboot names the core packages or the running services that ask for it, instead of only listing what the run changed.
  • role:system_update: A host with nothing to update no longer sends a "System updated without Reboot" mail on every update day.
  • role:system_update: The update mail and the reboot request describe the packages the run just changed instead of those of an earlier run.
  • role:system_update: The AIDE database is only refreshed when the update changed packages and the AIDE check was passing beforehand, so a host that was already reporting changes keeps reporting them instead of having them accepted as the new baseline.
  • role:system_update: The AIDE database is refreshed after the update rather than before it, on Debian and Ubuntu as well as on RHEL, so the next check no longer flags every file the update touched.
  • role:system_update: A failed update on Debian is reported and stops the run, instead of being followed by a success mail or by the reboot of a half-configured host.
  • role:schedule_reboot: The role no longer aborts while deploying its reboot helper on Debian 12 and older and on Ubuntu 24.04 and older. Roles that pull it in, system_update among them, were unusable on those releases as well.
  • role:mariadb_server: On RHEL 8, MariaDB keeps its own SELinux confinement after a package upgrade, by installing mysql-selinux the way the MariaDB packages already do on RHEL 9 and 10. Without it, applications on the same host lose their database connection with Permission denied as of MariaDB 11.4.13 and 11.8.9.
  • playbook:icingaweb2, playbook:setup_icinga2_master, role:icingaweb2 update icingaweb2 dependent vars to ensure php.ini value post_max_size > upload_max_filesize by default.
  • role:monitoring_plugins: A source install installs the dependencies of the Linuxfabrik library, so checks that speak HTTP, MySQL, SMB or WinRM no longer report Python module "httpx" is not installed and its equivalents.
  • role:monitoring_plugins: A source install deploys the event plugins, which only the rpm/deb package used to ship.
  • role:monitoring_plugins: A source install completes on a minimal installation, which has neither the Python module ansible.builtin.pip needs nor an /etc/bash_completion.d directory.
  • role:monitoring_plugins: A source install leaves the plugins, the library and the virtual environment readable and executable for the monitoring user, even when the Ansible controller runs with a hardened umask.
  • role:monitoring_plugins: A second source install run against an unchanged host no longer reports changes.
  • role:login: Removing a user that had lingering enabled no longer aborts the run.
  • role:example: The config-validation handler of the reference role triggers the restart handler it notifies; only the template new roles are copied from was affected, not any role that manages an application.
  • role:freeipa_server: Commands and command groups can be assigned to a sudo rule, through the allow_sudocmds and allow_sudocmdgroups subkeys of freeipa_server__sudorules; the former cmds and cmdgroups names never reached FreeIPA and aborted the run with Unsupported parameters.
  • role:apache_solr: __apache_solr__java_package covers the Java package required by Solr 10.
  • role:collabora: The WOPI hosts from collabora__coolwsd_storage_wopi__* reach coolwsd again. Every entry was discarded on load, and access only kept working because coolwsd trusted the first host that happened to connect. Collabora 26.04 drops that fallback, where the result would have been that no document loads at all.

v8.0.0 - 2026-07-31

Highlights: Host reboots move to one configurable maintenance window managed by the new schedule_reboot role, so system_update__update_time and the reboot-downtime settings have to be moved in the inventory. dnf_versionlock changes its variable format and no longer unlocks packages that are simply dropped from the inventory. PHP on Debian can be pinned to a declared version instead of drifting with whatever sury promotes, and a fresh installation no longer bounces its services right after starting them. Review the Breaking Changes before updating: php, mariadb_server, apache_httpd and repo_baseos all change defaults.

Breaking Changes

  • role:dnf_versionlock: Rename dnf_versionlock__versionlocks to dnf_versionlock__versionlocks__group_var / __host_var and change it from a list of strings to a list of dictionaries (name, plus the optional raw and state subkeys). The role no longer rewrites the whole lock list, so locks set elsewhere (for example by monitoring_plugins) survive, but removing an entry from the inventory no longer unlocks the package: set state: 'absent' instead.
  • role:apache_httpd: Role-internal variables are now __-prefixed. If you copied the SSL/TLS snippet from EXAMPLES.md into a vHost raw block, rename apache_httpd__openssl_certificate_path, apache_httpd__openssl_privatekey_path and apache_httpd__openssl_chain_path to their __-prefixed form, otherwise the vHost fails to render.
  • role:system_update: Host reboots are now performed at one configurable maintenance window by the new schedule_reboot role (see Added). Adjust in your inventory: system_update__update_time to schedule_reboot__reboot_time__group_var (now a plain time of day, e.g. '04:00'), and any system_update__icinga2_* reboot-downtime settings to schedule_reboot__icinga2_*. Also, in most cases system_update__update_day should be used instead of system_update__notify_and_schedule_on_calendar.
  • role:php: In preparation for the upcoming PHP 8.6, php__ini_session_cookie_httponly now defaults to On, so session cookies are marked HttpOnly and are no longer accessible to JavaScript via document.cookie. This matches the hardened session defaults PHP 8.6 ships. Applications that must read the session cookie from JavaScript have to set php__ini_session_cookie_httponly__group_var: 'Off' (or the __host_var) to restore the previous behaviour.
  • role:php: The default php__ini_opcache_blacklist_filename now points to the distribution-neutral /etc/opcache.blacklist instead of /etc/php-zts.d/opcache*.blacklist. The old default pointed at the thread-safe (ZTS) config directory, which the non-ZTS PHP-FPM this role deploys never reads. No file exists at the new path by default, so no scripts are excluded from OPcache unless an admin creates one.
  • role:apache_httpd: The Matomo log-analytics import script (import_logs.py) and the apache_httpd:matomo tag have been removed and moved to the new matomo_import_logs role. Hosts that import their access logs into Matomo, or that pipe their access logs to /usr/local/sbin/import_logs.py for realtime tracking, must now also run the matomo_import_logs role, which deploys the script. The matomo LogFormat itself stays in apache_httpd.
  • role:repo_baseos: The Rocky Linux security repository now always points at the upstream mirrorlist, even when a custom repo_baseos__mirror_url is set, so critical CVE fixes keep coming straight from upstream instead of a potentially lagging mirror. Hosts that previously pulled the security repository from their custom mirror now reach upstream directly. Set repo_baseos__security_repo_use_upstream: false to restore the previous behaviour and have the security repository follow repo_baseos__mirror_url again.
  • role:mariadb_server: The default for skip_name_resolve is now OFF instead of ON. Hosts that relied on the previous default and grant access by hostname keep working, but connections are now resolved via DNS again. Set mariadb_server__cnf_skip_name_resolve__group_var: 'ON' (or the __host_var) to restore the previous behaviour.

Added

  • role:glpi_agent: Add optional scheduled database inventory via glpi_agent__database_inventory_enabled and glpi_agent__database_inventory_login, which runs glpi-agent --partial=database as a dedicated read-only database user on a systemd timer instead of letting the always-on daemon connect as root on every cycle. glpi_agent__conf_no_category disables arbitrary inventory categories and glpi_agent__database_inventory_on_calendar sets the schedule.
  • role:php: Add php__version to declare which PHP version a Debian host runs, for example '8.4', so an ordinary apt upgrade no longer migrates the host to a new major PHP version on its own. With the sury repo enabled, the unversioned metapackages follow whatever sury currently declares as its default; declaring a version makes the role install the versioned packages, pin the php, phar and phar.phar alternatives to it, and purge the stacks of all other versions on php:update. Leave it empty to keep the previous behaviour. Has no effect on RedHat, where the module stream pins the version at repo level.
  • playbook:php: Now runs the repo_sury role on Debian (skip with php__skip_repo_sury), since sury is what makes any PHP version other than the distribution's own available in the first place.
  • role:fail2ban: Add fail2ban__filters__*_var (combined-var pattern, unique_key="filename") so custom filter definitions can be deployed from the inventory in the same generic shape as fail2ban__jails__*_var. The built-in apache-dos and portscan filters move into fail2ban__filters__role_var with no behaviour change, and can now be opted out via state: 'absent'.
  • role:postfix: Add postfix__recipient_canonicals__group_var / __host_var to rewrite recipient addresses via Postfix's recipient_canonical_maps, mirroring the existing sender canonical rewriting, which is useful for redirecting all mail addressed to a host to a central team mailbox.
  • all roles: Add lfops__skip_restart_handlers to deploy configuration changes without restarting the affected services, for example when a bounce has to wait for a maintenance window. Reload handlers still run, since a reload applies the configuration without an outage. Note that the skipped restart is not remembered: a later ordinary run finds the configuration already correct and does not restart either, so the service has to be restarted explicitly (--tags <role>:state --extra-vars '<role>__service_state=restarted'). See the README.
  • Add a service state variable (for example chrony__service_state, clamav__clamd_service_state or php__fpm_service_state) to start, stop, restart or reload the managed service independently of whether it is enabled at boot; it defaults to started when the role's matching *_service_enabled is true and to stopped otherwise, so existing inventories keep their current behaviour (apache_solr, bind, blocky, chrony, clamav, collabora, coturn, fail2ban, glpi_agent, grafana, graylog_datanode, graylog_server, icinga2_master, icinga_kubernetes, icingadb, influxdb, keepalived, opensearch, php, redis, snmp, squid, vsftpd).
  • role:duplicity: Add Debian and Ubuntu support (proven on Debian 12, Debian 13, Ubuntu 22.04, Ubuntu 24.04 and Ubuntu 26.04), and install the gnupg package itself so backups also work on minimal installs that ship without gpg.
  • role:python_venv: Add an optional per-venv pip_constraints key that pins transitive dependencies through a pip constraints file, without having to list them as direct packages.
  • role:opensearch: Add opensearch__path_repo to register file system paths as path.repo in opensearch.yml, required for file system based snapshot repositories.
  • role:nextcloud: Add nextcloud__jobs_timeout_start_sec to configure the start-up timeout of the nextcloud-jobs.service, defaulting to 10m, for instances where background jobs regularly need longer.
  • role:icinga2_agent, role:icinga2_master: Deploy a systemd drop-in override ensuring the Icinga 2 service starts after SSSD on hosts where SSSD is installed.
  • role:librenms: Add librenms__config_app_trusted_proxies and librenms__config_app_url to set the APP_TRUSTED_PROXIES and APP_URL variables in /opt/librenms/.env, needed when running LibreNMS behind a reverse proxy.
  • role:mariadb_server: Add mariadb_server__cnf_innodb_flush_neighbors__group_var / __host_var to configure the innodb_flush_neighbors InnoDB system variable, defaulting to 0, which is the recommended value for SSD and NVMe storage.
  • role:freeipa_server: Add freeipa_server__limit_groups, freeipa_server__limit_hbacrules, freeipa_server__limit_hostgroups, freeipa_server__limit_pwpolicies, freeipa_server__limit_sudocmdgroups, freeipa_server__limit_sudocmds, freeipa_server__limit_sudorules and freeipa_server__limit_users to manage only specific resources via --extra-vars, which speeds up deployments on servers with many FreeIPA resources.
  • role:vsftpd: Add vsftpd__pam_use_userdb to authenticate virtual users via pam_userdb against /etc/vsftpd/login.db, so virtual-user logins work instead of failing against the local-user PAM stack the role always rendered.
  • role:opensearch: Add opensearch__heap to set the JVM heap size via a drop-in at /etc/opensearch/jvm.options.d/heap.options, defaulting to 50% of system memory capped at 31 GB.
  • role:trend_micro_v1es: Add a role to install and activate the Trend Vision One Endpoint Security agent (Endpoint Sensor and Server & Workload Protection).
  • role:matomo_import_logs: New role that imports Apache access logs into Matomo on a schedule, one systemd timer per site, and ships the Matomo log-analytics import script (import_logs.py). The token_auth is provided via a per-site auth file instead of the command line, since --token-auth, --login and --password are visible in the process list and now log a deprecation warning. The script also supports the Traefik access-log format.
  • role:glances: Add RHEL 10 / Rocky 10 / Alma 10 support by installing glances into a Python venv via the python_venv role, since the package is not available in EPEL 10. RHEL 10 is now marked proven (x) in COMPATIBILITY.
  • role:graylog_datanode: Add graylog_datanode__http_publish_uri to set the REST API URI the DataNode advertises, needed when the bind address is not directly reachable (multiple interfaces, a NAT gateway, or a 0.0.0.0 bind address).

Changed

  • role:php: The php:update tag also deploys the PHP-FPM pools and enables and starts the FPM service, because both live under version-specific paths on Debian, so a host that changed php__version would otherwise run the new version with none of its pools and a unit that was never enabled.
  • role:fail2ban: README documents the state subkey of the filter and jail entries as optional (defaults to present), notes that raw only applies to entries using the raw template, and states up front that filters and jails are defined in the inventory.
  • role:nextcloud: Adds Debian and Ubuntu support alongside Red Hat-family systems, marked (x) in COMPATIBILITY.md since package names are verified on Debian 13 but the role is not yet proven end to end. SELinux relabeling is skipped automatically on hosts where SELinux is disabled.
  • role:apache_solr, role:blocky, role:fail2ban, role:rsyslog: The service is started after its configuration has been deployed, not before, so on a fresh installation it comes up with the configuration the role just wrote instead of starting on the package defaults and being restarted afterwards.
  • role:duplicity: Validate the role variables at start, and align the task tags with the LFOps vocabulary: the duplicity:script tag is gone (the duba script now deploys under duplicity:configure), and the new duplicity:dump tag manages the backup schedule.
  • role:schedule_reboot: Hosts without an explicit reboot window are assigned a deterministic minute within the 04:00-04:59 window, staggered by hostname, so a fleet no longer reboots in lockstep at exactly 04:00. Pin schedule_reboot__reboot_time__group_var (or the __host_var) to keep a specific window.
  • role:monitoring_plugins: A source install deploys the plugins into a self-contained Python virtual environment and provisions a suitable Python by itself, so it works on RHEL 8 where the system Python 3.6 is too old. The Linuxfabrik library is deployed newest straight from GitHub and the third-party dependencies are installed unpinned, so a source install always tracks the newest code for the selected monitoring_plugins__version. The dependencies the former source install placed into the home directories of root and the icinga user are cleaned up on the next run.
  • role:icinga2_agent: The icinga2_agent:update tag refreshes the apt cache before the upgrade on Debian-family hosts, so it reliably installs the latest package instead of running against a stale cache.
  • role:mariadb_server: Databases created via mariadb_server__databases without an explicit collation or encoding inherit the server default character set and collation (utf8mb4) instead of being pinned to the legacy utf8 / utf8_general_ci. Existing databases are unaffected; set collation / encoding per database to override.
  • role:collabora: Support Collabora Online CODE 25.04.10, which had no coolwsd.xml template and therefore aborted the deploy on hosts that had updated to it.
  • role:clamav: Send notification mails through sendmail (provided by postfix) instead of the mail command (mailx), so one invocation works across distributions and delivery no longer depends on mailx being installed.
  • role:icingadb, role:icingaweb2, role:icingaweb2_module_reporting, role:icingaweb2_module_x509, role:mariadb_server: Move the MariaDB tasks from the deprecated community.mysql collection to its replacement ansible.mysql, so the deprecation warnings printed on every run are gone and the roles keep working once community.mysql is removed upstream.

Fixed

  • A configuration change no longer restarts or reloads a service that the very same run had just started, so a fresh installation no longer bounces the service right after starting it, and no longer starts a service that is configured to stay stopped (apache_httpd, apache_solr, apache_tomcat, bind, blocky, chrony, clamav, collabora, coturn, docker, elasticsearch, fail2ban, glpi_agent, grafana, graylog_datanode, graylog_server, icinga2_master, icinga_kubernetes, icingadb, influxdb, keepalived, kibana, logstash, mariadb_server, mongodb, opensearch, php, postfix, postgresql_server, redis, rocketchat, rsyslog, snmp, squid, sshd, systemd_journald, telegraf, vsftpd).
  • role:mariadb_server, role:monitoring_plugins, role:php: The update tags refresh the apt cache before upgrading on Debian-family hosts, so they reliably install the latest packages instead of running against a stale cache. RHEL-family hosts are unaffected, since dnf refreshes its metadata on its own.
  • role:mastodon: Modules set via apache_httpd__mods__host_var in the inventory are no longer discarded, because the role used the wrong dependent variable name.
  • role:postgresql_server: The grant_option subkey of postgresql_server__privs takes effect, and the entry's roles and state subkeys are documented.
  • playbook:php, playbook:redis, playbook:setup_grav, playbook:setup_moodle: These playbooks enable EPEL (and CRB on Rocky 9 and newer) before installing packages from Remi's repository, which depend on it; on RedHat 8 the run previously aborted with nothing provides libcapstone.so.4 needed by php-opcache. Skippable via <prefix>__skip_repo_epel and <prefix>__skip_repo_baseos.
  • role:php: A dry run (--check) against a host that does not have PHP-FPM installed yet no longer aborts, so the role can be previewed before the first real run.
  • role:icingaweb2, role:icingaweb2_module_fileshipper, role:icingaweb2_module_vspheredb, role:icingaweb2_module_x509, role:nextcloud: On Debian and Ubuntu, PHP extension names are built from the PHP version the php role manages, so the unversioned php-<module> metapackages can no longer pull a second, undeclared PHP runtime onto the host whenever sury promotes a new default. RedHat is unaffected.
  • role:nextcloud: The IMAP PHP extension installs on PHP 8.4 and newer, where IMAP was removed from PHP core, by installing it from the PECL package instead of the no-longer-existing php-imap.
  • role:php: Running the role with a specific tag such as --tags php:state on Debian and Ubuntu no longer fails with an undefined PHP version, so roles that build on php and only restart php-fpm work when run with their own tags.
  • role:nextcloud: The nextcloud-ldap-show-remnants script no longer aborts the nextcloud:cron deploy with 'setup_basic__skip_mailto_root' is undefined when the role runs outside the setup_basic playbook; report recipients come from nextcloud__mail_recipients, defaulting to the global mailto_root__to.
  • role:nextcloud: Replace ws.linuxfabrik.io with www.linuxfabrik.ch, since ws.linuxfabrik.io is decommissioned.
  • role:icingaweb2_module_grafana: icingaweb2_module_grafana__auth_jwt honours a quoted 'false', which previously enabled JWT authentication and deployed the private key anyway; unquoted true / false behaved correctly before and are unaffected.
  • role:shared: lfops__remove_rpmnew_rpmsave honours an explicit opt-out, so --extra-vars='lfops__remove_rpmnew_rpmsave=false' keeps the .rpmnew, .rpmsave, .dpkg-dist and .ucf-dist files instead of removing them. Leaving the variable unset was, and still is, safe.
  • role:apache_tomcat: apache_tomcat__service_state takes effect instead of being silently ignored in favour of apache_tomcat__service_enabled; its default is started if apache_tomcat__service_enabled is true and stopped otherwise, so hosts that never set it are unaffected.
  • role:freeipa_server: The pki-tomcatd start-up timeout configured via freeipa_server__systemd_timeoutstartsec is in effect, because the role now applies the same value to systemd and to FreeIPA and reloads systemd. On slow machines ipactl start, server upgrades and CA certificate renewals previously failed with a timeout even though the CA was still coming up.
  • role:duplicity: Swift backups work out of the box on Python 3.10 and newer, since the role pins a modern oslo.* stack in the venv, which fixes the collections.Mapping crash and drops the deprecated netifaces dependency. As a result the role no longer installs a C compiler or development headers on backup hosts, which removes the build toolchain from production machines.
  • role:keycloak: Keycloak is no longer restarted a second time right after it was started on a fresh install, and a configuration change no longer starts the service on hosts that pin keycloak__state to stopped.
  • role:nextcloud: Set the text workspace_available app config key as boolean instead of string, since newer Nextcloud enforces the config lexicon and the text app declares the key as ValueType::BOOL.
  • role:system_update: The update and security-update jobs no longer send a failure mail when a mirror hiccups briefly, because repository metadata is refreshed with a few retries before updates are applied.
  • role:mod_maxminddb, role:monitoring_plugins: The role no longer aborts at start demanding a variable that has an OS-specific default (monitoring_plugins__icinga_user respectively mod_maxminddb__apache_conf_modules_d), so there is no need to set it in the inventory.
  • role:monitoring_plugins: A source install no longer aborts on RHEL 8, where the system Python 3.6 is older than the required 3.9; the role installs and uses Python 3.9 automatically.
  • role:python_venv: Install python3-packaging on EL10, which ships Python 3.12 without the stdlib distutils, so Ansible's pip module can create a venv again.
  • role:icingaweb2_module_vspheredb: Download the module tarball from the canonical archive/refs/tags/<version>.tar.gz URL, so the pinned release tag is fetched reliably.
  • role:monitoring_plugins: A source install deploys the sudoers drop-in as /etc/sudoers.d/linuxfabrik-monitoring-plugins, the same file name the packages use, and both install methods remove the drop-in under the former name, so sudo no longer warns about a duplicate Cmnd_Alias.
  • role:collect_rpmnew_rpmsave: Stop emitting an Ansible deprecation warning on every run, which keeps the role working on Ansible 2.19 and later.
  • role:kvm_vm: Use kvm_vm__connect_url for every libvirt operation, so disk resizes (virsh blockresize) and a few other steps no longer ignore the configured connection URL and act on the wrong libvirt.

Security

  • role:opensearch: The OpenSearch data directory is no longer readable by other local users; its root uses mode 0750 instead of 2755, matching the OpenSearch package default.
  • role:monitoring_plugins: A source install leaves the plugins, the bundled library and the dependency venv owned by root instead of the monitoring user, closing a local privilege escalation in which that account could edit a plugin, a library module or the venv interpreter that runs as root via sudo.

v7.0.0 - 2026-06-11

Highlights: setup_basic gains three CIS-oriented hardening roles (core_dumps, kernel_modules, login) and the sshd defaults are tightened, which stops sessions that rely on X11 or agent forwarding and can lock out clients offering more than three keys. Reboots move to one windowed mechanism in the new schedule_reboot role. Tags were renamed across a dozen roles and the MinIO roles were removed, so review your --tags invocations and any object-store backup first. RHEL 10 is now proven for the roles setup_basic runs.

Breaking Changes

  • Internal OS-specific variables are __-prefixed to mark them as not overridable from inventory. Rename any inventory override of dnf_versionlock__list_path, dnf_versionlock__packages or a role's *__icingaweb2_owner variable to the __-prefixed form; the values are unchanged (dnf_versionlock, icingaweb2_module_businessprocess, icingaweb2_module_company, icingaweb2_module_cube, icingaweb2_module_fileshipper, icingaweb2_module_generictts, icingaweb2_module_incubator, icingaweb2_module_pdfexport, icingaweb2_theme_linuxfabrik).
  • plugin:combine_lod, role:apache_httpd, role:mariadb_server, role:proxysql, role:selinux: A composite unique_key (a list of keys) now requires every component to be set on each item, instead of letting one be filled by a downstream default. Set the previously optional component explicitly: virtualhost_port on every apache_httpd vHost, host on every mariadb_server user/role, port on every proxysql server, and proto on every selinux port. Otherwise the play fails with a clear error.
  • role:apache_httpd, role:apache_tomcat, role:mastodon, role:postgresql_server: Rename tags to the project-wide naming scheme. apache_httpd:config becomes apache_httpd:configure, and apache_tomcat:users, mastodon:users, postgresql_server:users and postgresql_server:databases lose their trailing s (...:user, ...:database). Adjust any --tags / --skip-tags invocations and automation that reference the old tag names.
  • role:sshd: Ship hardened SSH defaults that change the behaviour of existing installations on the next run: X11 forwarding, agent forwarding and TCP keepalives are now off, MaxAuthTries is lowered to 3, ClientAliveCountMax to 2, and LogLevel is raised to VERBOSE. Sessions relying on X11 or agent forwarding stop working, and a client offering more than three keys from its SSH agent can be locked out. Restore the previous behaviour where needed via the new variables: sshd__x11_forwarding: true, sshd__allow_agent_forwarding: true, sshd__tcp_keep_alive: true, sshd__max_auth_tries: 6, sshd__client_alive_count_max: 3, sshd__log_level: 'INFO'. Additionally configurable are sshd__allow_tcp_forwarding and sshd__max_sessions.
  • role:apache_httpd, role:apache_solr, role:freeipa_server, role:grav, role:icingaweb2, role:influxdb, role:mariadb_server, role:mongodb, role:nextcloud, role:opensearch: Align section tags to the controlled vocabulary, which uses plural names for sections that manage multiple objects. The :user tags become :users, the :database tags become :databases, and apache_httpd:config becomes apache_httpd:configure. Adjust any --tags / --skip-tags invocations and automation that reference the old tag names.
  • role:minio_client, role:objectstore_backup: Both roles and their playbooks (playbooks/minio_client.yml, playbooks/objectstore_backup.yml) have been removed, along with the corresponding role blocks in playbooks/setup_nextcloud.yml and the setup_nextcloud__skip_minio_client / setup_nextcloud__skip_objectstore_backup variables. MinIO Server has been archived as no-longer-maintained since February 2026, and we are moving away from using object storage for critical data. Users relying on these roles must replace the MinIO-based object-store backup with their own solution (e.g. rclone); the mc binary, its config under /etc/mc/, the objectstore-backup systemd timer/service, and /usr/local/bin/mc-mirror.sh are no longer managed by lfops and will remain on existing hosts until removed manually (#241).
  • role:infomaniak_vm: Always create a managed port for every entry in infomaniak_vm__networks, even when no fixed_ip is set. Previously only networks with a fixed_ip got a managed port; networks without one relied on OpenStack's auto-created port. To avoid creating unused (but billed) managed ports on VMs provisioned under the old behavior, make sure to manually rename the existing port in OpenStack to match the port_name. Note that this port will not survive VM deletion / detachment, since it was automatically created and therefore is owned by OpenStack, not the user.
  • role:shared: The Apache httpd user and group are defined once as __shared__apache_httpd_user / __shared__apache_httpd_group and loaded into every playbook through a new global-variables.yml task in pre_tasks, instead of being repeated in the vars/ of around 20 roles. Running one of those roles ad-hoc outside the bundled playbooks now requires importing shared's global-variables.yml first. On Suse, the monitoring_plugins web files use the correct apache group www instead of wwwrun.
  • role:crypto_policy, role:duplicity, role:icingaweb2, role:icingaweb2_module_x509, role:mariadb_server, role:php: The internal package-selection dicts behind the OS-keyed default lookups are no longer overridable from inventory; they were never meant to be. Behaviour is unchanged on supported platforms.

Added

  • all roles: Role variables are validated at role entry through meta/argument_specs.yml, so a type mismatch or a missing mandatory variable in the inventory fails immediately with a clear message instead of an obscure error later in the run.
  • role:schedule_reboot: New role providing a single, windowed reboot mechanism: a request spool (/run/schedule-reboot/), an ad-hoc schedule-reboot command, and one actor that performs a single reboot for all pending requests at a configurable window (schedule_reboot__reboot_time__*), setting an Icinga downtime around it. Other roles request a reboot instead of rebooting themselves; system_update uses it.
  • role:core_dumps: New role that disables core dumps, which can leak sensitive process memory to disk, following the CIS Benchmark recommendations. Runs as part of setup_basic.
  • role:kernel_modules: New role that hardens a host by blocking rarely used or risky kernel modules (FireWire, legacy filesystems, uncommon network protocols) following the CIS Benchmark recommendations, and runs as part of setup_basic. The defaults stay clear of modules that would break common workloads such as containers, snap and USB storage.
  • role:login: New role that sets a password-aging policy and a stricter default umask in /etc/login.defs, applying to newly created accounts and password changes rather than retroactively.
  • role:chromium_headless: New role providing a hardened, socket-activated headless Chromium backend for tools such as the Icinga Web 2 PDF Export Module, started on the first request and stopped again after an idle timeout so it uses no RAM while unused. Installs chromium-headless from EPEL instead of Google's proprietary repository.
  • role:tmux: New role that installs tmux and deploys a system-wide /etc/tmux.conf with a larger scrollback buffer and mouse support. Selections are copied to the local clipboard over SSH via OSC 52 where the terminal supports it, and prefix + P dumps a pane's whole scrollback buffer to a file.
  • role:hostname: Maintains an /etc/hosts entry mapping the FQDN and short name to the host's primary IPv4 address, configurable via hostname__etc_hosts_ip and disablable with hostname__manage_etc_hosts: false.
  • role:uptimerobot, plugins/modules/uptimerobot_*: New role and nine custom modules to manage UptimeRobot resources from a playbook: uptimerobot_monitor, uptimerobot_mwindow and uptimerobot_psp for CRUD, uptimerobot_alert_contact for deletion only (UptimeRobot API v2 does not expose creating contacts), plus five read-only info modules. All CRUD modules support --check and --diff and are idempotent on re-run. Configured via uptimerobot__monitors, uptimerobot__mwindows, uptimerobot__psps and uptimerobot__alert_contacts; the API key comes from the api_key parameter, api_key_file (default ~/.uptimerobot) or UPTIMEROBOT_API_KEY.
  • plugin:platform_select: New filter plugin for selecting a value from a platform-keyed dictionary by OS family, distribution or version.
  • role:system_update: Add a security lane for Rocky Linux: a daily timer installs only Rocky Linux security hot-fixes from the dedicated security repository and requests a reboot if needed, performed at the host's maintenance window. Enabled by default, a no-op where the security repository is not enabled, and turned off with system_update__security_enabled: false.
  • role:repo_baseos: Add the Rocky Linux security repository for critical CVE fixes, enabled by default. Opt out per host or group via repo_baseos__security_repo_enabled__host_var / __group_var.
  • role:sshd: Add Debian 13 and Ubuntu 22.04 / 24.04 / 26.04 support and run on Fedora. On Debian and Ubuntu the role manages the correct service unit (ssh.service) and disables OpenSSH socket activation (ssh.socket), and Red Hat-family releases without a version-specific template fall back to a generic RedHat sshd_config template instead of failing.
  • role:icinga2_master, role:icingadb, role:icingaweb2, role:icingaweb2_module_reporting, role:icingaweb2_module_x509: Add explicit Ubuntu variable files, making Ubuntu support visible alongside Debian. The Icinga repository, GPG key and package names were verified on Debian 13 and Ubuntu 24.04.
  • role:libmaxminddb, role:mod_maxminddb: Run on Debian and Ubuntu in addition to Red Hat-family systems, with the Apache module enabled automatically on Debian and Ubuntu.
  • role:monitoring_plugins, role:repo_monitoring_plugins: Add SLES 15 and SLES 16 support, installing the Linuxfabrik Monitoring Plugins from the SUSE channel of repo.linuxfabrik.ch and applying the SUSE-specific package version lock (#245).
  • role:repo_remi: Add RHEL 10 / Rocky 10 support with a new GPG key, repo templates and module-stream tasks for EL 10.
  • role:repo_monitoring_plugins: Add repo_monitoring_plugins__testing (default false) to switch from the release to the testing channel. On Red Hat-family systems a single /etc/yum.repos.d/linuxfabrik-monitoring-plugins.repo is deployed containing both channel sections with enabled= toggled by the variable, so DNF metadata for both can stay cached across switches; on Debian and Ubuntu the -release suffix in the apt sources file is replaced with -testing.
  • role:graylog_server: Make more HTTP, Elasticsearch, processing/output buffer and message journal settings configurable via graylog_server__http_external_uri, graylog_server__http_enable_cors, graylog_server__elasticsearch_max_total_connections, graylog_server__elasticsearch_max_total_connections_per_route, graylog_server__output_batch_size, graylog_server__processbuffer_processors, graylog_server__outputbuffer_processors, graylog_server__ring_size, graylog_server__inputbuffer_ring_size, graylog_server__message_journal_max_age and graylog_server__message_journal_max_size.
  • role:graylog_datanode: Add graylog_datanode__raw, plus graylog_datanode__path_repos and graylog_datanode__node_search_cache_size to configure searchable snapshot locations and the size of the disk-based searchable snapshot cache.
  • role:graylog_datanode, role:graylog_server: Add template for Graylog 7.1.
  • role:mariadb_server: Make aria_pagecache_buffer_size, key_buffer_size and sort_buffer_size configurable via the corresponding mariadb_server__cnf_* variables, and add mariadb_server__cnf_innodb_snapshot_isolation (MariaDB 10.6+), defaulting to 'ON'.
  • role:elasticsearch: Add optional variables elasticsearch__cluster_routing_allocation_disk_watermark_flood_stage_frozen and the four corresponding *_max_headroom variables.
  • role:kibana: Add kibana__logging to make the logging: block in kibana.yml fully user-configurable (appenders, loggers, root, rotation). The default preserves the previous behaviour: JSON logs at /var/log/kibana/kibana.log, rotated daily, 14 rotations kept.
  • role:logstash: Add optional variables logstash__monitoring_cluster_uuid and logstash__monitoring_enabled.
  • role:alternatives: Support managing subcommands (slaves/followers) and the Red Hat-only family grouping, ensure the alternatives tooling is installed, and allow the role to be included without variables as a no-op.
  • role:at, role:dnf_makecache, role:open_vm_tools, role:qemu_guest_agent: Add service state variables (at__service_state, dnf_makecache__service_state and __timer_state, open_vm_tools__service_enabled and __service_state, qemu_guest_agent__service_state) to control the running state independently from boot autostart. Default behaviour is unchanged.
  • role:infomaniak_vm: Add the keep_port_on_absent subkey on infomaniak_vm__networks entries to preserve the port and its fixed IP when the VM is set to absent, so the same IP can be re-used, and port_name to override the managed port's name.
  • role:mirror: Document the per-repository newest_only subkey on mirror__reposync_repos entries, defaulting to true. Set it to false for repositories that publish multiple versions in parallel, such as Icinga.
  • role:redis: Add template for version 8.8.
  • playbooks/setup_basic: Add setup_basic__skip_policycoreutils to skip the policycoreutils role, matching the pattern used by the other roles in the playbook.

Changed

  • all roles: The role READMEs follow one standard format and explain what the underlying software actually is and when an admin would want it, instead of only naming it. Install behaviour, upgrade paths, role scope and previously undocumented variables are spelled out, and tags and variables are bullet lists instead of markdown tables.
  • COMPATIBILITY: RHEL 10 is promoted to proven (x) for the 23 roles that setup_basic exercises, Ubuntu 26.04 is added, the EOL Debian 11 and Ubuntu 20.04 columns are dropped, and roles that are expected to work but are untested are marked (x). glances stays at (x) because the package is missing in EPEL 10.
  • role:nextcloud: Automatic app updates are enabled by default (nextcloud__timer_app_update_enabled), and the scheduled update only switches Nextcloud into maintenance mode when an app update is actually pending, so an instance that is already up to date keeps serving requests. The recommended database migrations are applied afterwards, and a failed run no longer leaves the instance stuck in maintenance mode.
  • role:keycloak: The bootstrap admin credentials no longer stay in /etc/sysconfig/keycloak after the first run. The role writes them, waits for Keycloak to consume them on startup, re-renders the sysconfig file without them, and stores a state marker so subsequent runs skip the credential render; keycloak__admin_login can then be removed from the inventory. For disaster recovery, delete the marker file, re-add the variable and re-run. A -temp suffix on the initial admin username is recommended so it is obvious which account must be deleted once a permanent admin exists.
  • role:icinga2_master, role:icingadb: Validate the Icinga 2 configuration before restarting the service, so a faulty config fails the playbook run loudly instead of bouncing the daemon into a broken state and leaving Icinga 2 down.
  • role:clamav: Runs on Debian and Ubuntu in addition to Red Hat-family systems, and works on RHEL 10. The role seeds the signature database on first install so the scanner starts reliably, and runs an EICAR self-test (also available via the clamav:test tag) that confirms detection actually works.
  • role:acme_sh: Issue ECDSA P-256 certificates by default instead of RSA-4096, for faster TLS handshakes at equivalent security. Certificates previously issued as RSA are reissued as ECDSA on the next run and the superseded RSA certificate is dropped from renewal; set acme_sh__key_length to an RSA value such as 4096 to keep RSA.
  • role:mailto_root: Send the verification mails via sendmail (provided by postfix) instead of the mail (mailx) command, completing the move off mailx, so the role no longer needs the mailx package installed.
  • playbooks: Roles that target the whole RHEL family run on any enterprise distribution that is not Fedora, instead of an explicit list of major versions, which adds support for RHEL 10 and future releases without further changes. The CRB repository is now also enabled on Rocky 10, which previously left dependencies such as python3-virtualenv uninstallable.
  • role:grafana: Apply the systemd/chkconfig workaround on RHEL 10 as well, not just RHEL 9.
  • role:tools: Install the German locale package (glibc-langpack-de) on RHEL 10 as well, and no longer install tmux; use the dedicated tmux role instead, which ships a configuration with sensible defaults.
  • role:repo_baseos: The Rocky 8 security repository matches Rocky 9 and 10: it adds the disabled security-debuginfo and security-source sub-repositories, a 6-hour metadata expiry so emergency hot-fixes are noticed quickly, and the $rltype mirrorlist variable.
  • role:redis: Bump the default for net.core.somaxconn from 1024 to 4096 to match the RHEL 9 and RHEL 10 kernel default and the current Redis upstream recommendation. RHEL 9 and 10 hosts see no effective change; RHEL 8 hosts now get 4096.
  • role:monitoring_plugins: install_method: 'source' reads the per-Python-LTS lockfile under lockfiles/pyXX/requirements.txt from both the monitoring-plugins and lib repos, picking the directory that matches the target host's Python, since the previous root-level requirements.txt no longer exists upstream.
  • role:system_update: Change the default of system_update__update_time so updates are spread deterministically across 04:00-04:59, with the minute derived from inventory_hostname, instead of all hosts firing at 04:00 sharp.
  • role:apache_httpd: Bump the Core Rule Set to 4.27.0, and update the two reverse-proxy snippets in EXAMPLES.md to use ProxyPass instead of RewriteRule, which %-decodes the URI pattern and breaks WebDAV apps such as Nextcloud on rename. See the blog post.
  • role:firewall: Install nftables together with iptables for firewall__firewall == "fwbuilder" on all distros, instead of only on Fedora and RHEL 8/9.
  • role:graylog_server: Update the server.conf templates to include telemetry_enabled = false.
  • role:network: Scope the hc-utils removal task to Red Hat-family hosts, since Hetzner ships hc-utils as RPMs only. No behaviour change on either family.
  • plugin:gpg_key: Refresh the bundled GPG helper library so the module keeps working on current Python and GnuPG releases, and make the gnupghome parameter expand ~ and resolve relative paths as documented. Existing playbooks are unaffected.
  • role:motd: Update the default value of motd__legal_notice.

Removed

  • role:repo_remi: Drop support for RHEL 7 and Fedora 35, both EOL, along with their per-platform task, vars and template trees.
  • role:freeipa_client: Remove the dead-code defaults freeipa_server__config_default_shell, freeipa_server__config_password_expiration_notification, freeipa_server__domain and freeipa_server__realm from defaults/main.yml; they were never read by the role.

Fixed

  • role:repo_elasticsearch, role:repo_grafana, role:repo_graylog, role:repo_icinga, role:repo_influxdb, role:repo_mariadb, role:repo_mongodb, role:repo_monitoring_plugins, role:repo_mydumper, role:repo_opensearch, role:repo_proxysql, role:repo_redis, role:repo_sury: Refreshing the apt cache is no longer reported as a change on every run.
  • roles: Controller-side downloads and git clones delegated to localhost are no longer skipped when the first targeted host happens not to need them, which previously risked leaving later hosts without the downloaded artifact.
  • roles: Set become: false on tasks delegated to localhost across the collection, so they no longer try to call sudo on the Ansible controller and fail with sudo: a password is required where passwordless sudo is not set up (#242).
  • role:repo_remi: Enabling the php, composer and Redis module streams is idempotent, so repeated runs no longer report a change or briefly disable and re-enable the stream.
  • role:proxysql: mysql_servers entries are deduplicated by their actual address field; the merge key referenced a non-existent hostname field, so multiple backends sharing a host group and port were silently collapsed into one.
  • role:repo_influxdb: Prevent the influxdata-archive-keyring package from being installed on both Enterprise Linux and Debian, since it drops a second repo file pointing at upstream that is not managed by LFOps.
  • role:php: php-fpm workers run with a defined PATH, which previously was empty and broke PHP code that shells out to system binaries and tripped Nextcloud's "PHP getenv" setup warning.
  • role:redis: The Redis configuration file is no longer world-readable; it is deployed as root:redis with mode 0640, so a configured password can no longer be read by other local users.
  • role:acme_sh: No longer reinstalls every certificate and reloads the web server on every run; certificates are only reinstalled when they were just (re)issued or when the installed file is missing.
  • role:keycloak: The role prints a clear instruction when a re-run can no longer obtain a token because the bootstrap admin was manually switched over to a permanent account and the bootstrap marker went missing.
  • role:keycloak: Fix ownership under /opt/keycloak/data/, which the post-install build step left owned by root:root so the keycloak service user could not write into it; the build now runs as the service user and existing installations are corrected on the next run.
  • role:keycloak: Fix the transaction timeout silently dropping from 3600s to 300s on Keycloak 26.6.0 and newer, and the MariaDB database encoding defaulting to the deprecated utf8 (utf8mb3) instead of utf8mb4.
  • role:mongodb: The role aborts early with a clear message when users are defined while mongodb__conf_security_authorization is disabled, instead of failing with a confusing authentication error, and the dump config no longer writes login credentials in that case.
  • role:kernel_settings: The systemd_cpu_affinity setting is actually applied; the value was computed and shown in the debug output but never passed to the underlying system role.
  • role:icingaweb2_module_pdfexport: PDF export works out of the box, because the headless browser backend the module needs is installed and configured automatically via the new chromium_headless role instead of having to be set up by hand.
  • role:nextcloud: The nextcloud-update script owns the maintenance mode lifecycle itself instead of expecting callers to enable it beforehand, which disabled the LDAP user provider and made the before-update export silently omit LDAP users. Callers must drop the manual maintenance:mode --on step from their pre-script workflow and rely on --single-transaction for the DB dump instead.
  • role:nextcloud: Ensure that the Nextcloud OCC is executable.
  • role:graylog_server: Fix the graylog_server:configure_defaults run aborting on Graylog 7.0 and newer with Unable to map property can_be_default while creating the default index set, by removing the property; Graylog 7.x dropped it and 6.x ignored it.
  • role:graylog_server: Validate that each graylog_server__system_inputs entry sets global: true or assigns a node, which was marked mandatory but never enforced.
  • role:graylog_datanode, role:graylog_server: Validate that the password_secret is at least 16 characters long.
  • role:graylog_datanode: Fix the Conditional result ... was of type 'str' deprecation warning.
  • role:nodejs: Fix @nodejs:<stream> install failing with broken groups or modules, by resetting the module first when nodejs__dnf_module_stream is set and installing the explicit /common profile.
  • role:blocky: The validate config & restart blocky.service handler is notified when the blocky binary changes, so the service is restarted after an update.
  • role:mariadb_server: Stop writing the deprecated innodb_buffer_pool_chunk_size setting for MariaDB 10.11, 11.4 and 11.8, which ignore it and derive the chunk size from innodb_buffer_pool_size. The role aborts at the start of the run with a clear error if innodb_buffer_pool_chunk_size (on MariaDB 10.11+) or innodb_file_per_table (on MariaDB 11.0+) is still set in inventory, so an upgrade from 10.6 to 11.x does not silently keep a stale override.
  • role:mariadb_server: Fix MariaDB starting in the unconfined_service_t SELinux domain on RHEL 10, which mislabels /var/lib/mysql/mysql.sock and breaks php-fpm and httpd_t clients such as Icinga Web 2 login. The role sets the mysqld_exec_t file context persistently via semanage fcontext and restorecon, since the previous chcon workaround cannot relabel the binary under EL10's read-only /usr service sandbox.
  • role:icinga2_master: Fix the selinux role failing on RHEL 10 with SELinux boolean icinga2_can_connect_all is not defined in persistent policy, by installing nagios-selinux from EPEL first so its %post registers the types that icinga2-selinux references.
  • role:redis: Fix No package redis available. on RHEL 10, where Red Hat replaced Redis with the compatible Valkey in AppStream and Remi no longer ships Redis for EL10. The role installs valkey on EL10 and guards the Redis Stack loadmodule directives that do not exist on Valkey; EL8 and EL9 keep installing Redis unchanged and the user-facing redis__conf_* variables stay backwards-compatible.
  • role:openvpn_server: Fix invalid selinux context on RHEL 10 when deploying server.p12 and crl.pem, by using etc_t there since the openvpn_etc_t type no longer exists in the RHEL 10 core policy.
  • role:repo_epel: Fix a malformed RHEL 10 epel.repo, where a missing newline rendered enabled=0username=<login> when repo_epel__basic_auth_login was set and dnf rejected the file.
  • role:repo_mariadb: Fix dnf -y module disable mariadb failing on RHEL 10, where modularity was removed, by scoping the task and the module_hotfixes directive to RHEL 8 and 9.
  • role:infomaniak_vm: Apply the VM's security group on the ext-net1 port instead of only on the server, since Neutron enforces the port's security groups when a VM boots against a pre-created port, and stop passing security_groups to openstack.cloud.server, which failed on internal-network ports with port_security_enabled set to false.
  • role:haveged: Setting haveged__service_state: 'stopped' no longer produces the invalid systemctl command stopp, so all four valid values work as expected.
  • role:influxdb: Always install curl, which is required to start influxdb but missing as a package dependency.
  • role:redis: Add the missing paths for running against Debian.
  • role:logstash: The default logstash__java_opts sets the JVM heap size to 60% of total memory, capped at 8g.
  • role:mount: Fix the when condition for NFS/CIFS client package installation failing with multiple mounts and when the state key is undefined.
  • execution-environment: Add the missing sshpass system package, required for SSH password-based connections such as --ask-pass.
  • plugin:nextcloud_occ_app_config: An array config value is compared as JSON, so a key whose stored value already matches no longer reports a change and re-runs occ config:app:set on every run.
  • plugin:bitwarden_item: The module no longer writes to the Bitwarden vault in check mode (--check), and a run without password no longer overwrites an existing item's password.
  • plugin:sqlite_query: A failed query fails the task instead of reporting success with the error text in query_result, and a REGEXP query against a column containing NULL values no longer fails.
  • plugin:uptimerobot_*: The modules no longer crash when the UptimeRobot API returns a non-list response for a list endpoint.
  • plugin:bitwarden_item, plugin:combine_lod, plugin:gpg_key, plugin:nextcloud_occ_app_config, plugin:nextcloud_occ_system_config, plugin:uptimerobot_monitor, plugin:uptimerobot_psp: Fixed the plugin documentation so ansible-doc renders it again, and corrected the gpg_key docs, which claimed a separate python-gnupg install is required and named the returned key field wrongly.
  • playbooks/clamav, playbooks/duplicity, playbooks/fangfrisch, playbooks/influxdb, playbooks/mongodb, playbooks/python_venv: Enable repo_baseos (CRB) and repo_epel on Rocky 9 and newer before the python_venv role, to fix No match for argument: python3-virtualenv.
  • playbooks/setup_graylog_datanode, playbooks/setup_graylog_server, playbooks/setup_icinga2_master, playbooks/setup_rocketchat: Extend the repo_baseos and repo_epel conditions to Rocky and RHEL 10.
  • playbooks/freeipa_client, playbooks/freeipa_server: Set strategy: 'linear' explicitly, so the playbooks work even when the user's ansible.cfg defaults to a strategy that reuses the target Python interpreter, which otherwise fails with API.bootstrap() already called.
  • role:repo_monitoring_plugins: Add the missing run_once: true on the local repo-key download task on Red Hat platforms, so the key is downloaded once per run instead of once per host.

Security

  • plugin:gpg_key: The cleartext passphrase is no longer included in the module's failure output when key generation fails.
  • role:repo_*: HTTP basic auth credentials are only written to the repository config files when a custom mirror URL is set. Previously, setting lfops__repo_basic_auth_login without lfops__repo_mirror_url wrote the credentials into repo files that still pointed at the public vendor mirrors, so the package manager sent them to servers that do not use basic auth. The Icinga repo is intentionally unchanged, since its subscription URL legitimately requires basic auth.

v6.0.1 - 2026-04-07

Fixed

  • ci: Strip badges from README.md before publishing to Galaxy, as external images are not rendered

v6.0.0 - 2026-04-07

Breaking Changes

  • role:nfs_server: Rework nfs_server__exports from a list of strings to a list of dictionaries with new path, clients, owner, group, and mode subkeys
  • role:kvm_host: Change NAT to be explicitly activated for virtual nets
  • role:apache_httpd: Change the default to not install/enable mod_qos by default (it is no longer shipped in EPEL 10)

Added

  • Add MkDocs-based documentation site, deployed automatically to GitHub Pages via tools/build-docs and a GitHub Actions workflow
  • CONTRIBUTING: Document semantic parameter ordering for Ansible modules
  • playbooks: Add example.yml and setup_example.yml playbooks as development references
  • role:example: Add complete example role with defaults, handlers, tasks, templates, and vars as a reference for consistent role development
  • role:icingaweb2_module_grafana: Add JWT support
  • role:grafana: Add JWT support
  • Add playbooks/README.md documenting all playbooks with their roles in execution order and available skip variables
  • role:apache_httpd: Add platform-specific behavior section, wsgi example, and document localhost endpoints in README
  • role:apache_httpd: Add skip variables section to README linking to relevant playbooks
  • role:mailx: Add skip variables section to README linking to relevant playbooks
  • role:policycoreutils: Add skip variables section to README linking to relevant playbooks
  • role:yum_utils: Add skip variables section to README linking to relevant playbooks
  • plugin:bitwarden_item: Add file-based item cache to reduce bw serve API calls, preventing crashes under load. Cache is stored in $XDG_RUNTIME_DIR (RAM-backed tmpfs) with /tmp fallback. After create/edit operations, the cache is updated inline to avoid expensive full re-syncs, with a 1-second sleep as rate limit to prevent Bitwarden API errors. Convert is_unlocked to a property to fix it never being called.
  • role:freeipa_server: Add --diff support for all FreeIPA modules and add freeipa_server:configure tag
  • role:mariadb_server: Add mariadb_server__cnf_wsrep_log_conflicts and mariadb_server__cnf_wsrep_retry_autocommit variables
  • role:mariadb_server: Add mariadb_server__cnf_wsrep_gtid_mode variable to configure wsrep_gtid_mode for Galera
  • role:openvpn_server: Add openvpn_server:crl tag to allow deploying the certificate revocation list independently
  • role:nextcloud: Add Icinga2 set / unset downtime functionality to nextcloud-update.j2
  • execution-environment: Add mitogen
  • role:nfs_client: Add optional owner, group and mode subkeys for mount point directories
  • role:logstash: Add support for deploying custom grok pattern files to /etc/logstash/patterns/
  • role:mount: Add optional owner and group subkeys for mount point directories
  • role:elasticsearch: Add logrotate config for daily rotation
  • role:freeipa_server: Add the ability to specify the systemd unit start timeout
  • role:postfix: Add RHEL 10 support
  • role:kvm_vm: Add the ability to resize disks
  • role:infomaniak_vm: Add the ability to choose the deployment region/datacenter
  • role:crypto_policy: Add RHEL 10 support
  • role:elastic_agent: Add new role
  • role:elastic_agent_fleet_server: Add new role
  • role:fail2ban: Make bantime configurable for the sshd and portscan jails
  • role:duplicity: Add support for RHEL 10
  • role:php: Make request_slowlog_timeout and request_terminate_timeout configurable
  • role:graylog_server: Make http_publish_uri configurable; make trusted_proxies configurable
  • role:graylog_datanode: Add template for 7.0
  • role:graylog_server: Add template for 7.0
  • role:lvm: Add new role
  • role:logrotate: Add support for RHEL 10
  • role:sshd: Add support for RHEL 10
  • role:yum_utils: Add support for RHEL 10
  • role:repo_epel: Add support for RHEL 10
  • role:repo_baseos: Add support for RHEL 10
  • role:policycoreutils: Add support for RHEL 10
  • role:mailx: Add support for RHEL 10
  • role:graylog_server: Make message_journal_dir configurable
  • playbook:setup_basic: Add lvm role

Changed

  • ci: Publish pre-releases directly to prod Ansible Galaxy instead of galaxy-dev, since it is unreliable and pulp-ansible excludes pre-release versions from "latest"
  • Update pre-commit hooks to latest versions
  • Unify CONTRIBUTING and convert from reStructuredText to Markdown
  • roles: Add backup: true to all ansible.builtin.template tasks to ensure config file backups before overwriting
  • role:nextcloud: Refactor nextcloud-update.j2
  • role:keycloak: Rework keycloak.conf template to match Keycloak's default config structure
  • role:apache_httpd: bump Core Rule Set to 4.24.1
  • role:repo_remi: Install Composer from remi-modular repository
  • role:icingadb: Enhance config.yml template
  • role:apache_httpd: Improve output; bump Core Rule Set to 4.24.0

Fixed

  • role:apache_httpd: Fix apache_httpd__mod_security_coreruleset_version default value in README (4.4.0 -> 4.24.1), fix prefork variable names in README (spare_threads -> spare_servers), fix various typos ("best practise", "Tipp")
  • role:mailx: Fix grammar in task name ("make" -> "makes"), sort template module parameters alphabetically
  • role:policycoreutils: Fix grammar in task name ("are" -> "is")
  • plugin:bitwarden_item: Fix missing raise in multipart error handling, break instead of continue in multi-term lookup, folder_id wrongly typed as list instead of str in module, notes default mismatch between documentation and code, and wrong "lookup plugin" wording in module documentation
  • role:mirror: Fix missing 0440 permissions on sudoers file
  • role:login: Rename sudoers file from lfops_login to linuxfabrik to match the kickstart configuration; remove the old file automatically
  • roles: Fix Ansible 2.19 deprecation warning for conditional results of type int by using | length > 0 instead of | length
  • role:firewall: Fix fwbuilder repo clone being skipped when run_once picks a host without firewall__fwbuilder_repo_url
  • role:sshd: Validate sshd config with sshd -t before reloading the service
  • role:nfs_client: Fix systemd not being aware of new or removed NFS mount units
  • role:keycloak: Fix issues preventing Keycloak from starting
  • role:systemd_unit: Correct the removal of units
  • role:bind: Fix incorrect distribution version comparison in named.conf
  • role:python_venv: Fix venv path in remove venv task
  • role:apache_httpd: Prevent deployment of mods that should be disabled
  • role:repo_postgresql: Remove EOL versions, adjust for RHEL 9 & 10
  • role:mariadb_server: Fix the root cause of /run/mariadb/wsrep-start-position: No such file or directory after update of MariaDB (10.11.14 -> 10.11.15 or 11.4.8 -> 11.4.9)
  • role:ansible_init: Install Ansible Collections from requirements.txt since that file contains the correct versions for running against RHEL 8
  • role:kibana: Enable log rotation
  • role:kibana: Fix when statement
  • playbook:setup_icinga2_master: Fix syntax; add missing kernel_settings for MariaDB
  • lookup_plugin:bitwarden: Make it more robust
  • role:monitoring_plugins: Fix installation of package against non-RHEL hosts
  • role:rocketchat: Fix typo and order of calls in playbook

v5.1.0 - 2026-01-06

Added

  • role:kibana: Add kibana__raw variable
  • role:elasticsearch: Add elasticsearch__raw variable
  • role:apache_httpd: Add nice ErrorDocuments
  • role:kibana: Make SSL settings configurable

v5.0.0 - 2025-11-14

Breaking Changes

  • role:elasticsearch_oss: Rename to elasticsearch, as both the free and subscription versions are now in the same package
  • role:repo_elasticsearch_oss: Remove, as both the free and subscription versions are now in the same package

Added

  • role:acme_sh: Add acme_sh__reload_cmd to allow setting the local reload command globally for all certificates
  • role:collabora: Add new template versions
  • role:elasticsearch:
  • Make node.roles configurable
  • Add variables for allocation awareness
  • Add elasticsearch__path_data variable to configure custom data directory
  • Improve handling of TLS certificates
  • Allow creation of clusters
  • role:gitlab_ce: Make the gitlab.rb options for default project features, email reply-to address, LDAP integration and the upload path configurable
  • role:graylog_server: Re-add graylog_server__elasticsearch_hosts to allow setups without Graylog Data Node
  • role:kibana: Add new role
  • role:mariadb_server:
  • Add support for version 11.8 (LTS)
  • Make log_slave_updates configurable
  • Add mariadb_server__cnf_server_raw variable
  • role:podman_containers: Add option to enable the podman-auto-update.timer
  • role:postfix: Add postfix__lookup_tables__*_var to allow easy deployment of lookup tables
  • role:redis: Add template for version 8.2
  • role:selinux:
  • Add handling of SELinux modules
  • Add capability to run restorecon
  • Add selinux__policy variable
  • role:shell: Add shell__limit_cmds to limit executed shell commands
  • playbook:selinux: Add selinux__skip_policycoreutils variable

Fixed

  • role:acme_sh: Fix certificate paths for Ubuntu and Debian
  • role:apache_solr: Automatically install the correct Java version
  • role:elasticsearch:
  • Prevent undefined variable error
  • Fix default of elasticsearch__path_data
  • Set vm.swappiness to 1
  • role:firewall: Ensure firewalld is installed if chosen
  • role:icinga2_agent: Deploy logrotate config as hotfix for upstream issue (#188)
  • role:icinga2_master: Deploy logrotate config as hotfix for upstream issue (#189)
  • role:icingaweb2: Fix Icinga username for Debian
  • role:keycloak: Install correct Java version, removing the keycloak__java_package_name variable
  • role:kvm_vm: Fix path
  • role:mariadb_server: Fix /run/mariadb/wsrep-start-position: No such file or directory after update
  • role:mastodon: Adjust to breaking changes in elasticsearch role
  • role:monitoring_plugins:
  • Also install lib via source if monitoring_plugins__install_method: 'source' is set
  • Add workaround for pip on Debian & Ubuntu
  • role:openvpn_server: Actually remove CCD with state: 'absent'
  • role:repo_mariadb: Fix handling of GPG key for Debian & Ubuntu
  • role:repo_opensearch: Deploy correct GPG key for selected OpenSearch version
  • role:rocketchat: Fix syntax of HealthCmd
  • playbook:opensearch: Prevent the whole cluster from restarting at once
  • playbook:setup_icinga2_master:
  • Fix order
  • Add missing injection for MariaDB Python modules

v4.0.0 - 2025-10-03

Breaking Changes

  • role:icinga2_master: Remove support for IDO, as it is deprecated in favor of IcingaDB. The following variables can be removed from the inventory:
  • icinga2_master__database_enable_ha
  • icinga2_master__database_host
  • icinga2_master__database_login
  • icinga2_master__database_name
  • role:icingaweb2_module_monitoring: Remove, as it is deprecated in favor of IcingaDB. All variables starting with icingaweb2_module_monitoring__ can be removed from the inventory.
  • role:mariadb_server:
  • Remove support for EOL version 10.5
  • Remove mariadb_server__cnf_expire_logs_days__group_var / mariadb_server__cnf_expire_logs_days__host_var, use mariadb_server__cnf_binlog_expire_logs_seconds__group_var / mariadb_server__cnf_binlog_expire_logs_seconds__host_var instead

Added

  • role:acme_sh: Add support for Debian/Ubuntu
  • role:apache_httpd: Add support for Debian/Ubuntu
  • role:elasticsearch_oss: Add elasticsearch_oss__discovery_type, elasticsearch_oss__network_host variables; reset JVM tmp directory
  • role:icingaweb2_module_pdfexport: Add new role
  • role:kvm_host: Add support for Ubuntu 24.04
  • role:mastodon: Add new role
  • role:mongodb: Add RedHat config template for v8.0
  • role:moodle: Add moodle__version variable to select the major and minor version
  • role:postgresql_server: Add postgresql_server__login_password variable
  • role:repo_mydumper: Add official repos for Debian-based systems
  • role:system_update: Add metadata_timer_sync option for cache-only installations
  • tool:particle: Add new tool

Changed

  • role:gitlab_ce: Update template to v18.4.0
  • role:mariadb_server:
  • Create a backup file of the most important config files before applying new versions
  • Make ownership of SSL certificate CIS-conform
  • role:monitoring_plugins: Remove monitoring_plugins__skip_notification_plugins__*_var variables as they are now always installed
  • role:systemd_journald: Move config file to /etc/systemd/journald.conf.d/z00-linuxfabrik.conf, improve calculations and default values

Fixed

  • role:apache_httpd:
  • Use platform-specific group for htpasswd files
  • Allow unsetting the CustomLog directive
  • role:apache_tomcat: Adjust logrotate config for multiple Tomcat instances
  • role:bind:
  • Do not run named-checkzone against forward zones
  • Remove obsolete options for RHEL 9
  • role:duplicity: Use python3.11 to prevent errors when installing latest duplicity
  • role:elasticsearch_oss: Move tmpdir to a location with exec permissions specified by CIS hardening
  • role:keycloak: Set keycloak__proxy_trusted_addresses to '127.0.0.1' due to FD leak if using '127.0.0.1,::1'
  • role:mariadb_server:
  • Correct mydumper dependency packages for Debian-based systems
  • Fix failing dumps after mydumper update to v0.20.1
  • Adjust SELinux settings after upgrades
  • Grant binlog monitor privilege for mariadb-backup user
  • role:monitoring_plugins:
  • Fix path to old sudoers file
  • Fix script execution in CIS-hardened /tmp
  • Improve versionlock and install SELinux package on RHEL
  • role:nextcloud: Add missing env module
  • role:repo_opensearch: Fix GPG key

v3.0.0 - 2025-06-13

Breaking Changes

  • role:apache_httpd:
  • Change conf_server_alias from a string to a list
  • Change default of the authz_document_root vHost variable from Require local to Require all granted. This is a more sensible default, as allowed_file_extensions is used to restrict the access.
  • Remove the authz_file_extensions vHost variable. Access to listed file extensions is now always allowed.
  • Fix a bug that allowed access to dotfiles which had extensions listed in allowed_file_extensions. Make sure this does not break your application, or set allow_accessing_dotfiles: true.
  • Change default of apache_httpd__skip_mod_security_coreruleset from false to true
  • role:apache_tomcat:
  • Rename apache_tomcat__skip_manager to apache_tomcat__skip_admin_webapps
  • Change apache_tomcat__users__*_var from a simple list to a list of dictionaries
  • role:borg_local: Add new mandatory variable borg_local__passphrase
  • role:collabora:
  • Change collabora__coolwsd_storage_wopi__*_var to a list of dictionaries from a list of strings
  • Change collabora__language_packages__*_var to a list of dictionaries from a list of strings
  • Rename collabora__coolwsd_allowed_languages to collabora__coolwsd_allowed_languages__*_var and change it to a list of dictionaries from a list of strings
  • role:fangfrisch: Remove malwarepatrol as it is discontinued (see https://malwareblocklist.org/)
  • role:grafana: Change default value for grafana__serve_from_sub_path from true to false
  • role:graylog_server:
  • Remove support for Graylog < 5.0
  • Only support Graylog 6.1+ (Graylog Data Node based installations). Currently no more support for dedicated OpenSearch or Elasticsearch.
  • Rename graylog_server__admin_user to graylog_server__root_user
  • role:icinga_kubernetes: Switch config to v0.3.0 multi-cluster format, remove icinga_kubernetes__kubeconfig_path
  • role:icingadb: Split into two roles, one for the IcingaDB daemon and one for IcingaDB Web. Have a look at the variables in the READMEs. Generally it is enough to rename icingadb__api_user_login to icingadb_web__api_user_login.
  • role:icingaweb2_module_director: The icingaweb2_module_director:basket tag only runs if explicitly called to prevent accidental config overwrites
  • role:icingaweb2_module_vspheredb: Remove the v prefix from the icingaweb2_module_vspheredb__version variable to be consistent with the other icingaweb2_module_* roles
  • role:kvm_vm: Change kvm_vm__boot_uefi (bool) to kvm_vm__boot (string)
  • role:login: Change default of remove_other_sshd_authorized_keys from true to false
  • role:mailto_root:
  • Move most functionality to role:postfix, remove the mailto_root:configure and mailto_root:testmail tags
  • Change mailto_root__from from optional to mandatory
  • Testmail to external addresses now uses sender address (mailto_root__from)
  • role:mariadb_client: Remove (use the apps role instead)
  • role:mariadb_server:
  • Remove support for EOL versions 10.3 and 10.4
  • Remove support for non-LTS versions
  • Change default of mariadb_server__cnf_client_ssl_verify_server_cert__*_var for versions lower than 10.11 from true to false to prevent errors when SSL is disabled
  • module:bitwarden_item, lookup_plugin:bitwarden:
  • Remove parameters password_uppercase, password_lowercase, password_numeric, password_special
  • Add parameter password_choice
  • role:mongodb: Change mongodb__conf_net_bind_ip from a string to a list of strings. For example: ```yaml # old mongodb__conf_net_bind_ip: '0.0.0.0'

# new mongodb__conf_net_bind_ip: - '0.0.0.0' * **role:monitoring_plugins**: * Remove variables: * `monitoring_plugins__pip_executable` * `monitoring_plugins__pip_package` * `monitoring_plugins__python__modules` * `monitoring_plugins__windows_variant` * The `lfops__monitoring_plugins_version` variable (and all the `*.monitoring_plugin.*_version` variables) now only accepts a specific release or the value `dev`. `stable` or `latest` are no longer supported. * The `lfops__monitoring_plugins_version` variable is now mandatory. * Rename `monitoring_plugins__linux_variant` to `monitoring_plugins__install_method`: * `monitoring_plugins__linux_variant: 'python'` becomes `monitoring_plugins__install_method: 'source'` * Rename `monitoring_plugins__repo_version` to `monitoring_plugins__version`: * `monitoring_plugins__repo_version: 'latest'` becomes `monitoring_plugins__version: 'dev'` * Remove the tasks for Nuitka compilation, as the compilation is done by the [Monitoring Plugins GitHub Action](https://github.com/Linuxfabrik/monitoring-plugins/actions/workflows/nuitka-compile.yml) now * Lock the version of the `monitoring-plugins` package after installing it. Updating the plugins should be done manually along with updating the monitoring system configuration. * **role:monitoring_plugins_grafana_dashboards**: Change from provisioning to grizzly for the deployment of the dashboards * **role:mount**: Change `mount__mounts` to `mount__mounts__host_var` / `mount__mounts__group_var` * **role:nextcloud**: * Rename `nextcloud__apps_config` to `nextcloud__app_configs__*_var`, add `state` subkey, make more use of the `value` subkey. `--value` is no longer required:yaml # old nextcloud__apps_config: - { key: 'core', value: 'shareapi_default_expire_date --value=yes' } # new nextcloud__app_configs__host_var: - key: 'core shareapi_default_expire_date' value: 'yes' state: 'present' * Rename `nextcloud__apps` to `nextcloud__apps__*_var`, add `state` subkey * Rename `nextcloud__sysconfig` to `nextcloud__sysconfig__*_var`, add `state` subkey, make more use of the `value` subkey (same as `nextcloud__app_configs__*_var`) * Remove `nextcloud__proxyconfig`. Use `nextcloud__sysconfig__*_var` instead. * Implement [notify_push](https://github.com/nextcloud/notify_push). Add the following to your Apache HTTPd config:apacheconf RewriteRule ^\/push\/ws(.) ws://nextcloud-server:7867/ws$1 [proxy,last] RewriteRule ^\/push\/(.) http://nextcloud-server:7867/$1 [proxy,last] ProxyPassReverse /push/ http://nextcloud-server:7867/ `` * Change default ofnextcloud__timer_app_update_enabledfromtruetofalse, as this can sometimes lead to Nextcloud ending up in maintenance mode * Renamenextcloud__apache_httpd__vhosts_virtualhost_iptonextcloud__vhost_virtualhost_ip* Renamenextcloud__apache_httpd__vhosts_virtualhost_porttonextcloud__vhost_virtualhost_port* **role:opensearch**: * Change default ofopensearch__plugins_security_disabledfromtruetofalse* For new installations of OpenSearch 2.12 and later, you must define a custom admin password inopensearch__opensearch_initial_admin_password* **role:openssl**: Remove (use theappsrole instead) * **role:perl**: Remove (use theappsrole instead) * **role:postfix**: Now completely templates the whole config file. Beware when running against existing hosts. * **role:postgresql_server**: Rename thenamesubkey ofpostgresql_server__users___vartousernamefor consistency and easier integration of the Bitwarden lookup plugin * **role:python**: Changepython__modules___varto a list of dictionaries from a list of strings * **role:redis**: * Drop support for Redis v5 (end of life) * Drop support for Redis v6 * Change default ofredis__service_timeout_start_secandredis__service_timeout_stop_secfrom5sto90s* **role:repo_icinga**: * Removerepo_icinga__use_subscription_urlfor RHEL (and compatibles) as the packages without a subscription are outdated. The variable is now only effective for openSUSE and SLES. * Renamerepo_icinga__subscription_logintorepo_icinga__basic_auth_loginand add a variable to explicitly use the Icinga Repo Subscription URL (repo_icinga__use_subscription_url). If you haverepo_icinga__subscription_loginset in your inventory, rename it torepo_icinga__basic_auth_loginand setrepo_icinga__use_subscription_url: truefor the same effect. * **role:repo_mydumper**: Adjust to use https://repo.linuxfabrik.ch/mydumper/ by default. Removerepo_mydumper__baseurl, addrepo_mydumper__mirror_urlinstead. * **role:rocketchat**: * Switch deployment method from native installation to Podman container * Removerocketchat__npm_versionvariable * Rename and alter: *rocketchat__application_pathtorocketchat__user_home_directory(new default:'/opt/rocketchat') *rocketchat__service_enabledtorocketchat__container_enabled*rocketchat__service_statetorocketchat__container_state* Change default ofrocketchat__mongodb_hostto'host.containers.internal'* Remove Rocket.Chat notifications from the default banaction * **role:selinux**: Changeportssubkey ofselinux__ports__*_vartoport, accepting only a single port or port range, not a list * **role:sshd**: * Removesshd__ciphers,sshd__kexandsshd__macsvariables, as these settings are managed bycrypto-policyon RHEL * Now deploy the complete/etc/ssh/sshd_configas a template * Remove support for RHEL 7 * **role:system_update**: Removesystem_update__icinga2_mastervariable. Usesystem_update__icinga2_api_urlinstead. * **role:systemd_journald**: The value forsystemd_journald__conf_system_max_useis now interpreted as a size in bytes. It supports the size specifications possible injournald.conf(e.g.4G). If you want to specify a percentage, use'40%'. * **role:tar**: Remove (use theappsrole instead) * **playbook:icinga2_agent**: Change to also include the installation of the [Linuxfabrik Monitoring Plugins](https://github.com/Linuxfabrik/monitoring-plugins). This can be skipped by settingicinga2_agent__skip_monitoring_plugins: true. * **playbook:setup_icinga2_master**: * Change default ofsetup_icinga2_master__icingaweb2_module_company__skip_rolefromfalsetotrue* Change the format of the role skip-variables fromplaybook_name_skip_role_nametoplaybook_name__role_name__skip_rolefor clarity and consistency. Have a look at the [README.md](./README.md#skipping-roles-in-a-playbook). * Addplaybook_name__role_name__skip_role_injectionsvariables to disable or re-enable the role's injections * Change default ofsetup_icinga2_master__skip_icingaweb2_module_monitoringfromfalsetotrue`

Added

  • role:nextcloud: Add nextcloud_occ_*_config modules with diff and check mode support
  • role:alternatives: Add new role
  • role:apache_httpd:
  • Add some mods
  • Add skip_allowed_file_extensions vHost variable
  • Add skip_allowed_http_methods vHost variable
  • role:apache_solr: Add new role
  • role:audit: Add more config variables
  • role:bind:
  • Add multiple new variables, now allowing a primary-secondary setup
  • Add bind__named_conf_raw variable
  • role:blocky: Add new role
  • role:borg_local: Add new role
  • role:clamav: Add new role
  • role:cloud_init: Add task to remove /etc/cloud/cloud.cfg.rpmsave
  • role:collect_rpmnew_rpmsave: Add new role
  • role:dnf_versionlock: Add new role
  • role:duplicity: Add duplicity__backup_full_if_older_than variable
  • role:fangfrisch: Add new role
  • role:firewall: Add firewall__firewalld_ports__*_var and firewall__firewalld_services__*_var variables
  • role:github_project_createrepo: Add new role
  • role:glpi_agent: Add new role
  • role:grafana: Add creation of service accounts and their tokens
  • role:grafana_grizzly: Add new role
  • role:graylog_datanode: Add new role
  • role:graylog_server: Add variables and documentation for multi-node setup; add Debian support
  • role:icinga2_agent: Add icinga2_agent:update tag; add icinga2_agent__validate_certs variable
  • role:icinga2_master: Add icinga2_master__bind_host variable
  • role:icinga_kubernetes: Add new role
  • role:icinga_kubernetes_web: Add new role
  • role:icingadb: Add new role
  • role:icingaweb2_module_businessprocess: Add new role
  • role:icingaweb2_module_cube: Add new role
  • role:icingaweb2_module_fileshipper: Add new role
  • role:icingaweb2_module_generictts: Add new role
  • role:icingaweb2_module_jira: Add new role
  • role:icingaweb2_module_reporting: Add new role
  • role:icingaweb2_module_x509: Add icingaweb2_module_x509__url variable
  • role:kvm_vm: Add the option to boot the VM with UEFI
  • role:logrotate: Add compression
  • role:mariadb_server:
  • Add mariadb_server__cnf_wsrep_sst_auth and mariadb_server__cnf_wsrep_sst_method variables
  • Add mariadb_server__cnf_extra_max_connections__*_var and mariadb_server__cnf_extra_port__*_var variables
  • Add support for client and server TLS
  • Add Galera cluster installation
  • Make datadir configurable, including copy of old data to the new location
  • Make socket configurable
  • role:mirror: Add new role
  • role:mongodb:
  • Add Debian support
  • Add keyfile handling
  • Adjust for replica set across members
  • Implement user management (fix #89)
  • role:moodle: Add new role
  • role:mount: Add new role
  • role:opensearch: Add Debian support; add variables for cluster configuration
  • role:php: Add tag php:fpm
  • role:podman_containers: Add new role
  • role:proxysql: Add new role
  • role:python_venv:
  • Allow specifying different certificate store
  • Allow specifying the Python executable to be used in the venv
  • Add Debian support
  • role:repo_baseos: Add AlmaLinux 8 support
  • role:repo_epel: Add repo_epel__epel_cisco_openh264_enabled variable
  • role:repo_gitlab_runner: Add new role
  • role:repo_graylog: Add Debian support
  • role:repo_mongodb: Add Debian support
  • role:repo_opensearch: Add Debian support
  • role:repo_proxysql: Add new role
  • role:repo_redis: Add new role
  • role:repo_rpmfusion: Add new role
  • role:selinux: Add support for SELinux ports
  • role:shell: Add new role; add option to ignore errors during command execution
  • role:system_update: Add option -y to yum check-update
  • role:systemd_journald: Add variable systemd_journald__conf_system_keep_free; make SystemMaxUse configurable
  • role:systemd_unit: Add support for mount units
  • role:tools: Add tools__prompt_use_fqdn variable
  • playbook:setup_basic: Add support for AlmaLinux 8

Changed

  • role:apache_httpd: Change default of the conf_custom_log vHost variable from unset to 'logs/{{ conf_server_name }}-access.log linuxfabrikio'
  • role:graylog_server: Remove version defaults from the role
  • role:icingaweb2_module_grafana: Change GitHub repo from Mikesch-mp to NETWAYS
  • role:mariadb_server: mariadb-dump checks for the mydumper version and sets parameters accordingly
  • role:open_vm_tools: Start and enable vmtoolsd
  • role:opensearch: Make opensearch__version* optional

Fixed

  • role:influxdb: Fix wrong systemd service name, which was preventing InfluxDB dumps from being scheduled
  • role:mariadb_server:
  • Fix handler when bind_address is not localhost
  • Add installation of missing package for mariabackup Galera SST
  • Fix clone-datadir against new Galera cluster
  • role:redis: Fix various messages from log, fix v7 template settings, fix various comments and README

v2.0.1 - 2023-02-28

Changed

v2.0.0 - 2023-02-28

Breaking Changes

  • All roles: Rename all injectable variables:
  • rolename__combined_varname to rolename__varname__combined_var
  • rolename__dependent_varname to rolename__varname__dependent_var
  • rolename__group_varname to rolename__varname__group_var
  • rolename__host_varname to rolename__varname__host_var
  • rolename__role_varname to rolename__varname__role_var
  • role:acme_sh:
  • Add name subkey to acme_sh__certificates
  • Move acme_sh__reload_cmd to a subkey of acme_sh__certificates
  • role:chrony: Fix wrong variable prefix: adjust chrony_server__ to chrony__
  • role:collabora: Rename rolename and vars from collabora_code to collabora
  • role:duplicity:
  • Rename duplicity__public_master_long_keyid to duplicity__gpg_encrypt_master_key
  • Rename duplicity__public_master_key to duplicity__gpg_encrypt_master_key_block
  • Change the format of duplicity__backup_sources__host_var
  • role:fail2ban: Adjust subkeys of fail2ban__jails__group_var / fail2ban__jails__host_var
  • role:git: Add and later remove in favor of a more general apps role
  • role:hostname:
  • Rename hostname__domain_name to hostname__domain_part
  • Rename hostname__hostname to hostname__full_hostname
  • role:icinga2_agent:
  • Add new mandatory variable icinga2_agent__icinga2_master_cn
  • Make icinga2_agent__icinga2_master_host optional
  • Most users can replace all instances of icinga2_agent__icinga2_master_host with icinga2_agent__icinga2_master_cn
  • role:infomaniak_vm:
  • Rename infomaniak_vm__password to infomaniak_vm__api_password
  • Rename infomaniak_vm__project_id to infomaniak_vm__api_project_id
  • Rename infomaniak_vm__username to infomaniak_vm__api_username
  • Rename infomaniak_vm__volume_size to infomaniak_vm__separate_boot_volume_size
  • role:java: Remove, better substituted by the apps role
  • role:kernel_settings: Make kernel_settings__ variables injection-capable via kernel_settings__host_*, kernel_settings__group_* and kernel_settings__dependent_*
  • role:libselinux_python: Rename the role to policycoreutils
  • role:login: Change logic and rename login__users to two combined variables login__users__group_var (define users in group vars) and login__users__host_var (define users in host vars)
  • role:mariadb_server:
  • Rename mariadb_server__admin_login to mariadb_server__admin_user
  • Move mariadb_server__admin_host to mariadb_server__admin_user["host"]
  • Rename mariadb_server__dump_login to mariadb_server__dump_user
  • Move mariadb_server__dump_user_* to subkeys in mariadb_server__dump_user
  • role:monitoring_plugins: Rename monitoring_plugins__deploy_notification_plugins to monitoring_plugins__skip_notification_plugins and flip the logic
  • role:php: Make more variables injectable, therefore the variables have a new name
  • role:stig: Move to a new GitHub repo (temporarily)
  • role:system_update: Rename variables (note: old and new names appear identical in the original CHANGELOG, likely a documentation error):
  • system_update__mail_recipients_new_configfiles => system_update__mail_recipients_new_configfiles
  • system_update__mail_recipients_updates => system_update__mail_recipients_updates
  • system_update__mail_from => system_update__mail_from
  • system_update__mail_subject_prefix => system_update__mail_subject_prefix
  • system_update__notify_and_schedule_on_calendar => system_update__notify_and_schedule_on_calendar
  • playbook:basic_setup: Rename to setup_basic to be consistent with the other setup playbooks. Remove audit and crypto_policy roles for now.

Added

  • This CHANGELOG
  • role:acme_sh: Add new role
  • role:ansible_init: Add new role
  • role:apache_httpd: Add new role
  • role:apache_tomcat: Add new role
  • role:apps: Add new role
  • role:at: Add new role
  • role:audit: Add new role
  • role:bind: Add new role
  • role:chrony: Add new role
  • role:cloud_init: Add new role
  • role:cockpit: Add new role
  • role:collabora: Add new role
  • role:coturn: Add new role
  • role:crypto_policy: Add new role
  • role:dnf_makecache: Add new role
  • role:docker: Add new role
  • role:elasticsearch_oss: Add new role
  • role:exoscale_vm: Add new role
  • role:fail2ban: Add new role
  • role:firewall: Add new role
  • role:freeipa_client: Add new role
  • role:freeipa_server: Add new role
  • role:glances: Add new role
  • role:grafana: Add new role
  • role:grav: Add new role
  • role:graylog_server: Add new role
  • role:haveged: Add new role
  • role:hetzner_vm: Add new role
  • role:hostname: Add new role
  • role:icinga2_agent: Add new role
  • role:icinga2_master: Add new role
  • role:icingaweb2: Add new role
  • role:icingaweb2_module_company: Add new role
  • role:icingaweb2_module_director: Add new role
  • role:icingaweb2_module_doc: Add new role
  • role:icingaweb2_module_grafana: Add new role
  • role:icingaweb2_module_incubator: Add new role
  • role:icingaweb2_module_monitoring: Add new role
  • role:icingaweb2_module_vspheredb: Add new role
  • role:influxdb: Add new role
  • role:infomaniak_vm: Add new role
  • role:kdump: Add new role
  • role:keepalived: Add new role
  • role:kernel_settings: Add new role
  • role:keycloak: Add new role
  • role:kvm_host: Add new role
  • role:kvm_vm: Add new role
  • role:libmaxminddb: Add new role
  • role:librenms: Add new role
  • role:libreoffice: Add new role
  • role:login: Add new role
  • role:mailto_root: Add new role
  • role:mariadb_client: Add new role
  • role:mariadb_server: Add new role
  • role:maxmind_geoip: Add new role
  • role:minio_client: Add new role
  • role:mod_maxminddb: Add new role
  • role:mongodb: Add new role
  • role:motd: Add new role
  • role:network: Add new role; add functionality to configure network connections
  • role:nextcloud: Add new role
  • role:nfs_client: Add new role
  • role:nfs_server: Add new role
  • role:nodejs: Add new role
  • role:objectstore_backup: Add new role
  • role:open_vm_tools: Add new role
  • role:openssl: Add new role
  • role:openvpn_server: Add new role
  • role:perl: Add new role
  • role:php: Add new role
  • role:policycoreutils: Add new role
  • role:postgresql_server: Add new role
  • role:qemu_guest_agent: Add new role
  • role:redis: Add new role
  • role:repo_baseos: Add new role
  • role:repo_collabora: Add new role
  • role:repo_collabora_code: Add new role
  • role:repo_debian_base: Add new role
  • role:repo_docker: Add new role
  • role:repo_elasticsearch_oss: Add new role
  • role:repo_gitlab_ce: Add new role
  • role:repo_grafana: Add new role
  • role:repo_icinga: Add new role
  • role:repo_influxdb: Add new role
  • role:repo_mariadb: Add new role
  • role:repo_mongodb: Add new role
  • role:repo_monitoring_plugins: Add new role
  • role:repo_mydumper: Add new role
  • role:repo_postgresql: Add new role
  • role:repo_remi: Add new role
  • role:repo_sury: Add new role
  • role:rocketchat: Add new role
  • role:rsyslog: Add new role
  • role:snmp: Add new role
  • role:sshd: Add new role
  • role:stig: Add new role
  • role:system_update: Add new role
  • role:systemd_journald: Add new role
  • role:systemd_unit: Add new role
  • role:tar: Add new role
  • role:telegraf: Add new role
  • role:timezone: Add new role
  • role:unattended_upgrades: Add new role
  • role:wordpress: Add new role
  • role:yum_utils: Add new role

Changed

  • module_util:bitwarden: Switch to the Bitwarden client API, as it is more reliable than using the command line tool directly
  • role:acme_sh: Automatically update acme.sh (fix #74)
  • role:apache_tomcat: Use the correct Java version depending on Tomcat version (fix #82)
  • role:duplicity: Implement massive-parallel backups
  • role:hetzner_vm: Improve handling of IP addresses (new Hetzner features) (fix #72); manage the provider firewall (fix #71)
  • role:login: Add a switch to be aggressive or not (fix #65)
  • role:mariadb_server: Implement mydumper / adapt to the LFOps standards (fix #56)
  • role:mongodb: Implement dumping / user management (fix #78)
  • role:python: On RHEL 8+, don't install python3. Instead install python38 or python39 explicitly (fix #62)
  • role:tools: Show distro in prompt (fix #47)

Fixed

  • role:audit: Fix wrong README (fix #51, fix #58)
  • role:crypto_policy: Fix wrong README (fix #52, fix #76)
  • role:icinga2_agent: On Debian, user nagios does not exist when certs folder is created (fix #77)
  • role:icinga2_master: Fix missing option name in icinga2_master/tasks/main.yml (fix #105)
  • role:monitoring_plugins: Fix "deploy" vs "skip" logic (fix #103)
  • role:repo_graylog: Fix repo_graylog__mirror_url never actually being used (fix #94)
  • role:sshd: Fix ModuleNotFoundError: No module named 'seobject' (fix #53)
  • playbook:basic_setup: Fix Failed to set locale, defaulting to C.UTF-8 (fix #55)
  • Do not use become: true in all playbooks (fix #66)
  • Deploy nft in basic-setup or the fwbuilder role (fix #61)
  • role:freeipa_server: Fix In unattended mode you need to provide at least -r, -p and -a options (fix #83)

v1.0.1 - 2022-03-17

Changed

  • Adjust tags for Ansible Galaxy

v1.0.0 - 2022-03-17

Added

  • role:duplicity: Add new role
  • role:monitoring_plugins: Add new role
  • role:python_venv: Add new role
  • role:repo_epel: Add new role
  • module:bitwarden_item: Add new module
  • module:gpg_key: Add new module
  • lookup_plugin:bitwarden: Add new lookup plugin
  • module_util:bitwarden: Add new module util
  • module_util:gnupg: Add new module util