MurOS [BETA]

What MurOS does today

MurOS is a fork of OPNsense ported to Debian 13. The configuration model, the web UI and the rule editor are kept from OPNsense; the parts that talk to the system are rewritten for Linux: nftables instead of pf, iproute2 instead of ifconfig, systemd instead of rc, and dpkg / apt instead of the FreeBSD package tools. The list below reflects what is actually wired on Debian. Each area carries a percentage showing how far it has been ported from FreeBSD to Debian, and individual items still being wired are marked in progress.

Network 90%

  • Interface assignment. Each NIC is bound to a logical key (wan, lan, opt1, ...). Rules and NAT reference the key, not the device name. At first boot the keys are mapped to the real Linux devices automatically, so the box comes up without hand-editing.
  • Static addressing via iproute2. IPv4 and IPv6 address, MTU and link state per NIC, applied from config.xml.
  • DHCP client on WAN. The lease is applied by a Linux lease hook (address, netmask, broadcast, classless and static routes) through iproute2, and is kept across renew, rebind and reboot. Assigned interfaces can alternatively be driven by systemd-networkd.
  • VLANs, bridges and link aggregation. 802.1Q VLANs, bridges (members, port isolation, STP timers) and LAGG mapped to Linux bonding (LACP, balance, failover), all applied through iproute2.
  • Wireless. A wifi card is used as an access point or as a station. The channel list offered by the interface form comes from the regulatory domain the radio reports, with the high throughput modes it advertises, and hostapd or wpa_supplicant drives the cell, protected or open. The status page shows the networks in range and the associated peers as Linux reports them: signal, negotiated rates, traffic counters, idle and connected time. WEP is refused, and a card has to be assigned directly rather than cloned.
  • Temporary bans. A rule with a per source limit can name the table the sources that go over it are added to, and a block rule written against that table then keeps them out. An entry lasts an hour. The per source counters can be emptied from the interface to start the counting over.
  • Connection tracking per rule. A rule can ask for no tracking at all, for the traffic whose replies do not look like replies; those packets are excluded ahead of the tracker. Permissive tracking is the default behaviour of the kernel here. The options with no counterpart on this platform are named rather than dropped in silence.
  • Rules that are actually loaded. A check walks the configuration and looks for every rule in the ruleset the kernel runs, telling apart a rule that is applied, one waiting for a reload, and one that will never be applied at all, plus rules left in the kernel for items that no longer exist. It also names the options a rule carries that have no counterpart on this platform, so a rule that is loaded but does not do everything it says is visible. It runs from the console and as part of the health audit. Every rule also carries the identifier of the item it came from, which is what attaches the packet and byte counters to the right line in the rule list.
  • Tunnels. GRE and GIF tunnels (sit, ipip, ip6tnl, chosen from the underlay and overlay address family) created with iproute2.
  • Static routes. Entries in the main routing table, shown live from ip route.
  • Persistence. Assignment and addressing are reapplied at boot by systemd units (muros-interface-assign, muros-interfaces) before the firewall loads, so the state survives a reboot.
  • Multi-WAN gateways. Gateways are configured in the UI and each one is monitored for latency, packet loss and availability by the dpinger daemon, with alarms when a link degrades. A gateway group fails over automatically: its routing table holds the members of the highest tier that still passes the trigger of the group, as a weighted multipath route when that tier has several uplinks, and it is rebuilt as soon as the monitor reports a change. The connections that were already open move as well, the tracked connections pinned to the gateway that changed state are dropped so their next packet takes the new path.

