Ansible Role for managing an opiniated Alpine Router
- Jinja 100%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
All checks were successful
ci/woodpecker/push/linting Pipeline was successful
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> |
||
| .woodpecker | ||
| defaults | ||
| handlers | ||
| meta | ||
| roles | ||
| tasks | ||
| templates | ||
| .ansible-lint | ||
| .editorconfig | ||
| .gitattributes | ||
| .gitignore | ||
| .markdownlint-cli2.jsonc | ||
| .sops.yaml | ||
| .yamllint | ||
| AGENTS.md | ||
| ansible.cfg | ||
| playbook.yaml | ||
| readme.md | ||
| renovate.json | ||
Ansible Role: Router
Configures an Alpine Linux host as a router: IPv4 forwarding, an nftables firewall with NAT (masquerade and port forwards), conntrack sizing and network performance tuning.
Requirements
- Alpine Linux: packages are installed with
apk(nftables). - Collections
community.generalandansible.posix(modprobe, apk, sysctl). - Two interfaces: a WAN and a LAN interface.
Dependencies
None (dependencies: [] in meta/main.yaml). roles/requirements.yml only fetches this role itself from
https://git.simoncor.net/ansible/router.git.
Variables
| Variable | Required | Default | Description |
|---|---|---|---|
wan_interface |
Yes | eth0 |
WAN network interface |
lan_interface |
Yes | eth1 |
LAN network interface |
nat_port_forwards |
No | [] |
List of port forwards from the WAN to hosts on the LAN |
incoming_firewall_rules |
No | [] |
List of extra rules that allow traffic to the router itself |
icmp_rate_limit_enabled |
No | true |
Rate limit ICMP and ICMPv6 on the WAN; when false all ICMP is accepted |
icmp_rate_limit_rate |
No | "50" |
Accepted ICMP packets per second on the WAN |
icmp_rate_limit_burst |
No | "5" |
ICMP burst size in packets |
wireguard_enabled |
No | true |
Allow forwarding for interfaces named wt* (WireGuard) incl. exit node |
dhcp_enable |
No | false |
Accept DHCP requests (UDP 67) on the LAN interface |
nat_port_forwards
| Key | Required | Default | Description |
|---|---|---|---|
name |
Yes | Description, used as a comment in the ruleset | |
dst |
Yes | LAN destination IP address | |
port |
Yes | Port on the WAN, DNAT'ed to the same port on dst |
|
protocol |
No | tcp |
Protocol |
incoming_firewall_rules
| Key | Required | Default | Description |
|---|---|---|---|
name |
Yes | Description, used as a comment in the ruleset | |
source |
Yes | Source address or CIDR | |
port |
Yes | Destination port on the router | |
protocol |
No | tcp |
Protocol |
interface |
No | lan_interface |
Interface the traffic arrives on |
Example
wan_interface: "eth0"
lan_interface: "eth1"
icmp_rate_limit_enabled: true
icmp_rate_limit_rate: "50"
icmp_rate_limit_burst: "5"
wireguard_enabled: true
dhcp_enable: false
incoming_firewall_rules:
- name: "allow ssh from lan"
source: "192.168.1.0/24"
protocol: "tcp"
port: 22
- name: "allow dns from lan"
source: "192.168.1.0/24"
protocol: "udp"
port: 53
nat_port_forwards:
- name: "forward https to web server"
dst: "192.168.1.10"
port: 443
protocol: "tcp"
Usage
Run playbook.yaml through Semaphore. The playbook first runs ansible-galaxy install -f -r roles/requirements.yml
on localhost, then includes the router role. It runs with serial: 1, so routers are configured one at a time.
Operational notes
- The role imports three task files in this order:
routing.yaml,firewall.yaml,performance.yaml. None of the tasks carry tags. - Routing: installs
nftables, enables IPv4 forwarding, disables ICMP redirects and source routing, sets loose reverse path filtering (rp_filter=2). Settings are written to/etc/sysctl.conf. - Firewall: renders
/etc/nftables.nft(mode0600) and restartsnftableson change. Input and forward policies aredrop, output isaccept. LAN to WAN is forwarded and masqueraded. The ruleset is flushed on load. - Conntrack: loads
nf_conntrack(also at boot), setshashsize=16384,nf_conntrack_max=16384and timeouts for established (3600) and generic (120) connections. - Performance: larger socket buffers, BBR congestion control with the
fqqdisc, ECN and a few other TCP settings. - The role does not enable the
nftablesservice at boot; it only restarts it when the ruleset changes.