Using a CRS304 for Local 10GbE and Staged Egress Control
Using a CRS304 as both the RouterOS router and 10GbE local switch, with VLAN segmentation, allowlist-based egress control, and Prometheus/Loki monitoring.
Introduction
When I first put the CRS304 under RouterOS, the obvious starting point was VLAN separation and a conservative firewall baseline. That part was already clear. The harder part was day-to-day operation: I wanted the Linux box to stay effectively offline most of the time, but I also wanted to keep a fast local 10GbE path between Linux and my Mac. I did not want to give up local transfer performance just to simplify outbound control.
The final shape of the design was to use the CRS304 as both the VDSL-edge router and the local switch. Port2 and Port3 stay focused on local wired traffic, the Wi-Fi AP carries household internet-facing clients on separate segments, Linux new outbound traffic is governed by allowlists, Mac remains looser for everyday use, all ISP-side inbound traffic is dropped, and monitoring is pushed into Prometheus and Loki.
This article combines the original VLAN and RouterOS design with the later operational note that clarified the physical topology, expected performance envelope, firewall policy, and observability model. The goal stayed consistent throughout: keep local traffic local, and open the minimum possible egress only when needed.
Background and Goals
Putting daily-use clients, Wi-Fi devices, IoT gear, and an experiment-heavy Linux machine into one mental bucket leads to blurry policy. The Linux host was the main issue. Most of the time I wanted it dedicated to local development and file transfer. Occasionally I needed package updates or other narrowly scoped outbound access. At the same time, I still wanted local 10GbE transfers between Linux and the Mac.
The design goals became:
- preserve high-speed local transfer between Mac and Linux
- keep Linux offline by default or restricted to a very small allowlist
- avoid over-restricting the Mac for normal daily work
- separate IoT and mobile Wi-Fi traffic from the wired local segment
- drop all inbound traffic from the ISP side
- keep enough metrics and logs to audit what the policy is actually doing
The RouterOS baseline provided VLAN segmentation, stateful firewalling, and destination-based controls. The later note turned that into an operational design that also accounted for physical port roles and future migration beyond VDSL.
Overall Design Summary
The fixed port roles are:
Port1 = WANPort2 = Mac or wired client sidePort3 = LinuxPort4 = Wi-Fi AP trunkPort5 = console / management
The VLAN model remains:
VLAN10 = Wired-LANVLAN20 = Trusted Wi-FiVLAN30 = IoT Wi-Fi
Once the second note is folded in, the practical interpretation becomes: Port2 and Port3 are for local-first wired traffic, the Wi-Fi AP carries the internet-facing household side, Linux new connections are allowlist-based, WAN-side input is fully dropped, and the router is monitored via SNMP exporter and Syslog to Loki.
1) Address Plan (Example)
The base RouterOS plan uses:
10.10.10.0/24for wired LAN10.20.20.0/24for trusted Wi-Fi10.30.30.0/24for IoT Wi-Fi- DHCP on the WAN side
The later operational note also describes the device roles in a simpler shorthand:
| Device | IP | Purpose |
|---|---|---|
| ONU | ISP-assigned (WAN side) | VDSL termination |
| CRS304 | 1.10 | Router / NAT / DHCP server |
| Wi-Fi AP | 1.11 | Wireless client side |
| Mac | 1.12 | Local wired peer for Linux |
| Linux | 1.13 | Primarily local transfer, with controlled outbound access |
I treat those two views as different layers of the same design. The 10.x ranges describe the implementation-level segmentation. The 1.10 to 1.13 notation is the simpler operational map.
2) RouterOS v7 Configuration Script (Draft)
This was the baseline RouterOS configuration covering the bridge, VLAN interfaces, DHCP, DNS, NAT, and firewall policy.
# ========== インタフェースとブリッジ ==========
/interface bridge add name=br-core vlan-filtering=yes protocol-mode=none
# 物理ポート割当(例)
# ether1=Port1(WAN), sfp-sfpplus1=Port2(Mac), sfp-sfpplus2=Port3(Linux),
# sfp-sfpplus3=Port4(AP), sfp-sfpplus4=Port5(Console)
# 実機のif名に合わせて修正
/interface bridge port
add bridge=br-core interface=sfp-sfpplus1 pvid=10 # Mac: access VLAN10
add bridge=br-core interface=sfp-sfpplus2 pvid=10 # Linux: access VLAN10
add bridge=br-core interface=sfp-sfpplus3 # AP: trunk (tagged)
add bridge=br-core interface=sfp-sfpplus4 pvid=10 # Console: access VLAN10(管理をLANから)
# WAN はブリッジに入れない(ルーターポートとして独立)
# ether1 は WAN 専用
# ========== VLAN インタフェース ==========
/interface vlan
add name=vlan10-LAN interface=br-core vlan-id=10
add name=vlan20-TRUST interface=br-core vlan-id=20
add name=vlan30-IOT interface=br-core vlan-id=30
# ========== VLAN タグ付与設定 ==========
/interface bridge vlan
# VLAN10: access on Port2/3/5 (untagged), tagged on bridge-cpu
add bridge=br-core vlan-ids=10 tagged=br-core untagged=sfp-sfpplus1,sfp-sfpplus2,sfp-sfpplus4
# VLAN20: tagged on AP trunk + bridge-cpu
add bridge=br-core vlan-ids=20 tagged=br-core,sfp-sfpplus3
# VLAN30: tagged on AP trunk + bridge-cpu
add bridge=br-core vlan-ids=30 tagged=br-core,sfp-sfpplus3
# ========== IP アドレス ==========
/ip address
add address=10.10.10.1/24 interface=vlan10-LAN comment="LAN gw"
add address=10.20.20.1/24 interface=vlan20-TRUST comment="Trusted gw"
add address=10.30.30.1/24 interface=vlan30-IOT comment="IoT gw"
# WAN は DHCP
/ip dhcp-client add interface=ether1 use-peer-dns=no use-peer-ntp=yes add-default-route=yes
# ========== DHCP サーバ(Wi-Fi用。LANは固定でも可) ==========
/ip pool add name=pool-trust ranges=10.20.20.100-10.20.20.199
/ip pool add name=pool-iot ranges=10.30.30.100-10.30.30.199
/ip dhcp-server add name=dhcp-trust interface=vlan20-TRUST address-pool=pool-trust lease-time=12h
/ip dhcp-server add name=dhcp-iot interface=vlan30-IOT address-pool=pool-iot lease-time=12h
/ip dhcp-server network
add address=10.20.20.0/24 gateway=10.20.20.1 dns-server=10.20.20.1
add address=10.30.30.0/24 gateway=10.30.30.1 dns-server=10.30.30.1
# ========== DNS(ルータを唯一のDNSに) ==========
/ip dns set servers=1.1.1.1,8.8.8.8 allow-remote-requests=yes use-doh-server="" verify-doh-cert=no
# ========== アドレスリスト(Port3-Linuxの許可先) ==========
# 直接IPで許可したい先
/ip firewall address-list
add list=allowlist-Linux comment="例: Gitホスト" address=203.0.113.10
add list=allowlist-Linux comment="例: R2/Cloud" address=198.51.100.20
# もしドメイン許可が必要なら(動的解決):
# RouterOS v7は /ip/firewall/address-list add address=example.com でFQDN可(DNS依存)
add list=allowlist-Linux address=github.com
add list=allowlist-Linux address=registry-1.docker.io
add list=allowlist-Linux address=ghcr.io
# ========== NAT ==========
# Trusted/IOT → WAN のみマスカレード(LAN→WANは不可にするので不要でも良いが保険でON)
/ip firewall nat
add chain=srcnat src-address=10.20.20.0/24 out-interface=ether1 action=masquerade comment="Trusted -> WAN"
add chain=srcnat src-address=10.30.30.0/24 out-interface=ether1 action=masquerade comment="IoT -> WAN"
# VLAN10(LAN) はインターネット禁止のため NAT しない(誤設定時の外出し防止)
# ========== Firewall 基本ポリシー ==========
# 1) 既定:全部閉じる(最後に drop)
# 2) state: established, related は許可。invalidはdrop
# 3) WAN→ルータ input は既定 drop(必要最小限のみ許可)
# 4) forward はVLAN間/対WANをポリシーベースで制御
/ip firewall filter
# --- hygiene
add chain=input connection-state=invalid action=drop comment="DROP invalid"
add chain=forward connection-state=invalid action=drop comment="DROP invalid"
add chain=input connection-state=established,related action=accept
add chain=forward connection-state=established,related action=accept
# --- WAN側からの input は all drop(DHCPクライアントの更新等は別経路)
add chain=input in-interface=ether1 action=drop comment="DROP all from ISP(WAN)"
# --- ルータ管理:VLAN10 からのみ許可(Winbox/SSH/HTTPS 等)
add chain=input in-interface=vlan10-LAN src-address=10.10.10.0/24 action=accept comment="Mgmt from LAN"
# 必要なら VLAN20 からも限定許可
# add chain=input in-interface=vlan20-TRUST src-address=10.20.20.0/24 action=accept
# --- DNS サービス(全VLANからルータのDNSを使わせる)
add chain=input protocol=udp dst-port=53 in-interface-list=LAN action=accept comment="DNS UDP"
add chain=input protocol=tcp dst-port=53 in-interface-list=LAN action=accept comment="DNS TCP"
# インターフェイスリストでLAN系を包括
/interface list add name=LAN
/interface list member
add list=LAN interface=vlan10-LAN
add list=LAN interface=vlan20-TRUST
add list=LAN interface=vlan30-IOT
# --- VLAN間ポリシー ---
# 既定:相互隔離(必要な穴だけ下に書く)
# 1) IoT は他VLANへのアクセス禁止(DNSは input で受けるためOK)
add chain=forward in-interface=vlan30-IOT out-interface=!ether1 action=drop comment="Isolate IoT to others"
# 2) Trusted -> LAN を既定禁止(必要なら個別許可)
add chain=forward in-interface=vlan20-TRUST out-interface=vlan10-LAN action=drop comment="Block Trusted->LAN by default"
# 3) LAN(有線) 同士は許可(Mac/Linus/Console間のローカル通信)
add chain=forward in-interface=vlan10-LAN out-interface=vlan10-LAN action=accept comment="Allow LAN intra"
# --- WAN への出口ポリシー ---
# VLAN10(LAN) は WAN 禁止
add chain=forward src-address=10.10.10.0/24 out-interface=ether1 action=drop comment="Block LAN->WAN"
# VLAN20/30 は WAN 許可(上の established でOK。念のため明示)
add chain=forward src-address=10.20.20.0/24 out-interface=ether1 action=accept comment="Trusted->WAN"
add chain=forward src-address=10.30.30.0/24 out-interface=ether1 action=accept comment="IoT->WAN"
# --- ポート別要件(Port2/3) ---
# Port2=Mac(LAN内 NEW 制限なし)→ 既に VLAN10 intra を許可済み。WAN は上で禁止。
# Port3=Linux(NEW は allowlist のみ + ローカル)
# 1) Linux のIPまたはMACで識別(例はIP固定: 10.10.10.13)
/ip firewall address-list add list=linux-host address=10.10.10.13
# 2) Linux からの NEW を既定 drop(まずブロックしてから穴あけ)
add chain=forward src-address-list=linux-host connection-state=new action=drop comment="Linux NEW default drop"
# 3) 例外許可:LAN内(Mac/Console/ルータ)へは NEW 許可
add chain=forward src-address-list=linux-host dst-address=10.10.10.0/24 connection-state=new action=accept comment="Linux NEW to LAN allowed"
# 4) 例外許可:allowlist (FQDN/IP) 宛は NEW 許可
add chain=forward src-address-list=linux-host dst-address-list=allowlist-Linux connection-state=new action=accept comment="Linux NEW to allowlist allowed"
# --- 既定 DROP(最後尾) ---
add chain=input action=drop comment="Default drop input"
add chain=forward action=drop comment="Default drop forward"
That baseline was already useful, but the second note made the operating model much more concrete.
Logical Design (Zone Separation)
The refined model splits Linux outbound usage into two zones:
VLAN10 (192.168.10.0/24)for updatesVLAN15 (192.168.15.0/24)for long-running training or temporary internet-dependent work
The allowed destinations also differ by intent:
dev-allowforapt,pip,npm,docker,github, andgoogletemporary-allowforHuggingFace,Kaggle, and container registries
What mattered in the later note, though, was not just the logical model. It also clarified the physical topology, local switching requirement, and expected routing limits. That made the design usable in practice instead of just defensible on paper.
Topology
The physical layout is:
ONU (VDSL) → CRS304 (Router)
|
|-- Port1 → WAN
|-- Port2 → Mac (1.12, primarily on Wi-Fi, wired for local-only use)
|-- Port3 → Linux server (1.13, wired for local-only use)
|-- Port4 → WiFi AP
|-- Port5 → Console
This lets the CRS304 play three roles at once:
- the router directly attached to the ONU
- the 10GbE switch for local Mac-to-Linux transfer
- the aggregation point for household Wi-Fi and the local wired segment
Because Port2 and Port3 stay on the local L2 path, large file transfer and local development workflows do not need to touch the WAN path at all. That is the main reason I kept the design wired-first for local traffic.
IP and Routing Layout
The operational shorthand from the second note is:
| Device | IP | Purpose |
|---|---|---|
| ONU | ISP-assigned (WAN side) | VDSL edge |
| CRS304 (router) | 1.10 | Router / NAT / DHCP server |
| Wi-Fi AP | 1.11 | Wireless client side |
| Mac | 1.12 | Local wired peer for Linux |
| Linux | 1.13 | Local transfer first, controlled outbound second |
That makes the traffic split easy to reason about: Linux-to-Mac stays local, while internet-facing access flows through the Wi-Fi side and the router policy.
CRS304 Role
The second note helped frame the CRS304 as more than a stopgap router.
As a router
It terminates the VDSL side at the ONU and handles NAT, DHCP, and firewalling. For a roughly 100 Mbps-class line, RouterOS performance is good enough.
As a switch
Port2 and Port3 can be used as the local 10GbE path, so file transfer and local dataset movement do not need another dedicated switch.
As the integration point
By hanging the Wi-Fi AP off Port4, the router can keep household wireless clients on separate segments while still centralizing policy.
Operational Rules
The key improvement in the original zone design was to make physical operation part of the security boundary:
- leave Linux
NIC3unplugged by default - connect it to
ether2only for the update zone - connect it to
ether3only for the learning or temporary zone - switch the matching IP and gateway on the Linux side
The later note simplifies the same idea in practical terms: the wired link between Mac and Linux stays focused on local use, and outbound traffic only happens through an explicitly permitted path. Linux settings alone are not enough. Cable placement alone is not enough. Router rules alone are not enough. That is what keeps the day-to-day behavior predictable.
3) Wi-Fi AP Settings (Concept)
On the AP side, ether4 is used as a trunk carrying VLAN20 and VLAN30.
- one SSID maps to the trusted side
- one SSID maps to the IoT side
That keeps routine client internet access separate from the stricter wired Linux workflow.
4) Additional Hardening Ideas
The follow-up ideas remain straightforward:
- place AdGuard Home in front of upstream DNS to manage allowlists and denylists more comfortably
- add an mDNS relay only if cross-segment discovery is actually required
- keep log-prefixed drop rules so missing destinations can be identified from real traffic
RouterOS can enforce a lot on its own, but FQDN-oriented policy gets easier to operate when DNS behavior is also visible.
5) Validation Checklist
The earlier checklist is still valid:
- Linux should not reach the WAN during normal operation
dev-allowandtemporary-allowshould stay separate- trusted Wi-Fi and IoT should remain segmented
- inter-VLAN traffic should stay closed unless explicitly allowed
- router management must not be exposed from the WAN side
The later note adds a few practical checks:
- Port2 and Port3 should provide local transfer without traversing the WAN path
- the Mac should remain usable without unnecessary friction
- Linux should stay local-first and only gain egress in narrow, intentional cases
- drop logs, login failures, and config changes should all be observable
Benefits of This Layout
It matches the current VDSL environment
The CRS304 is not a high-end router, but that is not the requirement right now. On a 100 Mbps-class VDSL line, its RouterOS performance is sufficient, and the combination of routing plus local 10GbE switching is more valuable than raw routing headroom.
It preserves future reuse
If I later move to 1G or 10G fiber, the design already has a clean migration path: move the CRS304 into SwOS as a dedicated switch and place a stronger router such as a CCR, RB5009, or L009 in front of it.
It stays practical to run continuously
The power envelope, roughly 15 to 21 watts, makes it friendly to UPS-backed, always-on use.
Switching Results
The switching-side figures are:
- non-blocking Layer 2 throughput/capacity of roughly
39,480 Mbpsto40,000 Mbps - even with 64-byte packets, about
30to40 Gbps
For local transfer, those numbers are more than enough. That is exactly the kind of workload I care about between the Mac and the Linux box.
Ethernet Test Results
For RouterOS paths that involve the CPU, the summary is:
| Mode | Condition | Measured |
|---|---|---|
| Bridging (none, fast path) | no filter | ~2.0 Gbps |
| Bridging (25 bridge filter rules) | bridge plus 25 filters | ~1.0 Gbps |
| Routing (none, fast path) | routing only | ~2.0 Gbps |
| Routing (25 simple queues) | 25 traffic-shaping rules | ~1.0 Gbps |
| Routing (25 ip filter rules) | 25 IP filters | ~0.5-1.5 Gbps |
So the picture is clear: plain routing or bridging is around 2 Gbps, and additional filtering or queuing pulls that down into the 0.5 to 1.0 Gbps range. That is still fine for the current line, but it is exactly the kind of data that informs a future FTTH redesign.
Network Layout and Operations Summary
At this point the design can be summarized in one sentence: use the CRS304 as the current RouterOS router plus the local 10GbE switch, while separating local wired traffic, household Wi-Fi, and Linux outbound access by role.
Physical Layout
VDSL → CRS304 (RouterOS)
| (All RJ45)
|-- Port1 → WAN
|-- Port2 → Mac (1.12, primarily Wi-Fi, wired = local-only)
|-- Port3 → Linux server (1.13, wired = local-only)
|-- Port4 → Wi-Fi AP (1.11, IoT/Mobile segment)
|-- Port5 → Console
- CRS304 acts as both router and switch
- Mac and Linux use 10GbE for local transfer
- the Wi-Fi AP handles the internet-facing segment, separate from the local wired side
Firewall Policy
Core Policy
- drop all inbound traffic from the ISP side
- base outbound control on domain allowlists
- leave Mac unrestricted for new outbound sessions
- restrict Linux to approved authoritative domains
- allow
established,related
Practical Enforcement
On Linux (Port3), new outbound sessions are limited to allowlisted domains. The explicitly mentioned destinations such as apt, pypi, and ghcr.io serve as examples of legitimate update sources. On Mac (Port2), new outbound sessions stay unrestricted for daily use. Across all ports, inbound traffic is dropped, RouterOS management is limited to a management address range, SSH is expected to use key-based auth, and drop rules carry log prefixes so audits are possible.
Metrics and Log Monitoring
The monitoring model deliberately separates hardware health from behavior anomalies.
SNMP exporter (Prometheus)
SNMP exporter collects CPU, memory, interface bandwidth, temperature, and uptime. In Grafana, the primary value is long-term trend tracking: sustained CPU load, changing bandwidth patterns, and general device health.
Syslog to Loki
Loki receives drop logs, SSH login failures, config changes, and DNS anomalies. Example Grafana queries:
count_over_time({job="routeros"} |= "DROP" [1m])
count_over_time({job="routeros"} |= "login failure" [5m])
That makes it easier to spot missing allowlist entries, unnecessary management access, or other unusual behavior close to real time.
Results
What this design clarifies is:
- the CRS304 is currently sufficient as both router and switch in the VDSL environment
- local high-speed transfer between Mac and Linux can stay intact while outbound access remains tightly controlled
- Wi-Fi clients can be separated cleanly from the local wired segment
- the observability path is good enough to refine the policy later instead of guessing blindly
The most useful result is the clean split between wired-local traffic, internet-facing Wi-Fi traffic, and explicit Linux egress paths.
Discussion and Future Work
This design fits the current VDSL and local 10GbE requirement well, but it should be revisited once the WAN side changes. If I move to fiber and start expecting higher routed throughput with heavier filtering, the CRS304 should probably stop acting as the RouterOS router and become a dedicated switch under SwOS instead.
For now, the next practical step is not redesign. It is operation: keep the setup stable, watch the drop logs and bandwidth trends, and tighten the allowlists without breaking the core principle that local traffic stays local and internet access stays intentional.
