Ansible is a powerful automation tool that allows you to manage configurations and deployments across multiple servers and environments. One of its most useful modules is lineinfile, which gives you granular control to modify lines within files on remote hosts.
In this comprehensive guide, we will explore how to leverage lineinfile to its full potential. Whether you need to add, update, replace, or remove lines, this module has you covered. We will walk through real-world examples so you can immediately apply these techniques in your infrastructure.
Overview of lineinfile
The lineinfile module gives Ansible the ability to ensure lines are present or absent within files on remote hosts.
Some key capabilities include:
- Adding or updating lines
- Replacing existing lines
- Removing lines
- Inserting lines before or after matching patterns
- Backing up files before changes
- Validating line presence with check mode
This makes lineinfile invaluable for modifying configuration files like /etc/hosts, Apache or Nginx config files, systemd unit files, and countless other applications.
Compared to other modules like replace, blockinfile, or template, lineinfile offers more precision without having to rewrite entire files. Small, surgical changes also reduce chances of unwanted side effects.
Now let‘s dive into some practical examples.
Adding a line
The simplest use of lineinfile is adding a new line to a file if it doesn‘t already exist.
For example, here is a playbook that will add a DNS entry for a new web server to /etc/hosts:
- hosts: webservers
tasks:
- name: Add webapp1 entry to /etc/hosts
lineinfile:
path: /etc/hosts
line: "192.168.1.100 webapp1"
This will check /etc/hosts on the remote host and insert the line if missing. The great thing about lineinfile is idempotence. Running this playbook multiple times will only make the change once.
You can also add multiple lines:
lines:
- 192.168.1.100 webapp1
- 192.168.1.101 webapp2
And lineinfile will add these lines if they don‘t exist yet in the target file.
Inserting lines
In addition to adding lines at the end of a file, you can insert lines before or after matching patterns.
For example, this will insert a line after the localhost entry in /etc/hosts:
- name: Insert line after localhost entry
lineinfile:
path: /etc/hosts
insertafter: ‘127.0.0.1\s+localhost‘
line: "192.168.1.100 webapp1"
You can also insert lines before a matching pattern:
insertbefore: ‘127.0.0.1\s+localhost‘
Using regular expressions provides precision on exactly where to insert new lines.
Replacing lines
To replace existing lines, use the backrefs option:
- name: Replace IP address
lineinfile:
path: /etc/hosts
regexp: ‘^192\.168\.1\.100‘
line: ‘192.168.5.100 webapp1‘
backrefs: yes
This searches /etc/hosts for the pattern 192.168.1.100 and replaces with the new IP address.
The backrefs option tells lineinfile to use the matched line and substitute just the IP rather than the entire line content. This avoids disrupting other service configurations in that line.
Removing lines
Deleting lines is straightforward – just set state: absent like so:
- name: Remove webapp entry
lineinfile:
path: /etc/hosts
regexp: ‘192\.168\.1\.100‘
state: absent
This removes the line containing the IP 192.168.1.100 from /etc/hosts.
You can get more surgical by using a specific line pattern:
regexp: ‘192\.168\.1\.100\s+webapp1‘
Commenting lines
A common requirement is to comment out a line rather than completely removing it. Lineinfile can handle this as well using backrefs:
- name: Comment out HTTP port
lineinfile:
path: /etc/httpd/conf/httpd.conf
regexp: ‘^Listen 80‘
line: ‘#\1‘
backrefs: yes
This inserts a comment marker # before the matched Listen 80 line to comment it out.
The backrefs option replaces the line with itself (\1 referring to the matched line) prefixed with #.
Validating changes
A handy feature of lineinfile is the ability to validate if lines are present or absent without actually changing any files.
This "check mode" is great for playbook testing:
- name: Verify webapp1 entry exists
lineinfile:
path: /etc/hosts
line: "192.168.1.100 webapp1"
check_mode: yes
register: lineinfile_check
- name: Output check result
debug:
msg: "Line exists: {{ lineinfile_check.found }}"
This task checks if the line is in /etc/hosts without modifying the file. It registers a variable with the result that you can output.
Check mode is extremely helpful for ensuring your lineinfile tasks will make the correct changes before executing against production environments.
Handling lineinfile errors
When working with remote files, you should implement some error handling in your playbooks.
For example, you can add a state variable to capture failures:
- name: Add new line
lineinfile:
path: /etc/hosts
line: "10.0.0.100 host1"
register: result
- name: Fail if lineinfile had an error
fail:
msg: "lineinfile failed"
when: result.failed
This will cause the playbook to fail if lineinfile encounters any issues, making troubleshooting easier.
Some common errors include:
- File permissions problems
- Matching incorrect file location
- Regular expression issues
Always prepare for errors when modifying remote files in automated processes.
Idempotence
A nice bonus of lineinfile is that playbooks using it are idempotent out of the box.
For example, take this simple task:
- name: Ensure 192.168 entry exists
lineinfile:
path: /etc/hosts
line: "192.168.1.100 host1"
Running this playbook multiple times will only add the line if missing – Ansible is smart enough not to duplicate it if already present.
Idempotence cuts down on unintended side effects when applying the same playbook to servers in sequence.
Backing up files
When modifying critical system files, it is often prudent to create backups just in case.
Lineinfile can automatically backup a file before applying changes:
- name: Backup hosts file
lineinfile:
path: /etc/hosts
regexp: ‘192\.168\.1\.100‘
state: absent
backup: yes
This removes the desired line but first backs up /etc/hosts to /etc/hosts.bak. Rollback would then be restoring from this backup.
Lineinfile patterns
A key component of lineinfile is pattern matching using regular expressions.
Here are some examples of matching lineinfile patterns:
IP address pattern
\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b
Email pattern
\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b
URL pattern
^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$
Date patterns
^(19|20)\d\d[- /.](0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])$
See the full regex resource guide for more pattern examples.
The key is scoping your regexp to narrowly match the desired line and not unintended entries.
lineinfile use cases
Beyond config files, lineinfile can simplify edits to many file types:
- User accounts – Add users to /etc/passwd or groups to /etc/group
- Service configs – Tweak Apache, Nginx, systemd unit files
- Database config – Set Redis or MongoDB settings
- Environment variables – Modify .bashrc or .profile variables
- Application configs – Change settings in config.properties files
- Access controls – Whitelist IPs in IPtables or firewall configs
- Custom files – Insert build strings into version tracking files
The use cases are unlimited – any situation requiring surgical line modifications is perfect for lineinfile.
Now let‘s walk through some end-to-end examples in real systems.
Example 1 – Apache configuration
A common task is modifying Apache config values without disrupting unrelated settings.
Lineinfile makes this simple, such as updating the listen port:
/etc/httpd/conf/httpd.conf:
# Listen 12.34.56.78:80
Listen 127.0.0.1:8080
# Other config entries
Playbook:
- name: Change Apache listen port
lineinfile:
path: /etc/httpd/conf/httpd.conf
regexp: ‘^Listen 127.0.0.1:8080‘
line: Listen 127.0.0.1:8088
backrefs: yes
This searches for the 8080 port line and replaces just the port value itself, leaving other configs untouched.
The backrefs option replaces with the existing line matched by regexp and substitutes only the8080 pattern within.
You can also use lineinfile to append new config properties:
- name: Insert custom Apache directive
lineinfile:
path: /etc/httpd/conf/httpd.conf
insertafter: ‘</VirtualHost>‘
line: Include conf/custom.conf
This demonstrates the flexibility of inserting directives around other patterns in complex config files.
Example 2 – Nginx templating
Nginx utilizes template directives to reduce duplicate configurations – perfect for lineinfile.
For example:
/etc/nginx/nginx.conf
http {
# templated server configs
include servers/*.conf;
}
This applies all config files within /servers, allowing you to define hosts separately.
To add a new DNS entry, use lineinfile on the individual server template:
/etc/nginx/servers/webapp.conf
server {
listen 80;
server_name www.webapp.com;
# web root and other configs
}
Playbook
- name: Add server alias to Nginx
lineinfile:
path: /etc/nginx/servers/webapp.conf
insertafter: ‘server_name www.webapp.com‘
line: ‘server_name webapp.internal‘
This demonstrates adding new server aliases without having to copy or rewrite the base Nginx config. Lineinfile updates just what you need.
Example 3 – Systemd configuration
Systemd has become the dominant service manager on Linux. Its config files have a standardized structure perfect for lineinfile modifications.
For example, to add an Environment variable to systemd:
/etc/systemd/system/myservice.service
[Unit]
Description=My Custom Service
[Service]
ExecStart=/usr/local/bin/myservice
Playbook
- name: Add service env var
lineinfile:
path: /etc/systemd/system/myservice.service
insertafter: ‘[Service]‘
line: ‘Environment=MYVAR=value‘
Simple change, but inserted surgically in the correct systemd file section to ensure proper parsing.
Lineinfile allows incrementally modifying unit files to alter service settings. Much safer than replacing the entire file.
This same method works for the global systemd config at /etc/systemd/system.conf or user units in ~/.config/systemd.
Example 4 – User account management
Managing Linux user accounts is prime territory for lineinfile. Rather than rewriting passwd & shadow files, you can surgically insert just what you need.
For example, adding a user:
/etc/passwd
jsmith:x:1001:1001:Joe Smith:/home/jsmith:/bin/bash
bjones:x:1002:1002:Bob Jones:/home/bjones:/bin/bash
/etc/shadow
jsmith:$6$saltsalt$hashhash:18297:0:99999:7:::
bjones:$6$saltsalt$hashhash:18297:0:99999:7:::
Playbook
- name: Insert ted user
lineinfile:
path: /etc/passwd
line: ‘ted:x:1003:1003:Ted:/home/ted:/bin/bash‘
- name: Insert ted shadow hash
lineinfile:
path: /etc/shadow
line: ‘ted:$6$saltsalt$hashhash:18297:0:99999:7:::‘
This demonstrates inserting just the lines needed for the new user into the proper system files. Much easier than rewriting the entire passwd & shadow contents.
You can also remove user accounts by using state: absent and referencing lines by UID.
Example 5 – MongoDB configuration
MongoDB stores its config file at /etc/mongod.conf, which has multiple sections. Lineinfile makes it easy to tweak settings.
For example, to alter the systemLog verbosity:
/etc/mongod.conf
systemLog:
destination: file
logAppend: true
path: /var/log/mongodb/mongod.log
verbosity: 0
Playbook
- name: Increase MongoDB verbosity
lineinfile:
path: /etc/mongod.conf
regexp: ‘verbosity: 0‘
line: verbosity: 2
backrefs: yes
This bumps up logging without restarting the entire mongod process. Granular edits prevent service disruptions.
For database services, lineinfile allows optimizing memory usage, query throughput, indexes, and more.
Example 6 – IPtables configuration
Firewalls like IPtables filter network traffic based on rulesets. Inserting new rules requires precision.
Here is an IPtables rule allowing SSH traffic:
-A INPUT -p tcp --dport ssh -j ACCEPT
To append additional rules with lineinfile:
Playbook
- name: Allow SMTP traffic
lineinfile:
path: /etc/sysconfig/iptables
insertbefore: ‘-A INPUT -p tcp --dport ssh -j ACCEPT‘
line: ‘-A INPUT -p tcp --dport smtp -j ACCEPT‘
This demonstrates inserting port 25 SMTP access before the existing SSH rule.
Controlling rule order is critical for firewall policy management, making lineinfile a key capability for infrastructure automation.
Example 7 – Managing custom files
Beyond traditional config files, you can leverage lineinfile for other operational requirements.
For example, some teams track build strings in custom files like /opt/version.txt
1.3.2
To increment versions:
Playbook
- name: Bump version to 1.3.3
lineinfile:
path: /opt/version.txt
regexp: ‘(^\d+\.\d+\.\d+)$‘
line: ‘\11.3.3‘
backrefs: yes
This uses a regex backref to isolate the version string and increase the patch number.
You can track anything in custom files – configurations, metrics, application data, log fingerprints, and more. Lineinfile provides an automation method to update these timestamped tracking files.
The possibilities are endless!
Conclusion
The lineinfile module is an indispensable tool for Ansible engineers and DevOps teams needing precise control to modify files on remote servers.
Key takeaways include:
- Adding, inserting, replacing, and removing file lines
- Use regular expressions for surgical precision
- Idempotent and check modes to safely test changes
- Backup options available
- Applies to practically any file type used in systems
Hopefully this guide provided a comprehensive overview of how to utilize lineinfile in your infrastructure automation. The examples showcase just a subset of where this module can help manage your server fleets and reduce configuration drift.
What use cases are you considering for lineinfile? What other Ansible modules integrate well with it? Please share your experiences below!


