A set of tasks that must be run in the just created machines, before anything else will happen.
Go to file
Andrea Dell'Amico 76eab10a4f
First commit. Some tasks from basic-system-setup have been moved here.
2026-02-23 10:47:58 +01:00
defaults First commit. Some tasks from basic-system-setup have been moved here. 2026-02-23 10:47:58 +01:00
files First commit. Some tasks from basic-system-setup have been moved here. 2026-02-23 10:47:58 +01:00
handlers First commit. Some tasks from basic-system-setup have been moved here. 2026-02-23 10:47:58 +01:00
meta First commit. Some tasks from basic-system-setup have been moved here. 2026-02-23 10:47:58 +01:00
tasks First commit. Some tasks from basic-system-setup have been moved here. 2026-02-23 10:47:58 +01:00
templates First commit. Some tasks from basic-system-setup have been moved here. 2026-02-23 10:47:58 +01:00
tests First commit. Some tasks from basic-system-setup have been moved here. 2026-02-23 10:47:58 +01:00
vars Initial commit 2026-02-21 12:31:20 +01:00
.ansible-lint First commit. Some tasks from basic-system-setup have been moved here. 2026-02-23 10:47:58 +01:00
.gitignore Exclude some directories. 2026-02-23 10:40:37 +01:00
LICENSE Initial commit 2026-02-21 12:31:20 +01:00
README.md First commit. Some tasks from basic-system-setup have been moved here. 2026-02-23 10:47:58 +01:00

README.md

os-bootstrap

An Ansible role that performs early-stage OS bootstrapping for Linux servers. It runs before any role dependencies (rsyslog, firewall, NTP, etc.) and establishes the baseline system state: locale, timezone, hostname, package prerequisites, network configuration, disk management, sysctl tuning, and PKI infrastructure.

This role is designed to be the first dependency of higher-level roles such as basic-system-setup.

Requirements

  • Ansible >= 2.9
  • Python 3 on target hosts (this role installs additional Python packages needed by subsequent Ansible tasks)

Ansible Collections Required

ansible-galaxy collection install ansible.posix
ansible-galaxy collection install community.general

Supported Platforms

  • Ubuntu 20.04 (Focal), 22.04 (Jammy), 24.04 (Noble)
  • Debian 11 (Bullseye), 12 (Bookworm)
  • RHEL / CentOS Stream / Rocky Linux / AlmaLinux 8, 9, 10

Task Descriptions

Tasks run in the following order:

Task File Description Condition
http_client_proxy.yml Configures system-wide HTTP/HTTPS proxy environment variables enable_env_proxy
ansible-python3-pkgs.yml Installs Python 3 packages required by Ansible modules always
hostname.yml Sets the system hostname from inventory explicitly_set_hostname
locale.yml Generates and configures system locales always
timezone.yml Sets the system timezone always
etchosts-customizations.yml Adds custom entries to /etc/hosts always
network-interfaces.yml Configures additional network interfaces via Netplan (Ubuntu) ubuntu_configure_additional_interfaces
additional_disks.yml Partitions, formats, and mounts additional disks additional_disks
swap_device.yml Configures a swap device swap_device
external_repos_el.yml Installs EPEL and optional elrepo repositories RedHat family only
basic_setup_el.yml EL/RedHat package install, SELinux configuration, service management RedHat family only
deb_general.yml Debian/Ubuntu package install, apt proxy, unattended upgrades, service cleanup Debian family only
sysctl.yml Writes custom kernel parameters to /etc/sysctl.d/ always
grub_cmdline_parameters.yml Appends parameters to GRUB_CMDLINE_LINUX configure_grub_cmdline_parameters
pki_dir.yml Creates the PKI directory hierarchy always
self_signed_certificate.yml Generates a self-signed certificate with mkcert letsencrypt_acme_install is defined and true
trusted_ca.yml Installs Lets Encrypt and custom CA certificates into the system trust store always
certificate_from_private_ca.yml Requests a certificate from a private CA (mkcert) mkcert_create_certificate and no Lets Encrypt

Sub-tasks for deb_general.yml

