Beginner-friendly · no experience required

Flashing OPNsense onto a Mono Gateway Router

A guide for installing OPNsense onto your Mono Gateway router.

Time needed: ~25 minutes Computer: any with 1 USB + 1 Ethernet port Risk: fully reversible Skill level: copy, paste, wait

Every gray box below is a command. computer means type it on your own computer. router means type it on the router's text screen.

i
Using the mono-imager?

If you flash with the mono-imager tool, use v1.4.0 or newer and give it the .img.bz2 file from the images page: in LAN mode, its path on your computer; in USB mode, copy it to the stick. Save your config first, since the imager erases the router's storage.

Download the latest mono-imager · install instructions

The rest of this guide is the manual method, without the mono-imager.

!
Already running OPNsense? Save your config first

Flashing erases everything on the router, including your settings. Before you start, open the OPNsense dashboard, go to System › Configuration › Backups and click Download configuration. Keep that file on your computer: after flashing, you can restore it from the same page.

1
Before you start

What you need first

  • Your Mono Gateway Router, plugged into power, sitting nearby.
  • Any computer with one free USB port and one Ethernet port (built-in Ethernet is fine — if you only have USB ports free, a second USB-to-Ethernet adapter works too).
  • A plain USB-C cable (no separate adapter needed) — this gives you a text-only screen straight into the router, like a keyboard and monitor packed into one cable.
  • A regular Ethernet cable, and a USB-to-Ethernet adapter if your computer doesn't already have a spare Ethernet port — this is how the actual OPNsense file gets sent to the router.
  • A terminal app on your computer. Mac and Linux already have one built in. Windows 10/11 also has one built in (PowerShell), or you can use PuTTY instead if you prefer it — this guide shows PowerShell.

Not sure which port on your unit is the console port, or what the board looks like in general? Mono's own Getting Started guide and hardware description cover the physical layout in detail.

2
Get the file

Download the OPNsense image

"The image" is one big file that contains an entire, ready-to-run copy of OPNsense — the operating system, the firewall, the web dashboard, everything. Download it to your computer, anywhere easy to find, like your Desktop.

↓
Download

mono-opnsense.sincevic20.com/images — download OPNsense-202610081133-arm-aarch64-GATEWAY.img.bz2 (618 MB).

It downloads as a compressed .img.bz2 file. You don't need to decompress it yourself, that is done later automatically.

i
Optional but worth it: check the file isn't damaged

Big downloads occasionally arrive corrupted without any error showing up. You can confirm your copy matches before going any further. Run whichever of these matches your computer, from the folder you downloaded into:

computer — Mac
shasum -a 256 OPNsense-202610081133-arm-aarch64-GATEWAY.img.bz2
computer — Linux
sha256sum OPNsense-202610081133-arm-aarch64-GATEWAY.img.bz2
computer — Windows (PowerShell)
Get-FileHash OPNsense-202610081133-arm-aarch64-GATEWAY.img.bz2 -Algorithm SHA256

The result must be f81030c95147eaa989dab4a179c439696cd914536d207c6892c7c2bd4af9691d (Windows shows it in capital letters, which is the same). If it doesn't match, delete the file and download it again rather than continuing.

3
Plug everything in

Connect your computer to the router

Two connections, both from your computer to the router:

Your computer
USB port (plain USB-C cable)
Router
USB-C UART / console port
Your computer
Ethernet port (built-in or USB adapter)
Router
Port 3 (the network port closest to the two fiber/SFP+ slots)
i
Why port 3 specifically?

Any of the router's copper network ports can carry the file, but port 3 is the one this guide's commands are already set up for. Plug into a different port and the router will just call it by a different internal name later on — stick with port 3 and you can copy every command exactly as written.

Unplug every other network cable from the router while you do this. With other cables in, several ports show a link and it's hard to tell which one is your computer's.

4
Wake it up

Open a text screen and enter Recovery Mode

Plug the USB-C cable into the router's console port and your computer, then open your terminal app and connect to it at 115200 baud — it has to match exactly or you'll just see garbled text.

computer — Mac / Linux
terminal.app
screen /dev/cu.usbserial-XXXXXXXX 115200

