Introduction
The ansible.builtin.lineinfile module edits single lines in text files — inserting, replacing, or removing lines based on regular expressions. It's the go-to module for configuration file changes where you need to modify one specific setting without templating the entire file.
For multi-line edits, use blockinfile. For full file management, use template.
Module Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
path | string | Yes | File path to edit |
line | string | No* | Text to insert or replace |
regexp | string | No | Regex to find the line to replace |
state | string | No | present (default) or absent |
insertafter | string | No | Insert after this regex (or EOF) |
insertbefore | string | No | Insert before this regex (or BOF) |
create | bool | No | Create file if it doesn't exist |
backup | bool | No | Create a backup before editing |
validate | string | No | Command to validate after editing |
owner | string | No | File owner |
group | string | No | File group |
mode | string | No | File permissions |
*Required when state: present.
Basic Usage
Replace a Line
- name: Enable password authentication in SSH
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config
regexp: "^PasswordAuthentication"
line: "PasswordAuthentication yes"
validate: 'sshd -t -f %s'
This finds any line starting with PasswordAuthentication and replaces it entirely.
Insert a Line at End of File
- name: Add DNS server
ansible.builtin.lineinfile:
path: /etc/resolv.conf
line: "nameserver 8.8.8.8"
If the line already exists, no change is made (idempotent).
Remove a Line
- name: Remove old DNS entry
ansible.builtin.lineinfile:
path: /etc/resolv.conf
regexp: "^nameserver 10\.0\.0\.1"
state: absent
Practical Examples
SSH Configuration
- name: Harden SSH configuration
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config
regexp: "{{ item.regexp }}"
line: "{{ item.line }}"
validate: 'sshd -t -f %s'
loop:
- { regexp: '^#?PermitRootLogin', line: 'PermitRootLogin no' }
- { regexp: '^#?PasswordAuthentication', line: 'PasswordAuthentication no' }
- { regexp: '^#?MaxAuthTries', line: 'MaxAuthTries 3' }
- { regexp: '^#?X11Forwarding', line: 'X11Forwarding no' }
- { regexp: '^#?AllowTcpForwarding', line: 'AllowTcpForwarding no' }
notify: restart sshd
Kernel Parameters (sysctl.conf)
- name: Set kernel parameters
ansible.builtin.lineinfile:
path: /etc/sysctl.conf
regexp: "^{{ item.key }}\\s*="
line: "{{ item.key }} = {{ item.value }}"
loop:
- { key: 'net.ipv4.ip_forward', value: '1' }
- { key: 'vm.swappiness', value: '10' }
- { key: 'net.core.somaxconn', value: '65535' }
notify: reload sysctl
/etc/hosts Entries
- name: Add host entries
ansible.builtin.lineinfile:
path: /etc/hosts
regexp: "\\s+{{ item.hostname }}$"
line: "{{ item.ip }} {{ item.hostname }}"
loop:
- { ip: '192.168.1.10', hostname: 'db.internal' }
- { ip: '192.168.1.20', hostname: 'web.internal' }
- { ip: '192.168.1.30', hostname: 'cache.internal' }
Environment Variables
- name: Set JAVA_HOME
ansible.builtin.lineinfile:
path: /etc/environment
regexp: "^JAVA_HOME="
line: "JAVA_HOME=/usr/lib/jvm/java-17-openjdk"
sudoers File (with Validation)
- name: Allow deploy user to restart services
ansible.builtin.lineinfile:
path: /etc/sudoers.d/deploy
line: "deploy ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart myapp"
create: true
mode: '0440'
validate: 'visudo -cf %s'
The validate parameter is critical for sudoers — a syntax error locks you out.
Insert After/Before Specific Lines
# Insert after a specific section
- name: Add option after [mysqld] section
ansible.builtin.lineinfile:
path: /etc/mysql/my.cnf
insertafter: '^\[mysqld\]'
line: 'max_connections = 500'
# Insert before a line
- name: Add comment before setting
ansible.builtin.lineinfile:
path: /etc/myapp/config.conf
insertbefore: '^max_workers'
line: '# Performance tuning'
Create File If Missing
- name: Ensure config line exists
ansible.builtin.lineinfile:
path: /etc/myapp/custom.conf
line: "log_level = info"
create: true
owner: root
group: root
mode: '0644'
Backup Before Editing
- name: Edit with backup
ansible.builtin.lineinfile:
path: /etc/nginx/nginx.conf
regexp: "^\\s*worker_connections"
line: " worker_connections 4096;"
backup: true
Creates a timestamped backup like nginx.conf.2024-01-15@10:30:00~.
Using Backreferences
Capture parts of the matched line and reuse them:
- name: Comment out a line (preserve content)
ansible.builtin.lineinfile:
path: /etc/myapp/config.conf
regexp: '^(important_setting.*)$'
line: '# \1'
backrefs: true
Important: When backrefs: true, the line is only changed if the regexp matches. If no match, no change is made (unlike default behavior which appends).
- name: Update port while keeping the rest
ansible.builtin.lineinfile:
path: /etc/myapp/config.conf
regexp: '^(listen\s+)\d+'
line: '\g<1>8443'
backrefs: true
lineinfile vs Other Modules
| Task | Best Module |
|---|---|
| Change one line/setting | lineinfile |
| Insert a block of text | blockinfile |
| Manage entire file from template | template |
| Simple find/replace in text | replace |
| Edit INI-style files | community.general.ini_file |
| Edit XML files | community.general.xml |
| Edit JSON files | ansible.builtin.copy with content filter |
Common Mistakes
Regexp Too Broad
# WRONG — matches any line containing 'port'
regexp: "port"
# CORRECT — match the specific setting
regexp: "^listen_port\\s*="
Missing Escape Characters
# WRONG — dot matches any character
regexp: "^192.168.1.1"
# CORRECT — escape the dots
regexp: "^192\\.168\\.1\\.1"
Using lineinfile for Multi-Line Content
# WRONG — lineinfile is for single lines
- ansible.builtin.lineinfile:
path: /etc/config
line: |
line1
line2
# CORRECT — use blockinfile for multiple lines
- ansible.builtin.blockinfile:
path: /etc/config
block: |
line1
line2
Related Articles
- Edit Multi-Line Text: blockinfile Module
- Create a Template: template Module
- Change File Permissions: file Module
- Copy Files to Remote Hosts: copy Module
- Ansible Best Practices Guide
- Ansible Privilege Escalation
Conclusion
The lineinfile module is your surgical tool for single-line edits in configuration files. Always use regexp to find and replace existing lines (rather than appending duplicates), use validate for critical files like sshd_config and sudoers, and use backup: true for safety. For multiple settings in the same file, loop over a list of regexp/line pairs. When you need more than single-line changes, switch to blockinfile or template.