Task File Description Condition
apt_proxy.yml Configures APT proxy in /etc/apt/apt.conf.d/02proxy use_apt_proxy
dist_upgrade.yml Performs a full distribution upgrade dist_upgrade
packages_deb.yml Installs common and additional packages always
remove_unneeded_pkgs.yml Removes unwanted packages (exim, snapd, lxd, etc.) always
pubkeys.yml Manages root SSH authorized keys manage_root_ssh_keys
unattended_upgrades.yml Configures unattended-upgrades for automatic security updates always
disable_services.yml Disables unwanted services disable_some_not_needed_services

Role Variables

Timezone and Locale

timezone: Europe/Rome

default_locale_lang: en_US.UTF-8
default_deb_locale_messages: C.UTF-8
default_el_locale_messages: en_US.UTF-8

locales_list:
  - { name: "{{ default_locale_lang }}" }
  - { name: en_US.UTF-8 }
  - { name: en_US }
  - { name: it_IT.UTF-8 }
  - { name: it_IT }

Hostname and /etc/hosts

explicitly_set_hostname: true
domain_name: "{{ ansible_domain }}"

# Inline block of hosts entries, e.g.:
# "192.168.1.10 host1.example.com host1"
custom_etc_hosts_entries: ""
custom_etc_hosts_entries_adjunct: ""

Network Interfaces (Ubuntu / Netplan)

ubuntu_configure_additional_interfaces: false
ubuntu_configure_additional_int_dhcp_overrides: true
ubuntu_configure_additional_ints_list: []
# Example:
# ubuntu_configure_additional_ints_list:
#   - name: eth1
#     dhcp4: true

disable_ipv6: false
ipv6_sysctl_value: 1
ipv6_sysctl_file: /etc/sysctl.d/10-ipv6-disable.conf

Sysctl

sysctl_custom_file: /etc/sysctl.d/90-custom-values.conf
sysctl_opts_reload: true
sysctl_custom_file_state: present

# Only name and value are mandatory
sysctl_custom_options: []
# - name: 'net.nf_conntrack_max'
#   value: '32768'
#   sysctlfile: '{{ sysctl_custom_file }}'
#   sysctl_reload: '{{ sysctl_opts_reload }}'
#   sysctlfile_state: '{{ sysctl_custom_file_state }}'

GRUB

configure_grub_cmdline_parameters: false
grub_cmdline_additional_parameters: ""
# Example: "intel_iommu=on quiet"

Additional Disks

additional_disks: false
disks_and_mountpoints_list: []
# - mountpoint: '/data'
#   device: 'xvda3'
#   fstype: 'xfs'
#   opts: 'noatime'
#   state: 'mounted'
#   create_filesystem: true

Swap Device

swap_device: false
swap_device_name: /dev/vdxxxxx

HTTP Client Proxy

enable_env_proxy: false
env_proxy_http_host: localhost
env_proxy_http_port: "3128"
env_proxy_http_protocol: http
env_proxy_https_protocol: "{{ env_proxy_http_protocol }}"
env_proxy_http_url: "{{ env_proxy_http_protocol }}://{{ env_proxy_http_host }}:{{ env_proxy_http_port }}"
env_proxy_https_url: "{{ env_proxy_http_url }}"
env_proxy_use_authentication: false
env_proxy_username: ""
env_proxy_password: ""
no_proxy_targets:
  - ::1
  - 127.0.0.1
  - localhost

Python 3 Packages for Ansible

ansible_python3_debs:
  - python3-lxml

ansible_python3_el:
  - python3-lxml

PKI Directory and Certificates

pki_dir: /etc/pki
pki_subdirs:
  - certs
  - keys

pki_install_a_custom_ca: false

# Self-signed certificate paths (used when letsencrypt is not available)
self_signed_cert: "{{ pki_dir }}/selfsigned/cert"
self_signed_fullchain: "{{ pki_dir }}/selfsigned/fullchain"
self_signed_key: "{{ pki_dir }}/selfsigned/privkey"
self_signed_subject: /CN={{ ansible_fqdn }} self signed

# Certificate from private CA (mkcert)
mkcert_create_certificate: false
mkcert_cert_name: "{{ ansible_fqdn }}.pem"
mkcert_cert_dest_path: "{{ pki_dir }}/certs"
mkcert_key_name: "{{ ansible_fqdn }}-key.pem"
mkcert_key_dest_path: "{{ pki_dir }}/keys"
mkcert_dsn_and_ip_list: "{{ ansible_fqdn }} {% for ip in ansible_all_ipv4_addresses %}{{ ip }} {% endfor %}"
mkcert_ca_host: localhost

