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!

Similar Posts