UFW Allow Port with Ansible: Complete Firewall Management Guide (Ubuntu/Debian)
By Luca Berton · Published 2024-01-01 · Category: installation
Manage UFW firewall rules with Ansible on Ubuntu and Debian. Allow ports, deny traffic, rate-limit SSH, configure web server and database firewalls, IPv6.

How to open firewall ports in Debian-like systems with Ansible? I'm going to show you a live Playbook and some simple Ansible code. I'm Luca Berton and welcome to today's episode of Ansible Pilot.
Ansible open firewall ports in Debian-like systems
Today we're talking about the Ansible module UFW.
The full name is community.general.ufw, which means that is part of the collection supported by the Ansible community. This module requires Ansible 2.9+.
It works in Debian-like systems so distributions like Debian, Ubuntu, and Mint with ufw firewall, the Uncomplicated Firewall.
This module manages the firewall with UFW.
See also: Ansible on Debian 11 Bullseye: UFW Firewall Automation Complete Guide
Parameters
The parameter list is pretty wide but these are the most important options for our use case to open firewall ports. The first set of parameters controls UFW program and the second the single rules.
UFW program parameters
| Parameter | Type | Options | Description |
|-----------|------|---------|-------------|
| default (policy) | string | allow / deny / reject | Change default policy for incoming or outgoing traffic |
| logging | string | on / off / low / medium / high / full | Toggle UFW logging (uses LOG_KERN syslog) |
| state | string | enabled / disabled / reloaded / reset | Enable, disable, reload, or reset firewall |
| direction | string | in / incoming / out / outgoing / routed | Direction for the default policy |
The "state" parameter options:
• enabled - reloads firewall and enables firewall on boot
• disabled - unloads firewall and disables firewall on boot
• reloaded - reloads firewall
• reset - disables and resets firewall to installation defaults
Rule-specific parameters
| Parameter | Type | Options | Description |
|-----------|------|---------|-------------|
| rule | string | allow / deny / limit / reject | Firewall rule action |
| name (app) | string | Application name | Uses profile in /etc/ufw/applications.d |
| port (to_port) | string | Port number or range | Destination port (e.g., 80 or 60000:61000) |
| proto | string | any / tcp / udp / ipv6 / esp / ah / gre / igmp | Protocol |
| from_ip | string | IP address or CIDR | Source address (default: any) |
| to_ip | string | IP address or CIDR | Destination address (default: any) |
| interface | string | Interface name | Network interface for the rule |
| direction | string | in / out | Direction for interface rules |
| route | boolean | true / false | Apply rule to routed/forwarded packets |
| comment | string | Text | Add comment to the rule |
| insert | integer | Rule number | Insert rule at position instead of appending |
| insert_relative_to | string | zero / first-ipv4 / last-ipv4 / first-ipv6 / last-ipv6 | Relative position for insert |
| delete | boolean | true / false | Delete matching rule |
| log | boolean | true / false | Log matched packets |
Basic Playbook: Open Firewall Ports
---
- name: ufw module Playbook
hosts: all
become: true
tasks:
- name: nginx installed
ansible.builtin.apt:
name: "nginx"
state: "present"
update_cache: true
- name: ufw enabled
community.general.ufw:
state: "enabled"
policy: "deny"
logging: "on"
- name: ufw rules
community.general.ufw:
rule: "allow"
port: "{{ item }}"
proto: "tcp"
loop:
- "22"
- "80"
- "443"
See also: Ansible on Debian 12 Bookworm: UFW Firewall Automation Complete Guide
Allow Port: Common Examples
Allow a Single Port
- name: Allow SSH
community.general.ufw:
rule: allow
port: '22'
proto: tcp
Allow Port from Specific IP
- name: Allow SSH from office network
community.general.ufw:
rule: allow
port: '22'
proto: tcp
from_ip: '10.0.0.0/8'
comment: 'SSH from office'
Allow Port Range
- name: Allow high ports for passive FTP
community.general.ufw:
rule: allow
port: '60000:61000'
proto: tcp
comment: 'Passive FTP range'
Allow by Application Profile
- name: Allow Nginx Full profile
community.general.ufw:
rule: allow
name: 'Nginx Full'
comment: 'Web server HTTP and HTTPS'
To see available application profiles:
sudo ufw app list
# Available applications:
# Nginx Full
# Nginx HTTP
# Nginx HTTPS
# OpenSSH
Allow on Specific Interface
- name: Allow MySQL on internal interface only
community.general.ufw:
rule: allow
port: '3306'
proto: tcp
interface: eth1
direction: in
comment: 'MySQL on private network'
Deny and Reject Rules
- name: Deny incoming telnet
community.general.ufw:
rule: deny
port: '23'
proto: tcp
- name: Reject with ICMP unreachable
community.general.ufw:
rule: reject
port: '25'
proto: tcp
comment: 'Reject SMTP - use relay instead'
The difference: deny silently drops packets (attacker gets no response). reject sends an ICMP unreachable back (faster failure for legitimate clients).
See also: Ansible on Debian 13 Trixie: UFW Firewall Automation Complete Guide
Rate Limiting with UFW
The limit rule allows only 6 connections per 30 seconds from a single IP. Essential for SSH brute-force protection:
- name: Rate limit SSH connections
community.general.ufw:
rule: limit
port: '22'
proto: tcp
comment: 'Rate limit SSH - 6 conn/30s'
Delete Rules
- name: Remove old FTP rule
community.general.ufw:
rule: allow
port: '21'
proto: tcp
delete: true
Complete Web Server Firewall Playbook
---
- name: Configure web server firewall
hosts: webservers
become: true
vars:
allowed_ssh_networks:
- '10.0.0.0/8'
- '172.16.0.0/12'
web_ports:
- { port: '80', comment: 'HTTP' }
- { port: '443', comment: 'HTTPS' }
monitoring_port: '9100'
monitoring_server: '10.0.10.50'
tasks:
- name: Install UFW
ansible.builtin.apt:
name: ufw
state: present
update_cache: true
- name: Set default deny incoming
community.general.ufw:
default: deny
direction: incoming
- name: Set default allow outgoing
community.general.ufw:
default: allow
direction: outgoing
- name: Allow SSH from trusted networks
community.general.ufw:
rule: limit
port: '22'
proto: tcp
from_ip: "{{ item }}"
comment: "SSH from {{ item }}"
loop: "{{ allowed_ssh_networks }}"
- name: Allow web traffic from anywhere
community.general.ufw:
rule: allow
port: "{{ item.port }}"
proto: tcp
comment: "{{ item.comment }}"
loop: "{{ web_ports }}"
- name: Allow node-exporter from monitoring server
community.general.ufw:
rule: allow
port: "{{ monitoring_port }}"
proto: tcp
from_ip: "{{ monitoring_server }}"
comment: "Prometheus scrape from monitoring"
- name: Enable UFW logging
community.general.ufw:
logging: 'low'
- name: Enable UFW
community.general.ufw:
state: enabled
- name: Verify UFW status
ansible.builtin.command:
cmd: ufw status verbose
register: ufw_status
changed_when: false
- name: Show firewall rules
ansible.builtin.debug:
msg: "{{ ufw_status.stdout_lines }}"
Database Server Firewall
---
- name: Configure database firewall
hosts: databases
become: true
vars:
app_servers:
- '10.0.1.10'
- '10.0.1.11'
- '10.0.1.12'
db_port: '5432'
tasks:
- name: Default deny incoming
community.general.ufw:
default: deny
direction: incoming
- name: Allow PostgreSQL from app servers only
community.general.ufw:
rule: allow
port: "{{ db_port }}"
proto: tcp
from_ip: "{{ item }}"
comment: "PostgreSQL from {{ item }}"
loop: "{{ app_servers }}"
- name: Allow SSH from bastion
community.general.ufw:
rule: allow
port: '22'
proto: tcp
from_ip: '10.0.0.5'
comment: 'SSH from bastion host'
- name: Deny all other PostgreSQL access
community.general.ufw:
rule: deny
port: "{{ db_port }}"
proto: tcp
comment: 'Deny direct DB access'
- name: Enable UFW
community.general.ufw:
state: enabled
Kubernetes Node Firewall
---
- name: Configure K8s node firewall
hosts: k8s_nodes
become: true
tasks:
- name: Default deny incoming
community.general.ufw:
default: deny
direction: incoming
- name: Allow Kubernetes API server
community.general.ufw:
rule: allow
port: '6443'
proto: tcp
comment: 'K8s API server'
- name: Allow kubelet API
community.general.ufw:
rule: allow
port: '10250'
proto: tcp
comment: 'Kubelet API'
- name: Allow NodePort range
community.general.ufw:
rule: allow
port: '30000:32767'
proto: tcp
comment: 'K8s NodePort services'
- name: Allow flannel VXLAN
community.general.ufw:
rule: allow
port: '8472'
proto: udp
comment: 'Flannel VXLAN'
- name: Allow etcd (control plane only)
community.general.ufw:
rule: allow
port: '2379:2380'
proto: tcp
comment: 'etcd client and peer'
when: "'control_plane' in group_names"
- name: Enable UFW
community.general.ufw:
state: enabled
IPv6 Support
- name: Configure IPv6 firewall rules
hosts: all
become: true
tasks:
- name: Enable IPv6 in UFW config
ansible.builtin.lineinfile:
path: /etc/default/ufw
regexp: '^IPV6='
line: 'IPV6=yes'
notify: reload ufw
- name: Allow HTTP over IPv6
community.general.ufw:
rule: allow
port: '80'
proto: tcp
from_ip: '::/0'
comment: 'HTTP IPv6'
handlers:
- name: reload ufw
community.general.ufw:
state: reloaded
Firewall Reset
- name: Reset UFW to defaults
community.general.ufw:
state: reset
- name: Disable UFW completely
community.general.ufw:
state: disabled
Verification Commands
# Check UFW status
sudo ufw status
sudo ufw status verbose
sudo ufw status numbered
# Check specific app profiles
sudo ufw app list
sudo ufw app info 'Nginx Full'
# Check UFW logs
sudo tail -f /var/log/ufw.log
FAQ
How do I allow a port with UFW in Ansible?
Use community.general.ufw with rule: allow and specify the port and proto parameters. For example: community.general.ufw: rule=allow port=80 proto=tcp. Add from_ip to restrict access to specific source networks.
What is the difference between deny and reject in UFW?
deny silently drops the packet - the sender gets no response and eventually times out. reject sends an ICMP unreachable message back. Use deny for external-facing rules (reveals less information to attackers) and reject for internal rules (faster failure for legitimate connections).
How do I rate-limit SSH with Ansible and UFW?
Use rule: limit instead of rule: allow. This automatically limits connections to 6 per 30 seconds from a single IP address: community.general.ufw: rule=limit port=22 proto=tcp. This is the simplest brute-force protection.
Can I use UFW with Docker?
Docker modifies iptables directly, bypassing UFW rules. Containers with published ports are accessible even if UFW blocks the port. Use DOCKER_OPTS="--iptables=false" or the ufw-docker utility to make Docker respect UFW rules.
How do I allow a port range with UFW in Ansible?
Specify the range with a colon: port: '60000:61000'. You must also specify proto: tcp or proto: udp - port ranges require an explicit protocol.
Conclusion
Now you know how to manage firewall rules on Debian-like systems with Ansible using UFW, the Uncomplicated Firewall. From basic port opening to complete web server, database, and Kubernetes firewall configurations - thecommunity.general.ufw module handles it all with simple, declarative YAML.
Related Articles
• Ansible firewalld ufw Module: Manage Firewall Rules Guide • Deploy a web server with Ansible (apt, copy, service, ufw) • reverse proxy with Ansible Nginx • sudo and become in Ansible playbooks • Ansible on Ubuntu 26.04 LTSCategory: installation
Watch the video: UFW Allow Port with Ansible: Complete Firewall Management Guide (Ubuntu/Debian) — Video Tutorial