Workflow
I use automation tools as much as possible but a lot of managing the infrastructure is done manually.
Network/Hardware
Section titled “Network/Hardware”Terraform is used to manage the network and hardware, and I run it manually when I want to change something.
Network
Section titled “Network”To change the network settings, to add a new subdomian for example, I edit the Terraform code in terraform/dns.tf.
I then run
terraform applyto change the network settings.
Hardware
Section titled “Hardware”To change the hardware I edit the terraform/web.tf file.
I would do this to change the settings of the Pi, or to change the Pi to a VPS.
I then run
terraform applyto change the hardware.
Software
Section titled “Software”Ansible is used to manage the software, and I run it manually when I want to change something.
To change the software, to add a new website to host for example, I edit the Ansible code.
I then run
ansible-playbook site.yamlto apply the site.yaml playbook which contains the whole setup. The name site is just an old name I keep using for the “main” Ansible playbook.
I can run only parts of the setup using tags:
ansible-playbook site.yaml --tags web, caddywhich I would do if I added a new site to deploy (part of the web role) and changed the Caddyfile to serve it (part of the caddy role).
The playbook and the roles it uses are set up so that I don’t need to edit them directly to make simple changes like adding a new site to host.
To make a simple change, like adding a new site to host, I would edit the ansible/group_vars/all/main.yaml file:
web_sites_root: "/srv/www"web_sites: - "paultibbetts.uk" - "infra.paultibbetts.uk" - "dev.paultibbetts.uk"
web_deploy_user: "deploy"web_deploy_home: "/home/deploy"web_deploy_ssh_keys: - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK+5ESd3EGl8/Wm3VDkQ4PKTp4uDLrEDXpdgYD1nuKmV"web_group: "deploy"web_keep_releases: 3
caddy_caddyfile_template: "{{ playbook_dir }}/templates/Caddyfile.j2"caddy_install_method: downloadcaddy_plugins: - github.com/caddy-dns/cloudflarecaddy_manage_systemd_env_file: truecaddy_systemd_env: CF_API_TOKEN: "{{ vault_cf_api_token }}"Ansible is written in Python.
I use uv to install and manage Python versions and dependencies, because it’s reliable and 100x faster than Pip, and so the command to run the playbook is:
uv syncuv run ansible-playbook site.yamlI use make to collect the commands that I use when working with Ansible.
These are listed in a Makefile as a reference and also to run using make <target>.
.PHONY: setup deps deps-upgrade site
GALAXY_FLAGS ?=PLAYBOOK_FLAGS ?=
setup: @command -v uv >/dev/null || \ (echo "uv is not installed" && exit 1) uv sync
deps: setup uv run ansible-galaxy role install -r requirements.yaml -p roles/galaxy $(GALAXY_FLAGS) uv run ansible-galaxy collection install -r requirements.yaml $(GALAXY_FLAGS)
deps-upgrade: setup uv run ansible-galaxy role install -r requirements.yaml -p roles/galaxy --force $(GALAXY_FLAGS) uv run ansible-galaxy collection install -r requirements.yaml --force $(GALAXY_FLAGS)
site: deps uv run ansible-playbook site.yaml $(PLAYBOOK_FLAGS)where site is the recipe that runs the Ansible playbook.
Deployments
Section titled “Deployments”Deployments happen when the main branch of the code for the website gets updated.
I can trigger a deployment by making a change to one of the websites and it will be live a few minutes later.
This process is fully automated and deployed websites should always be in sync with their code.