Trusted CA Certificates

trusted_ca_el_anchors_path: /etc/pki/ca-trust/source/anchors
trusted_ca_deb_path: /usr/local/share/ca-certificates

# Let's Encrypt intermediate CAs (normally already trusted by the OS)
trusted_ca_letsencrypt_install: false
trusted_ca_letsencrypt_ca_certificates_url: https://letsencrypt.org/certs

# Additional custom CAs to install
trusted_ca_additional_ca_files: []
# - { ca_url: 'https://example.com/foo-ca.pem', ca: 'foo-ca.pem', name: 'foo-ca' }

EL/RedHat — External Repositories

centos_install_epel: true
centos_epel_repo_url: epel-release
centos_install_release_scl: false

rh_install_elrepo: false

EL/RedHat — Basic Setup

centos_pkg_state: latest
centos_packages_cleanup: true

# SELinux
selinux_policy_type: targeted
selinux_policy_state: enforcing
centos_selinux_daemons_dump_core: false

# Services
centos_disable_avahi: true
centos_remove_avahi: false
centos_disable_networkmanager: false
centos_remove_networkmanager: false
centos_services_to_be_disabled:
  - acpid

# DNS (optional, for static resolver configuration)
centos_set_dns_servers: false
dns1: 208.67.220.220
dns2: 208.67.222.222

# Root SSH keys
manage_root_ssh_keys: true

Debian/Ubuntu — Package Management

use_apt_proxy: false
apt_proxy_url: http://localhost:3128

dist_upgrade: false

pkg_state: present
common_packages:
  - acl
  - curl
  - wget
  - htop
  - vim-tiny
  - psmisc
  - tcpdump
  - lsof
  - strace
  - rsync
  - unzip
  - tree
  - bash-completion
  - sudo
  - less
  # ... see defaults/main.yml for the full list

# Additional packages (define in your playbook or group_vars)
# additional_packages:
#   - pkg1
#   - pkg2

Debian/Ubuntu — Package Cleanup

cleanup_base_packages: true
base_packages_to_remove:
  - ppp
  - at
  - snapd

cleanup_exim_email_server: true
disable_apport_service: true
ubuntu_remove_lxd: true

Debian/Ubuntu — Unattended Upgrades

unatt_allowed_origins:
  - ${distro_id}:${distro_codename}-security
unatt_autofix: "true"
unatt_minimalsteps: "false"
unatt_install_on_shutdown: "false"
unatt_email_on_error: "false"
unatt_autoremove: "true"
unatt_autoreboot: "false"
unatt_autoreboot_time: now

Debian/Ubuntu — Service Management

disable_some_not_needed_services: false
services_to_be_disabled:
  - rpcbind
  - atd
  - acpid

Dependencies

None. This role is intentionally dependency-free so it can run before any other role.

Example Playbook

Normally you do not invoke os-bootstrap directly — it is pulled in automatically as a dependency. If you need to run it standalone:

---
- hosts: servers
  become: true
  roles:
    - role: adellam.os_bootstrap
      vars:
        timezone: Europe/Rome
        explicitly_set_hostname: true
        disable_ipv6: false
        sysctl_custom_options:
          - name: net.nf_conntrack_max
            value: "65536"

With proxy and extra disk

---
- hosts: servers
  become: true
  roles:
    - role: adellam.os_bootstrap
      vars:
        enable_env_proxy: true
        env_proxy_http_host: proxy.example.com
        env_proxy_http_port: "3128"
        additional_disks: true
        disks_and_mountpoints_list:
          - mountpoint: /data
            device: sdb1
            fstype: xfs
            opts: noatime
            state: mounted
            create_filesystem: true

EL with custom SELinux and EPEL

---
- hosts: el_servers
  become: true
  roles:
    - role: adellam.os_bootstrap
      vars:
        centos_install_epel: true
        selinux_policy_state: enforcing
        selinux_policy_type: targeted
        centos_pkg_state: latest

Testing

source ~/ansible/ansible6/bin/activate
ansible-lint

Basic test playbook is in tests/test.yml.

License

EUPL-1.2

Author Information

Andrea DellAmico andrea.dellamico@isti.cnr.it

ISTI-CNR, Pisa, Italy