The exact device name (the XXXXXXXX part) will be different on your machine — if you're not sure what it's called, this command lists every matching device your computer can currently see:

terminal.app
ls /dev/cu.usbserial-*
i
If nothing shows up there (Mac / Linux)

The router does the USB-to-UART conversion internally, on the board itself, which is why this still shows up as a usbserial device even though you're just plugging in a plain USB cable — there's no separate adapter to buy or carry. If ls comes back empty, try ls /dev/cu.usbmodem* instead (Mac), or ls /dev/ttyUSB* instead (Linux), in case your system enumerates it differently.

computer — Windows

First, find which COM port the router is using: open Device Manager → expand Ports (COM & LPT) → look for an entry like USB Serial Port (COM5). Note the number, then connect using PowerShell's built-in serial support:

powershell
$port = new-Object System.IO.Ports.SerialPort COM5,115200,None,8,one
$port.Open()
while ($true) { Write-Host -NoNewline $port.ReadExisting() }
i
A friendlier option

That PowerShell snippet only receives text — typing commands back to the router needs more scripting than is worth pasting here. Most Windows users will have an easier time installing PuTTY instead: open it, choose connection type Serial, set Serial line to the COM port from Device Manager (e.g. COM5) and Speed to 115200, then click Open. From here on, whenever this guide shows a router command box, type it into that PuTTY window.

Now power-cycle the router (unplug and replug it, or use its power switch). Watch the text scroll by, and the moment you see a line like Hit any key to stop autoboot: — press any key. You have only a few seconds, so keep a finger on the keyboard as it boots. This drops you into a special typing prompt that looks like this:

router console
=> 

That little => is called the U-Boot prompt. Think of it as the router's control room — before any operating system has even started, this is where you tell it what to do. Everything below happens either here or one level "deeper," inside something called Recovery Linux. From the => prompt, type:

router
router console
run recovery

A bunch of text will scroll by as it starts up a small, temporary version of Linux whose only job is helping you install things. You'll know you're there when you see:

router console
recovery login: 

Type root and press Enter — no password needed.

✓
Checkpoint

You should have a clean prompt that looks like root@recovery:~#. If you see that, you're ready for the next step.

This whole process — entering Recovery Mode, what it's for — is also covered from Mono's side in their own flashing firmware guide and boot process overview, if you'd like the fuller picture of what's happening under the hood.

5
Set up the link

Give the router and your computer matching addresses

For the router and your computer to send the file back and forth, they both need an address on the same private little network — just the two of them, nothing else involved.

router
recovery console
ip link set eth2 up
ip addr add 10.0.0.69/24 dev eth2
i
Port 3 has a different name on newer firmware

eth2 is port 3's name on the router's factory firmware. If your router has had Mono's firmware update (v2026.09.2 or newer), Recovery Linux calls the same port eth0 instead (both confirmed on real hardware). The link check at the end of this step tells you which one you have.

Now switch to your computer. Find the Ethernet adapter you plugged in and give it a fixed address by hand:

computer — Mac
SettingValue
WhereSystem Settings → Network → (the Ethernet port you plugged into the router) → Details → TCP/IP
Configure IPv4Manually
IP Address10.0.0.1
Subnet Mask255.255.255.0
Router(leave blank)
!
If it doesn't seem to connect (Mac)

macOS sometimes shows "Self-Assigned IP" instead of the address you typed. If that happens, double check it's really set to "Manually" and not "Using DHCP," make sure the Ethernet cable is fully clicked in on both ends, and try switching the network adapter off and back on in Settings.

computer — Windows
SettingValue
WhereSettings → Network & internet → Ethernet → (the adapter you plugged into the router) → IP assignment → Edit
Edit IP assignmentManual
IPv4On
IP address10.0.0.1
Subnet mask255.255.255.0
Gateway(leave blank)
!
If it doesn't seem to connect (Windows)

Windows sometimes flags the connection "No internet" once you set a manual address — that's expected and fine, since this tiny network genuinely has no internet access; it doesn't mean something's wrong. If the router still can't be reached, confirm you edited the right adapter (not Wi-Fi), the cable is fully seated on both ends, and Windows Firewall isn't set to block this network as "Public" — set it to "Private" if prompted.

✓
Checkpoint

