{"id":14984538,"url":"https://github.com/linuxfabrik/lfops","last_synced_at":"2026-01-06T17:23:37.641Z","repository":{"id":37452768,"uuid":"457700403","full_name":"Linuxfabrik/lfops","owner":"Linuxfabrik","description":"LFOps is an Ansible Collection of generic Roles, Playbooks and Plugins for managing Linux-based Cloud Infrastructures.","archived":false,"fork":false,"pushed_at":"2024-04-26T15:16:33.000Z","size":3364,"stargazers_count":38,"open_issues_count":35,"forks_count":10,"subscribers_count":6,"default_branch":"main","last_synced_at":"2024-05-01T11:35:05.701Z","etag":null,"topics":["ansible","ansible-playbooks","ansible-plugins","ansible-roles","cloud","data-center","debops","lfops","linux","linuxfabrik","playbook","self-hosted","sysadmin","sysadmin-tool"],"latest_commit_sha":null,"homepage":"https://linuxfabrik.ch","language":"Jinja","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"unlicense","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Linuxfabrik.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.rst","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"linuxfabrik"}},"created_at":"2022-02-10T08:52:10.000Z","updated_at":"2024-05-02T15:51:45.840Z","dependencies_parsed_at":"2024-05-02T15:51:44.792Z","dependency_job_id":"e2ac61a1-b4c1-41d1-8e70-82d2de6f1d4e","html_url":"https://github.com/Linuxfabrik/lfops","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Linuxfabrik%2Flfops","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Linuxfabrik%2Flfops/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Linuxfabrik%2Flfops/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Linuxfabrik%2Flfops/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Linuxfabrik","download_url":"https://codeload.github.com/Linuxfabrik/lfops/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248298832,"owners_count":21080411,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ansible","ansible-playbooks","ansible-plugins","ansible-roles","cloud","data-center","debops","lfops","linux","linuxfabrik","playbook","self-hosted","sysadmin","sysadmin-tool"],"created_at":"2024-09-24T14:09:14.126Z","updated_at":"2026-01-06T17:23:37.635Z","avatar_url":"https://github.com/Linuxfabrik.png","language":"Jinja","readme":"# LFOps - Ansible Collection of Roles, Playbooks and Plugins for managing Linux-based Cloud Infrastructures\n\n## The Purpose of LFOps\n\nLFOps is like [DebOps](https://docs.debops.org/) a collection of *Free and Open Source tools that allow users to bootstrap and manage an IT infrastructure based on* RHEL and other operating systems. *Ansible is used as the main configuration management platform.* LFOps *provides a collection of Ansible roles that manage various services, as well as a set of Ansible playbooks that tie them together in a highly integrated environment.*\n\nLFOps is designed to be used within the Linuxfabrik. Nevertheless, we try to keep its general-purpose as much as possible.\n\n\n## Installation\n\nInstall the current version of the collection (requires ansible \u003e= 2.10):\n```bash\n# via HTTPS\nansible-galaxy collection install git+https://github.com/Linuxfabrik/lfops.git\n\n# via SSH\nansible-galaxy collection install git@github.com:Linuxfabrik/lfops.git\n```\n\nTo use the git repository directly (just for development purposes):\n```bash\ngit clone git@github.com:Linuxfabrik/lfops.git\nmkdir -p ~/.ansible/collections/ansible_collections/linuxfabrik/\nln -s /path/to/lfops ~/.ansible/collections/ansible_collections/linuxfabrik/\n```\n\n## How to use LFOps\n\nExample: If you want to run `playbooks/php.yml`, place your host `myhost` in the `lfops_php` group. After that, run:\n\n```bash\nansible-playbook --inventory path/to/inventory linuxfabrik.lfops.php --limit myhost\n```\n\nFor more details on group names, Ansible tags, etc., see the playbooks and README files for the roles.\n\n\n## A typical Workflow Example\n\nFirst, add `myhost` to the corresponding groups in your Ansible inventory.\n\n```yaml\n[lfops_hetzner_vm]\nmyhost\n\n[lfops_setup_basic]\nmyhost\n\n[lfops_monitoring_plugins]\nmyhost\n\n[lfops_setup_nextcloud]\nmyhost\n```\n\nAfter that run the corresponding playbooks (optionally append parameters like `--diff` and/or `--check`):\n\n```bash\nansible-playbook --inventory path/to/inventory linuxfabrik.lfops.hetzner_vm --limit myhost\n```\n\nRun the basic setup:\n\n```bash\nansible-playbook --inventory path/to/inventory linuxfabrik.lfops.setup_basic --limit myhost\n```\n\nDeploy a component:\n\n```bash\nansible-playbook --inventory path/to/inventory linuxfabrik.lfops.monitoring_plugins --limit myhost\n```\n\nDeploy a full-fledged application (playbooks for complex application setups are prefixed by `setup_`):\n\n```bash\nansible-playbook --inventory path/to/inventory linuxfabrik.lfops.setup_nextcloud --limit myhost\n```\n\nChange some settings afterwards, for example in PHP:\n\n```bash\nansible-playbook --inventory path/to/inventory linuxfabrik.lfops.setup_nextcloud --limit myhost --tags php\n```\n\n\n## Compatibility List\n\nWhich Ansible role is proven to run on which OS? See [COMPATIBILTY](https://github.com/Linuxfabrik/LFOps/blob/main/COMPATIBILITY.md)\n\n\n## Skipping Roles in a Playbook\n\nNote: this is currently only implemented in this form in the `setup_icinga2_master` playbook.\n\nThe playbooks offer the option to skip roles based on variables that can be set in the inventory. For example to skip the setup of IcingaWeb2 for Icinga2 master, set `setup_icinga2_master__icingaweb2__skip_role: true`.\n\nSetting this also disables the injections coming from the `icingaweb2` role. Normally, the `icingaweb2` role injects databases and users to the `mariadb_server` role. This is now disabled. To re-activate this behaviour, also set `setup_icinga2_master__icingaweb2__skip_injections: false`. This is useful when one wants to run MariaDB and IcingaWeb2 on different hosts.\n\nIn short:\n\n* `playbook_name__role_name__skip_role`:\n    * Skips the role and disables the role's injections.\n    * Have a look at the playbook for the default value.\n\n* `playbook_name__role_name__skip_role_injections`:\n    * Disables or re-enables the role's injections. Takes priority over  `playbook_name__role_name__skip_role`.\n    * Defaults to `playbook_name__role_name__skip_role` for ease of use.\n    * Have a look at the playbook for the affected injections.\n\n\n## Bitwarden\n\nRequires the [bw CLI](https://bitwarden.com/help/article/cli/) version v2022.9.0+.\n\nIf you want to use Bitwarden as your password manager backend, do a `lookup` in your inventory like this:\n\n```yaml\ngrafana_grizzly__grafana_service_account_login:\n  \"{{ lookup('linuxfabrik.lfops.bitwarden_item',\n    {\n      'hostname': inventory_hostname,\n      'purpose': 'Grafana Service Account Token',\n      'username': 'grizzly',\n      'collection_id': lfops__bitwarden_collection_id,\n      'organization_id': lfops__bitwarden_organization_id,\n    },\n  ) }}\"\n```\n\nBefore running Ansible, unlock the access to your Bitwarden vault and start the Bitwarden RESTful API webserver as follows:\n\n```bash\nexport BW_SESSION=\"$(bw unlock --raw)\"\nbw status | jq\nbw serve --hostname 127.0.0.1 --port 8087 \u0026\n```\n\nAfter that run your playbook as usual:\n\n```bash\nansible-playbook ...\n```\n\nThe LFOps Bitwarden module will fetch the item from the vault and create it if it does not exist. See `ansible-doc -t lookup linuxfabrik.lfops.bitwarden_item` for all the details.\n\nThe lookup normally returns multiple keys, including the `username` and `password` subkeys. If only the password is required, use the following lookup:\n\n```yaml\nfreeipa_server__directory_manager_password:\n  \"{{ lookup('linuxfabrik.lfops.bitwarden_item',\n    {\n      'hostname': inventory_hostname,\n      'purpose': 'FreeIPA',\n      'username': 'cn=Directory Manager',\n      'collection_id': lfops__bitwarden_collection_id,\n      'organization_id': lfops__bitwarden_organization_id,\n    },\n  )['password'] }}\"\n```\n\nBeware that if you are using the lookup in `group_vars`, you probably do not want to use inventory_hostname. For example, the following would create a new login for each FreeIPA client:\n\n```yaml\nfreeipa_server__ipa_admin_password:\n  \"{{ lookup('linuxfabrik.lfops.bitwarden_item',\n    {\n      'hostname': inventory_hostname,\n      'purpose': 'FreeIPA',\n      'username': 'admin',\n      'collection_id': lfops__bitwarden_collection_id,\n      'organization_id': lfops__bitwarden_organization_id,\n    },\n  )['password'] }}\"\n```\n\nInstead, replace `inventory_hostname` with the correct FreeIPA server hostname:\n\n```yaml\nfreeipa_server__ipa_admin_password:\n  \"{{ lookup('linuxfabrik.lfops.bitwarden_item',\n    {\n      'hostname': 'freeipa.example.com',\n      'purpose': 'FreeIPA',\n      'username': 'admin',\n      'collection_id': lfops__bitwarden_collection_id,\n      'organization_id': lfops__bitwarden_organization_id,\n    },\n  )['password'] }}\"\n```\n\n\n## Documentation\n\n* Ansible Roles: Each role has its own README file.\n* Ansible Plugins: The documentation for all plugins is available through `ansible-doc`. For example, `ansible-doc linuxfabrik.lfops.gpg_key` shows the documentation for the GPG key managing module.\n\n\n## The \"all\" Playbook\n\nImagine that you want to deploy an updated MariaDB dump script to all hosts that have a MariaDB server. This would mean that you would need to run not only the `linuxfabrik.lfops.mariadb_server` playbook, but also all playbooks that include MariaDB Server, e.g. `linuxfabrik.lfops.setup_wordpress`, etc. To simplify this, you can simply use the `linuxfabrik.lfops.all` playbook, which imports all other playbooks. Make sure you use it with `--tags` and `--limit` to get the desired effect.\n\n\n## LFOps-wide Variables\n\nIt would sometimes be convenient to allow the user to set a default for multiple roles. However, since we strictly prefix all our variables with the role name, this is not that straightforward. Instead, we provide a handful of variables prefixed with `lfops__` that act as the default for multiple roles. It is, of course, still possible to overwrite the LFOps-wide variable with the role-specific one (for example, the value of `icingaweb2_module_director__monitoring_plugins_version` takes precedence over that of `lfops__monitoring_plugins_version`).\n\n### `lfops__monitoring_plugins_version`\n\nThis variable is used as the default whenever the version of the [Linuxfabrik Monitoring Plugins](https://github.com/Linuxfabrik/monitoring-plugins) is required. For example, it is used to deploy the correct version of the Director Basket and Grafana Dashboards in the `icingaweb2_module_director` and `icingaweb2_module_grafana` roles, respectively. For documentation of the value, have a look at the  `monitoring_plugins__version` variable in the [monitoring_plugins role README](https://github.com/Linuxfabrik/lfops/blob/main/roles/monitoring_plugins/README.md).\n\nExample:\n```yaml\nlfops__monitoring_plugins_version: 'dev'\n```\n\n### `lfops__remove_rpmnew_rpmsave`\n\nThis variable aims to simplify the management of rpmnew and rpmsave files (and their Debian equivalents) by allowing the admin to remove them with LFOps. The workflow would be to adjust the template in LFOps according to the new config file, then deploy with `--extra-vars='lfops__remove_rpmnew_rpmsave=true'` to update the config and remove the rpmnew / rpmsave in one run.\n\n### `lfops__repo_basic_auth_login`\n\nThis variable is used as the default across all `repo_*` roles if it is set. Can be used to authenticate against the repository server using HTTP basic auth. Have a look at the respective role's README for details.\n\nNote: Currently this only works for RPM repositories.\n\nExample:\n```yaml\nlfops__repo_basic_auth_login:\n  username: 'mirror-user'\n  password: 'linuxfabrik'\n```\n\n### `lfops__repo_mirror_url`\n\nThis variable is used as the default across all `repo_*` roles if it is set. Can be used to set the URL to a custom mirror server providing the repository. Have a look at the respective role's README for details.\n\nExample:\n```yaml\nlfops__repo_mirror_url: 'https://mirror.example.com'\n```\n\n## Tips, Tricks \u0026 Troubleshooting\n\nQ: **ansible_become: true**\n\nA: Don't use `become: true` or `ansible_become: true` in role playbooks. Instead, set `ansible_become: true` in your group_vars or host_vars ONLY (not in `all.yml` - `localhost` must not be part of the group. Otherwise you'll get errors like `sudo: a password is required`).\n\n\nQ: **Finding all groups a host belongs to**\n\nA: When running playbooks against a host it might be useful to know all the group memberships.\n\n```bash\nansible --inventory path/to/inventory myhost -m debug -a \"var=group_names\"\n```\n\nQ: **Connecting as an unprivileged user, correct sudoers config**\n\nA: When connecting as an unprivileged user, you must make sure that the user is allowed to change to all other user accounts, not just root.\nOtherwise it will be impossible to run tasks as other unprivileged users, for example `become_user: 'apache'`.\nThis means that the Runas_Spec in sudoers must be `(ALL)`, for example:\n\n```\nansible-user ALL=(ALL) NOPASSWD: ALL\n```\nor\n```\nansible-user ALL=(ALL) ALL\n```\n\n\nQ: **Finding out which playbooks ran against a host**\n\nA: All playbooks log every run to `/var/log/linuxfabrik-lfops.log` on the host. For example:\n\n```\n2024-05-23 11:15:26.604794 - Playbook linuxfabrik.lfops.apps: START\n2024-05-23 11:15:32.877064 - Playbook linuxfabrik.lfops.apps: END\n```\n\n\nQ: **Debian: fatal: [myhost]: FAILED! =\u003e changed=false - msg: No package matching '...' is available**\n\nA: Run `apt update` before running the specific role.\n\n\nQ: **[WARNING]: Collection x.y does not support Ansible version 2.16.xx**\n\nA: Install a newer Ansible version, and update all collections from Ansible Galaxy. For example:\n\n```bash\npython3 -m pip uninstall ansible-core ansible-lint ansible-compat ansible-navigator\n```\n\n```bash\npython3 -m venv ~/venvs/ansible-2.18\nsource ~/venvs/ansible-2.18/bin/activate\npip install --upgrade pip\npython3 -m pip install ansible-core~=2.18.0\n```\n\n```bash\nansible-galaxy collection list\nansible-galaxy collection list \\\n  | awk '($1 !~ /^#|^Collection|^-+$/ \u0026\u0026 NF) {print $1}' \\\n  | sort -u \\\n  | xargs -n1 -r ansible-galaxy collection install --upgrade\n```\n","funding_links":["https://github.com/sponsors/linuxfabrik"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flinuxfabrik%2Flfops","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flinuxfabrik%2Flfops","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flinuxfabrik%2Flfops/lists"}