Automatically configure and update your Raspberry PI with Ansible scripts

Elvis Ciotti
4 min readApr 11, 2021
Ansible logo

Ansible is a simple to use but yet very powerful free software to provision and configure operating systems.

With it, you can basically YAML config file with everything you want installed and configured inside the raspberry (list of packages, fstab, crontab entries, samba config, DHCP config, ssh authorized keys, customs scripts..), and just run it to apply the changes.

With one command (ansible-playbook ~/your-config.yaml), Ansible will check your playbook (the YAML file) and install/update only what’s missing. This is extremely useful when you want to make a change, and a big time saver if you need to reinstall, upgrade, or move SD card.

It also supports handlers with which you can reload the related service (e.g Samba) if its config (shared dir) changed.

Example

Here is a piece of the template I use to:

  • Mount an external USB disk into `/ext-disk`
  • Install and configure Samba sharing the disk and the pi home as R/W (and also to restart samba if the config is updated)
  • Switch off audio and wifi at startup
  • Set static IP and DNS
  • Set SSH authorized keys
  • Shutdown at 2am (Useful to save energy if you have a digital time to switch the power off after 2 am and switch it on back the next day when you normally start using it)
  • Every month launch a script to clean logs, upgrade packages and the raspberry OS
# Run with `ansible-playbook ~/raspberry-config.yaml`
- hosts: raspberry
gather_facts: no
remote_user: root
tasks:
- name: Install packages
apt:
update_cache: yes
autoremove: yes
state: present
pkg:
- samba
- samba-common-bin
- smbclient
- python-mako
- vim

- name: "reset cron"
shell: "crontab -r || echo already clean"
tags: [ cron ]

- file: { path: /ext-disk, state: directory }
tags: [ disk ]

- name: '/etc/fstab'
lineinfile:
path: /etc/fstab
line: 'UUID=240A-1CED /ext-disk vfat auto,nofail,noatime,rw,exec,uid=plex,gid=plex,nouser,async 0 0'
regexp: ^.*\/ext-disk
register: fstab
tags: [ disk, fstab ]

- name: audio off
lineinfile:
path: /boot/config.txt
line: 'dtparam=audio=off'
state: present
tags: [ audio ]

- name: static ip
copy:
dest: /etc/dhcpcd.conf
owner: root
group: root
mode: 0664
content: |
hostname
clientid
persistent
option rapid_commit
option domain_name_servers, domain_name, domain_search, host_name
option classless_static_routes
option interface_mtu
require dhcp_server_identifier
slaac private
interface wlan0
static ip_address=192.168.0.14/24
static routers=192.168.0.1
static domain_name_servers=8.8.8.8
tags: [ network ]

- name: samba config
blockinfile:
path: /etc/samba/smb.conf
block: |
[Films]
path = /ext-disk
read only = no
public = no
writable = yes
create mask=0644
directory mark=0755
force user = root
[pi]
path = /home/pi
read only = no
public = no
writable = yes
create mask=0644
directory mark=0755
force user = root
notify:
- restart samba
tags: [ samba ]

- name: "authorise SSH key mac 13 e 15"
copy:
dest: /root/.ssh/authorized_keys
content: |
ssh-rsa copy me from your local ~/.ssh/id_rsa.pub
ssh-rsa copy me from your local ~/.ssh/id_rsa.pub
ssh-rsa copy me from your local ~/.ssh/id_rsa.pub
tags: [ ssh ]

- cron:
name: "shutdown wifi at startup time"
special_time: reboot
user: root
job: "ifdown wlan0; ifconfig wlan0 down"
state: present
tags: [ cron ]

- cron:
name: "shutdown at 2am"
minute: "0"
hour: "2"
user: root
job: "/sbin/shutdown -P now"
tags: [ cron ]

- cron:
name: "every month at 1am launch raspi-clean-and-update.sh"
minute: "0"
hour: "1"
day: 1
user: root
job: "/bin/sh /usr/local/bin/raspi-clean-and-update.sh"
tags: [ cron ]

- name: "maintenance script to delete logs, update dist upgrade"
copy:
dest: /usr/local/bin/raspi-clean-and-update.sh
content: |
set -x
find /var/log -name '*.gz' | xargs rm -f {}
find /var/log -type f | xargs cat /dev/null > {}
apt update -y
apt autoremove
apt upgrade -y
apt dist-upgrade -y
tags: [ cron ]

handlers:
- name: restart samba
command: service smbd restart

As you can see, in the second line, I’m telling ansible to look for the raspberry as “raspberry”. To tell ansible where the “raspberry” is, you need to add a line to `/etc/ansible/hosts` with the raspberry IP. In this example I’m using the static IP I’ve set in the config itself.

#/etc/ansible/hosts
[raspberry]
raspberry_1 ansible_ssh_host=192.168.0.14

You can also define this in separate file and point it with from the playbook command `ansible-playbook yourFile.yml -i fileabove.ini`

Run

As written above, the command to run is:

ansible-playbook ~/raspberry-config.yaml 

Ansible has to be installed in your host machine of course, normally a very quick process.

More advanced config: tags

In the example playbook I’m using tags. If you run the playbook with -t tag1,tag2 only the config entries with tag1 and tag2 will be executed

Reference

https://docs.ansible.com contains everything you need to know about ansible. To find the reference for the single config, it’s probably quicker to google them e.g.“ansible lineinfile” or “ansible file”, or “ansible copy” to quickly jump to the reference pages.

Conclusions

You’ll surely run the same install and config operations more than once, so investing a few minutes in writing a YAMl file and run it with ansible will save your time, and be less stressful when you need to reinstall it. Ansible is also useful to install any other kind of machine, so you can also use it to install packages and set config for your Mac or Linux machine.

Clap if useful. Feel free to comment for clarifications

Raspberry

--

--

Elvis Ciotti

Software Contractor — Java, Spring, k8s, AWS, Javascript @ London - hire me at https://www.linkedin.com/in/elvisciotti