Back on the router, check the cable is on the port you set up:

router
recovery console
ip link show eth2

If the output includes LOWER_UP, the cable is on eth2 and you're set. If it doesn't, your firmware uses eth0 for port 3. Move the address over and check again:

router
recovery console
ip addr del 10.0.0.69/24 dev eth2
ip link set eth0 up
ip addr add 10.0.0.69/24 dev eth0
ip link show eth0

If neither shows LOWER_UP, make sure the cable is in port 3 and fully clicked in on both ends.

6
Hand off the file

Let the router grab the OPNsense file from your computer

Your computer is going to act like a tiny, temporary website that only the router can see, just so it can hand over the big file. Open a second terminal window on your computer, in the same folder as the file you downloaded — you'll need your first terminal window free for typing into the router (or, on Windows, your PuTTY window free).

computer — Mac / Linux
terminal.app (folder with the download)
python3 -m http.server 8000
computer — Windows

No need to install anything — PowerShell can serve the file on its own. Adjust the $dir line below if you saved the file somewhere other than your Desktop, then paste the whole block in:

powershell
# folder containing the downloaded file
$dir = "$env:USERPROFILE\Desktop"

$listener = New-Object System.Net.HttpListener
$listener.Prefixes.Add("http://10.0.0.1:8000/")
$listener.Start()
Write-Host "Serving $dir on port 8000 -- leave this window open"

while ($listener.IsListening) {
  $context = $listener.GetContext()
  $name = $context.Request.Url.LocalPath.TrimStart('/')
  $filePath = Join-Path $dir $name
  if (Test-Path $filePath) {
    Write-Host "Sending $name ..."
    $bytes = [System.IO.File]::ReadAllBytes($filePath)
    $context.Response.ContentLength64 = $bytes.Length
    $context.Response.OutputStream.Write($bytes, 0, $bytes.Length)
  } else {
    $context.Response.StatusCode = 404
  }
  $context.Response.Close()
}
!
First time running a script like this?

If PowerShell refuses with a message about "running scripts is disabled," that's Windows' default script-safety setting, and it's fine to loosen it just for this session (nothing is saved permanently): run Set-ExecutionPolicy -Scope Process Bypass first, in the same window, then paste the block above again.

This also loads the whole file into memory before sending it, which is fine for a one-time transfer but means you'll briefly see your RAM usage climb by the size of the image — expected, not a problem.

Leave that running — the little activity you see scroll by in a moment is a good sign, it means the router successfully connected.

7
The main event

Write OPNsense onto the router

Switch back to your router's terminal window. This step has three parts: save a small area of the router's storage (the 32MB boot section), write the OPNsense image to storage, then put that small boot section back in place.

7a · Save the startup firmware data

The first 32MB of the router's storage is reserved for its startup software (firmware). On a router that has had a Mono firmware update, that's where the firmware lives. The OPNsense image doesn't use this area, but writing the image to storage overwrites it with zeros. So we first need to save a copy of it to the router's memory:

router
recovery console
dd if=/dev/mmcblk0 of=/tmp/emmc-first32mb.bin bs=1M count=32

It finishes in a second or two with 32+0 records in / 32+0 records out.

i

Do this even if you've never updated your router's firmware. If the area is empty, you're just saving zeros and putting zeros back, which does no harm. You don't need to know which case you're in.

7b · Write OPNsense

This command does the actual work: it pulls the file from your computer, decompresses it on the fly, and writes it directly onto the router's internal storage chip.

router
recovery console
curl http://10.0.0.1:8000/<image-filename>.img.bz2 | bzip2 -dc | dd of=/dev/mmcblk0 bs=1M

Swap <image-filename> for the real name of the file you downloaded in step 2 — for example, OPNsense-202610081133-arm-aarch64-GATEWAY.img.bz2. If you're not sure you've typed it exactly right, switch to the terminal window from step 6 and check its output: every successful request the router makes shows up there, filename included. This takes a few minutes — you'll see a progress readout climbing toward 100%, followed by two lines ending in records in / records out, which is the router's way of saying "the whole file arrived and I wrote every byte of it."

7c · Put the startup firmware data back