Firewall 93%

  • Filter rules. Generated as an nftables ruleset: input / forward / output chains, action pass / block / reject, per-rule logging and comment.
  • Floating rules that can be overridden. A floating rule without the quick option sets a verdict a later interface rule can still override, the way the original packet filter behaved. The rules are ordered so that the first match a Linux ruleset finds is the one the original semantics would have chosen.
  • Scheduled rules. A rule can be limited to a time window: weekday sets, calendar days and hour ranges. A rule outside its window is not loaded at all, and the ruleset is rebuilt on a timer so it follows the clock.
  • Stateful by default. Default deny with connection-state matching, out of the box.
  • IPv4 and IPv6. Per-rule address family, with the common protocols (tcp, udp, icmp, esp, gre, ...) and TCP flag matching.
  • Aliases as sets. Host, network and port aliases are compiled into nftables named sets and referenced from rules; entries can be added to a running set and the contents are read back from nft.
  • Aliases that resolve. An alias whose content is not a list of addresses, a GeoIP country, a downloaded list, a host name, a MAC address, an autonomous system number or another alias, is resolved by a background updater. The addresses it found are written into the ruleset itself, so a reload arms the alias immediately instead of leaving the rules that use it matching nothing until the next update. An alias that resolves to nothing at all is reported.
  • Live counters. Per-rule and per-table packets and bytes read back from netfilter.
  • Policy routing (multi-WAN). A pass rule can be pinned to a gateway or to a gateway group: matching connections are marked and steered out that uplink (route-to). Replies to a connection that arrived on a WAN are sent back through the same uplink (reply-to), so a multi-homed box does not leak answers into the wrong ISP. The marks are saved on the connection, so every following packet keeps the same path.
  • Validated apply. The generated ruleset is checked with nft -c before it is loaded, and a mandatory anti-lockout rule (SSH / HTTP / HTTPS) keeps the management session reachable.

NAT 98%

  • Outbound NAT. Automatic masquerade per WAN, or manual rules matched on source and destination, written on either the Source NAT page or the older Outbound one. No-NAT rules exclude traffic from translation (for example to a remote VPN subnet), a fixed source port keeps protocols that need it from being rewritten, and a rule can translate to a single address or to a pool of them.
  • Port forwarding (DNAT). Publish an internal service on a public port, scoped to the destination address it is published on (the WAN address or a chosen IP) and an optional source, with the matching forward rule opened automatically. No-rdr exclusions exempt selected traffic, so a management subnet can reach a service directly while everyone else is forwarded.
  • 1:1 NAT. Static external-to-internal address mappings, for a single host or for a whole prefix, where the host part is kept across the translation.
  • IPv6 prefix translation. An internal ULA prefix is mapped onto the prefix delegated by the provider, so renumbering stays at the edge.
  • Bogons that are current. Blocking unallocated networks uses the full list downloaded every night, several thousand prefixes that move every week, not a handful of ranges frozen in the source. Private ranges the list marks as excluded are left out, so the option does not quietly block a network the operator allowed.
  • Sizing and hardening that apply. The maximum number of states sizes the connection tracking table, the maximum number of entries bounds every alias, traffic claiming port zero is dropped, and blocks of private or unroutable sources are logged. Each of these can be turned off where the interface says it can.
  • Anti-lockout that locks. The rule that keeps a firewall reachable while its policy is being written is bound to the primary inside interface and carries the ports the management interfaces actually listen on, not a fixed list. It can be turned off.
  • Rules the system asks for itself. A DHCP server, an IPsec tunnel or a captive portal zone each need a few rules to work at all. They are declared by the component rather than written by the operator, they show on the rule page as automatically generated, and they are compiled into the ruleset ahead of the rules the operator wrote. Any one of them that cannot be built is named by the rule check.
  • Reflection. A service published on the public address stays reachable under that same address from the inside networks, for port forwards and for 1:1 mappings, with the return path translated so the answer comes back through the firewall. It follows the per-rule setting and the system defaults.
  • Dual stack throughout. Outbound rules, port forwards and 1:1 mappings each follow the address family they were written for, so an IPv6 redirection or an IPv6 static mapping is translated like its IPv4 counterpart.
  • Translation pools. A rule can translate to a single address, to a range or to a network, with a sticky mapping that keeps one source on the same translated address, or a random pick across the pool.
  • Matched like a filter rule. An outbound rule narrows on protocol, source port and destination port, not only on addresses, and it can be logged.
  • Negation. Match everything except a given address or set.

