Latest / Linux Server Admin with Fexingo: Sysadmin, Bash, and Server Engineering / How to Automate Linux Server Configuration with Ansible
Transcript
- Lucas: If today's tech conversation gave you something usable, that's exactly the point. We deliberately don't run ads on these shows, and listener support is what keeps that choice possible. If you want to help sustain it, the link is buy me a coffee dot com slash fexingo. No pressure — just a way to keep the server lights on. Luna: Yeah, it's a small gesture that goes a long way. We really appreciate everyone who's chipped in. Lucas: Alright, let's get back to the terminal. So, you've got a fresh Ubuntu 24.04 server, SSH access, and you need to set up a web stack: Nginx, Node.js, PostgreSQL, and a firewall. You could SSH in and run a dozen commands, but next time you need to do it on five more servers? That's where Ansible comes in. Luna: And Ansible is agentless, right? You just need SSH and Python on the managed nodes. Lucas: Exactly. No agents, no PKI setup — just SSH keys and Python. That's a huge time saver. Tonight, let me walk through a real playbook I use for this exact stack. First, you need an inventory file. You create a file called 'hosts.ini' and list your servers: server1 ansible_host=192.168.1.10. That's it. Luna: So you group them by role — webservers, databases. That makes it easy to run different tasks on different groups. Lucas: Right. Now, the playbook itself is a YAML file. I'll call it 'webserver.yml'. The structure is simple: a list of plays, each targeting a group. Here's a skeleton: --- - hosts: webservers, become: yes, tasks:... The 'become: yes' means run tasks as sudo. Luna: And each task is a module. Like 'apt' for packages, 'copy' for files, 'service' for daemons. Lucas: Precisely. Let's start with Nginx. Our first task: name: Install Nginx, apt: name: nginx, state: present. Then enable and start it: service: name: nginx, state: started, enabled: yes. That's two tasks, and Ansible ensures idempotency — if Nginx is already installed, it skips. Luna: Idempotency is the killer feature. With a shell script, you'd have to write checks yourself. Ansible does that out of the box for most modules. Lucas: Yeah. Next, Node.js. The default Ubuntu repos have an older version, so I add the NodeSource repo. That's a bit trickier. I use the 'shell' module to run a curl command, but I add a 'creates' parameter so it only runs if the repo file doesn't exist. Something like: shell: curl -fsSL https://deb.nodesource.com/setup_20.x | bash -, args: creates: /etc/apt/sources.list.d/nodesource.list. Luna: So you're manually ensuring idempotency there because the shell module doesn't know what the command does. Lucas: Exactly. For custom commands, you have to help Ansible know when to skip. Then I install Node.js with apt: nodejs. For PostgreSQL, I add the official repo similarly, then install postgresql and python3-psycopg2 so Ansible can manage databases. Luna: And you can use the postgresql_db and postgresql_user modules to create databases and users declaratively. That's powerful. Lucas: Right. Let me show you a snippet for that: name: Create application database, postgresql_db: name: myapp, state: present. Then add a user with encrypted password. The module handles the SQL commands for you. Luna: What about the firewall? You'd use the ufw module, right? Lucas: Yes. ufw: rule: allow, port: '80', proto: tcp. Same for 443 if you have SSL. And deny incoming by default. Simple. Luna: Let's talk about testing. How do you make sure the playbook works without wrecking production? Lucas: Great question. I always test locally first with a Vagrant box or a Docker container. Ansible has a check mode: ansible-playbook webserver.yml --check. That simulates the run and reports what would change, but doesn't actually make changes. You can also use --diff to see file changes. Luna: Check mode is great, but some modules don't fully support it. Like shell commands won't report correctly. Lucas: True. For those, I either add a 'register' and 'failed_when' condition, or I run a small test instance. The other thing is idempotency testing: run the playbook twice. The second run should report 'changed=0' for all tasks. If it doesn't, something's off. Luna: That's a good habit. So once the playbook is solid, you can run it against your servers with a single command: ansible-playbook -i hosts.ini webserver.yml. Lucas: Exactly. And you can scale to ten or a hundred servers just by adding entries to the inventory. No manual SSH sessions. That's the beauty of Ansible. Luna: One thing I always forget: Ansible uses YAML, and indentation matters. A missing space can break the whole playbook. Lucas: Oh, absolutely. YAML is whitespace-sensitive. I use a linter like 'ansible-lint' or 'yamllint' to catch those errors before running. Also, use 'ansible-playbook --syntax-check' to validate the structure. Luna: Good tip. So where would you go from here? Roles? Variables? Lucas: Next step: organize your playbook into roles. Roles let you bundle tasks, handlers, variables, and templates into reusable units. For example, a 'nginx' role, a 'nodejs' role, a 'postgresql' role. Then your playbook just references the roles: roles: - nginx - nodejs - postgresql. That's cleaner and shareable. Luna: And you can version control each role separately, or use Ansible Galaxy to pull community roles. Lucas: Right. Galaxy has thousands of pre-built roles. But always audit them for security. For production, I prefer writing my own slim roles that do exactly what I need. Luna: That's a solid approach. So what's the one takeaway for someone who's never used Ansible? Lucas: Start small. Write a playbook that does one thing — say, install Nginx and set the index.html. Run it against a test server. Once you see how idempotency works and how easy it is to extend, you'll never go back to manual configuration. Automate early, automate often. Luna: Great advice. And remember to keep your playbooks in git. That way you have a full history of your infrastructure. Lucas: Exactly. Infrastructure as code. Thanks for joining us on this deep dive. Next time, we'll look at Ansible Vault for managing secrets.