Now write the saved copy back. skip=1 seek=1 leaves the first 4KB alone, so the new OPNsense partition table you just wrote stays in place. This is the same form of command Mono uses in its own firmware instructions.

router
recovery console
dd if=/tmp/emmc-first32mb.bin of=/dev/mmcblk0 bs=4096 skip=1 seek=1
sync

7d · Check it went back correctly

Run both of these. The two long codes they print must be identical:

router
recovery console
dd if=/dev/mmcblk0 bs=4096 skip=1 count=8191 | sha256sum
dd if=/tmp/emmc-first32mb.bin bs=4096 skip=1 | sha256sum

If they differ, run the two commands from 7c again, then check again.

!
Don't power off between 7b and 7c

Don't close the terminal or power off the router from the moment you start 7b until 7c has finished. Until then, the saved startup area exists only in the router's memory. This is the one genuinely risky moment in this whole guide.

If it does get interrupted, the router can still start from its other firmware copy (DIP switch on NOR, the factory default): enter Recovery Mode again and redo this step from 7b.

✓
Checkpoint

OPNsense now physically lives on the router, and its startup firmware data is exactly as it was before. It won't start OPNsense on its own yet, though — that's the next step.

8
One-time setup

Tell the router to boot into OPNsense automatically

Writing the image onto the router doesn't make it boot into OPNsense by itself — out of the box, the router doesn't know that's what it should do. This next part tells it to, just once, and it remembers from then on, every time it powers on.

Reboot the router and this time, interrupt it — the moment you see Hit any key to stop autoboot:, press a key, same as you did to reach Recovery Mode earlier. You should land back at the => prompt.

router
router console
reset

From the => prompt, type these four lines, pressing Enter after each one:

router
router console
setenv opnsense "load mmc 0:1 ${kernel_addr_r} kernel.img; load mmc 0:1 ${fdt_addr_r} dtb/mono-gateway-dk.dtb; booti 0x82000000 - 0x88000000"
setenv bootcmd_bak ${bootcmd}
setenv bootcmd "run opnsense || run recovery"
saveenv

The first line teaches the router how to start OPNsense. The second keeps a copy of the router's original startup behavior, safely tucked away, in case you ever want it back. The third makes OPNsense the new default, falling back to Recovery Mode only if something's missing. saveenv writes all of that down permanently, so it survives power-offs and reboots — not just this one session.

i
Undoing this later

If you ever want the router back to its out-of-the-box startup behavior, go back to this same => prompt and run setenv bootcmd ${bootcmd_bak}; saveenv. Nothing about the router's own bootloader is touched or overwritten by any of this — only a startup preference, and it's fully reversible.

9
Restart into it

Reboot the router

With that saved, the router finds and starts OPNsense on its own from now on. Reboot it one more time:

router
router console
reboot

Don't press anything during the countdown this time. Just watch — it should boot straight into OPNsense on its own.

10
The payoff

Confirm it's really working

Watch the text scroll by. You're looking for a screen that ends with something like this — the exact version number will likely be newer than what's shown here, and that's fine:

router console
*** OPNsense.internal: OPNsense 26.7.2_24 (aarch64) ***

 LAN (dtsec0)    -> v4: 192.168.1.1/24
 WAN (dtsec1)    ->

login: 

That's it. That's a real, complete, running copy of OPNsense, started entirely on its own. Log in with root and the password opnsense — the standard default for a freshly flashed image — to reach the console menu, or connect a computer to the router's LAN port and visit https://192.168.1.1 in a web browser to see the full graphical dashboard.

!
Change it right away

That default password is publicly known, since it's the same on every fresh OPNsense install. Change it as soon as you log in — in the web dashboard, under System → Access → Users.

✓
You're done

You can unplug the USB-C console cable now if you want — it was only ever needed to watch and type during setup. The router will keep booting into OPNsense on its own from here on, with no cables attached at all besides its network connections.

All done

That's the whole process

Two cables, a handful of copy-paste commands, and one file — and the router now runs a genuinely complete, self-built firewall operating system, entirely on its own power-on. If something along the way didn't match what this guide describes, the exact commands here were tested and confirmed working on real hardware, so it's worth re-checking the step just before where things diverged rather than assuming something's fundamentally wrong.

Login: root Password: opnsense