LAN services 85%

  • DHCP server (Kea). Per-interface pools for IPv4 and IPv6, offered gateway and DNS, lease time and static reservations. It runs on the Debian Kea daemons, generated from the UI and controlled through systemd; active leases are read live over the Kea control channel.
  • DHCP relay. Forwards client requests to upstream servers on the Debian isc-dhcp-relay binary, for both IPv4 and IPv6, with the relay agent information option and automatic upstream interface selection.
  • DHCP failover. Two firewalls share a single address pool in hot-standby through the Kea high availability hook, so leases survive a node going down. The generated configuration loads the lease and HA hook libraries shipped with Debian Kea.
  • Recursive DNS. Unbound resolver with DNSSEC, forwarders, local records and blocklists. The configuration is generated from the UI for the stock Debian daemon, without the FreeBSD chroot layout.
  • Host discovery. The hosts seen on the local networks are collected by a MurOS daemon that listens for ARP and IPv6 neighbour discovery on a packet socket and reads the kernel neighbour table. It feeds the host list, the captive portal and the MAC address aliases.

VPN 82%

  • WireGuard. The native Linux wg device and its routing are set up through iproute2; configuration pages and key management come from OPNsense. Peers with a hostname endpoint are re-resolved on a systemd timer, so a tunnel recovers when the remote address changes, and each peer reports an online or offline status with the age of its last handshake, while every tunnel summarises how many peers it has and how many are currently online.
  • OpenVPN. tun / tap devices and runtime interface setup ported to iproute2.
  • IPsec (strongSwan 6). Site-to-site (policy-based) and routed (VTI) tunnels run on the in-kernel XFRM stack: charon runs under systemd, and routed tunnels bind their security associations to ipsec xfrm interfaces through a matching interface id. Configuration pages and the built-in PKI (CA, leaf certificates, CRL) come from OPNsense.
  • The raw SAD and SPD diagnostic panels read the kernel XFRM stack through ip xfrm, with per-entry deletion, so they work on Linux without the FreeBSD setkey tool.
  • The strongSwan up/down handler is fully Linux-native: routed tunnels rely on the xfrm interface created at apply time, and manual security policies set on a phase 2 are installed through ip xfrm policy, reapplied idempotently when a tunnel comes up.

High availability 88%

  • VRRP active / passive and connection-state sync (virtual IPs sharing an interface and group id collapse into one instance, no TCP reset on takeover).
  • This replaces the OPNsense CARP / pfsync stack with keepalived (VRRP) and conntrackd on Linux. Virtual IPs are rendered as keepalived instances and the state channel as conntrackd; advskew maps to the VRRP priority, and status, maintenance mode and enable / disable are wired into the UI through a role notify hook. A failed service demotes its node so a healthy peer takes the virtual IPs. Virtual IPs that a node should own fail over together through a keepalived sync group, so a single link or service failure cannot split the cluster across both nodes. Every generated keepalived configuration is validated before it is applied, so a bad change cannot take the cluster down. Live failover, including service-failure takeover and recovery, is validated on a two-node cluster; long-run state-sync soak testing in progress.
  • VRRP can run over unicast with a pinned source address for segments that filter multicast, common on cloud and virtualised bridges, and a master periodically re-announces each virtual IP so downstream switches keep a fresh address entry and the post-failover blackout stays short.
  • Configuration synchronisation. The master pushes the selected configuration sections to the backup over XML-RPC, then reloads its templates and restarts the services that changed. Sections and elements marked as local, the interfaces and the virtual IPs without a group id are never sent, and a DHCP failover peer gets its interface resolved through the kernel routing table.

Intrusion detection 70%

  • Suricata. The Debian package runs under systemd with a generated configuration. Detection reads the traffic through af-packet, and prevention sends it to the engine through NFQUEUE from the nftables ruleset, so the same rules that filter also feed the inspection.
  • Rules. Rule sets are downloaded, enabled and tuned from the UI, and the alerts are read back from the engine log.
  • Flow export. NetFlow export runs on softflowd, with local collection and aggregation for the reporting pages.

Traffic shaping 75%

  • Pipes and queues. The shaper is rendered as tc classes: a pipe becomes an HTB class with its bandwidth, a queue becomes a child class with its weight, and the leaf discipline is fq_codel, with netem when a delay or a loss is configured.
  • Classification. Shaper rules are carried by the nftables ruleset as marks, which tc matches to put a flow in its class, so filtering and shaping share one classification.
  • Statistics. The status page reads the live class counters, so a pipe shows what it actually passes and drops.

Observability 80%

  • Dashboard. CPU, memory, disk, swap and per-interface throughput, read from /proc and refreshed live.
  • Service state. Start, stop and restart of MurOS services through systemd, from the UI.
  • Firewall live log. Pass and block decisions are logged by nftables and streamed live to the UI through the system journal (journald); each line carries the action and the rule that matched, and the matching rule label is resolved from the configuration.
  • Health graphs. CPU, memory and temperature history kept in round-robin databases, read from /proc and the thermal sensors.
  • SNMP and notifications in progress, being ported to the Debian equivalents (snmpd, SMTP).

Diagnostic 92%

  • Live tools. ping, traceroute, ARP / NDP and routing tables, read from iproute2 (ip neigh, ip route).
  • Interface details and counters. Addresses, link state and per-interface statistics from ip addr and ip -s link.
  • Ruleset inspection. The loaded nftables ruleset, viewable from the UI.
  • Connection states. Inspect and flush live connections through conntrack.
  • Packet capture. Start a capture per interface with a filter, then download or view the result; backed by tcpdump.
  • Open sockets. Listening and connected sockets with the owning process, read from ss.
  • Network insight. The netstat panels report what the Linux kernel accounts: per CPU softirq receive statistics, the packet sockets with the process holding them, and the socket memory charged against the kernel pressure limits.

System 91%

  • General. Hostname, time zone, locale, kernel and Debian version.
  • Kernel modules and devices. Required modules (nf_tables, bridge, 8021q, ...) loaded with modprobe; device events handled by systemd-udevd.
  • Backups. The whole configuration lives in a single config.xml. Download it, restore it, or keep dated copies.
  • System DNS. /etc/resolv.conf, separate from the recursive resolver.
  • Network time. Time sync runs on chrony. Upstream servers and pools, serving time to the LAN, interface binding and orphan mode are configured from the UI and written to the chrony daemon; the status page shows each source with its offset, jitter and delay read live from chrony.
  • Maintenance. Reboot and shutdown, immediate or scheduled.
  • Service monitoring. monit watches the services and the system limits, alerts by mail and restarts what it can. The control file is generated from the UI and the daemon is the one Debian ships.
  • Power savings. The four power modes are applied as the closest governor the cpufreq driver of the machine offers, with the energy performance preference where the platform exposes it, and they follow the AC line on a laptop or an appliance with a battery.
  • Packages and updates. MurOS installs and updates as a Debian package from the MurOS apt repository; installed packages and available updates are read through dpkg and apt, and the changelog of a version comes from the package itself, so a pending update can be read before it is applied. The full upgrade flow is in progress.

HTTP access 90%

  • Accounts. The web UI and SSH share the same accounts through PAM. Local accounts are real Debian accounts, created and synced with the shadow utilities (useradd, usermod, groupadd). root is the default administrator; grant or revoke web UI access per account.
  • TOTP MFA. Standard RFC 6238, any authenticator app.
  • Reachability at the firewall. The web UI listens on every interface; you decide who can reach it with a filter rule, the same way you expose any other service.
  • HTTP / HTTPS ports. Configurable, with HTTP -> HTTPS redirect.
  • TLS certificate. Upload an existing PEM cert + key, or generate a self-signed RSA 4096 in one click.

Console & SSH 90%

  • Shared accounts. Console and SSH authenticate through Linux-PAM against the same MurOS accounts as the web UI.
  • root by default. The root password is the one used for the web UI.
  • Serial console. Enable a serial console at the chosen baud rate; it is wired through systemd (serial-getty), and the local video console stays available alongside it.
  • sshd options from the UI (listen address, keys) are in progress.

Hardening 85%

  • Network hardening defaults. A curated set of kernel parameters is applied at boot: ICMP redirect and source-route rejection, reverse-path martian logging, TCP SYN cookies, smurf protection and no IPv6 privacy addresses. IPv4 and IPv6 forwarding ship as a sysctl.d drop-in.
  • System tunables editor. Add or override any kernel parameter from the UI; the values are applied live through sysctl and persisted in the configuration.
  • HTTPS-only UI. The web interface is served over TLS, with a CSRF token and an HTTP referer check.
  • Anti-lockout. A mandatory rule keeps SSH and the web UI reachable even under a default-deny ruleset.
  • fail2ban and API rate limiting are in progress.