My Journey

  • Used Raspberry Pi to install OpenWrt as the main system, but also wanted to build a Minecraft server. The Pi’s performance wasn’t sufficient, so I needed to upgrade.
  • Purchased a Mini PC for the Minecraft server. Debian could also run a software OpenWrt router, but only as a bypass router. I thought it best to have a dedicated device for network management.
  • Tried various web managers that could run on Debian like Cockpit, but they weren’t satisfying. Webmin was even worse - like a system from 20 years ago.
  • Ran OpenWrt as a Docker container on Debian. First tried Docker’s host mode, but it defeated the purpose of Docker’s isolation and added unnecessary complexity. Then struggled with macvlan - the container couldn’t communicate with the host. Eventually gave up.
  • Used PVE virtual machines to install OpenWrt, then installed Debian on another VM with its gateway pointing to OpenWrt.
  • Had a power outage at home and worried about PVE stability. Returned to the previous setup: Raspberry Pi as OpenWrt gateway, Mini PC as Debian server, each doing their own thing.
  • Planned to sell the Raspberry Pi (didn’t end up selling it because Docker version Home Assistant is crippled, so I’ll use the Pi to run HA). The Raspberry Pi I bought for $70 could suddenly sell for $100. That profit difference could buy another Nanopi R2S as a gateway (didn’t sell the Pi but bought the R2S anyway).

Required Hardware and Software

Hardware

  • A computer with ethernet port
  • Raspberry Pi 4B+ with 2GB+ RAM
  • 8GB+ microSD card for the Pi
  • SD card reader
  • Ethernet cable
  • Monitor (optional), Micro USB to HDMI cable (optional)

Software

  • Balena Etcher. MacBook users can download this or use command line instead.
  • Virtual Box and Ubuntu VM (optional) for compiling OpenWrt firmware. You can also download pre-compiled firmware. Note: the first compilation needs 60GB, but compiling a full firmware library with all features needs more, so 128GB is recommended.
  • SecureCRT or PuTTy (optional). I use my system’s built-in terminal.

Getting the Image

Official Download

You can download the image from OpenWrt’s official website.

OpenWrt Images

Local Compilation

The official firmware is lightweight and includes nothing extra. We can install what we need later. But if you don’t want to reinstall applications after each firmware flash, you need to compile your own. This repository lets you choose applications and compile them into the kernel. The README has detailed compilation steps. You can compile once locally to familiarize yourself, then use GitHub Actions for future compilations.

First Compilation

  • First, clone the repo on Ubuntu:

    git clone https://github.com/coolsnowwolf/lede.git
    
  • Install dependencies:

    sudo apt update -y
    sudo apt full-upgrade -y
    sudo apt install -y ack antlr3 asciidoc autoconf automake autopoint binutils bison build-essential \
    bzip2 ccache cmake cpio curl device-tree-compiler fastjar flex gawk gettext gcc-multilib g++-multilib \
    git gperf haveged help2man intltool libc6-dev-i386 libelf-dev libfuse-dev libglib2.0-dev libgmp3-dev \
    libltdl-dev libmpc-dev libmpfr-dev libncurses5-dev libncursesw5-dev libpython3-dev libreadline-dev \
    libssl-dev libtool lrzsz mkisofs msmtp ninja-build p7zip p7zip-full patch pkgconf python3 \
    python3-pyelftools python3-setuptools qemu-utils rsync scons squashfs-tools subversion swig texinfo \
    uglifyjs upx-ucl unzip vim wget xmlto xxd zlib1g-dev
    
  • Update feeds and select configuration:

    cd lede
    ./scripts/feeds update -a
    ./scripts/feeds install -a
    make menuconfig
    
  • This command opens the configuration page. I use Raspberry Pi 4B. Below is a breakdown of these configurations. Choose as needed:

    # Target system for compilation
    TargetSystem:
      - Broadcom BCM27xx
    Subtarget:
      - BCM2711 boards (64 bit)
    TargetProfile:
      - Raspberry Pi 4B/400/4CM (64bit)
    
    # Image parameters
    TargetImages:
      - squashfs
      - KernelPartitionSize: 64
      - RootFilesystemPartitionSize: 2048
    
    # LuCI settings
    LuCI:
      Collections:
        - luci # Enable luci
      Modules:
        Translations:
          - Chinese(zh-cn) # Chinese support
      Themes:
        - luci-theme-agron # Add theme
      # LuCI applications
      Applications:
        - luci-app-adguardhome # Ad-blocking
        - luci-app-advanced-reboot
        - luci-app-alist # File sharing (compilation is time-consuming, better as separate software)
        - luci-app-aria2 # Download tool
        - luci-app-cloudflared
        - luci-app-ddns
        - luci-app-diskman
        - luci-app-dockerman # Docker
        - luci-app-filebrowser # File management
        - luci-app-filetransfer
        - luci-app-firewall # Firewall
        - luci-app-frps
        - luci-app-frpc # Intranet penetration
        - luci-app-hd-idle # Hard drive sleep
        - luci-app-lucky
        - luci-app-opkg # Package manager
        - luci-app-openvpn
        - luci-app-openvpn-server
        - luci-app-passwall # VPN
        - luci-app-qos # Quality of service
        - luci-app-samba # Network sharing
        - luci-app-smartdns # Optimize VPN
        - luci-app-upnp # UPnP service
        - luci-app-usb-printer
        - luci-app-wol # Wake on LAN
      Protocols:
      	- luci-protocol-wireguard
    
    # Optional tools
    BaseSystem:
      - block-mount # Add <Mount Points> menu to LuCI
      - blockd # Auto-mount devices
      - wireless-tools # Wireless extension tools
    Administration:
      - htop # better top
    
    # File system
    KernelModules:
      Filesystems:
        - kmod-fs-ext4
        - kmod-fs-f2fs
        - kmod-fs-ntfs
        - kmod-fs-squashfs
        - kmod-fs-vfat
        - kmod-fuse
    
      # Network card support
      NetworkDevices:
        - kmod-xxx # Wired NIC, select as needed
      NetworkSupport:
      	- kmod-wireguard
      WirelessDrivers:
        - kmod-rt2800-usb # Ralink RT5370 chipset USB wireless NIC driver
      USBSupport:
        - kmod-usb-net:
          - kmod-usb-net-asix # Asix wired NIC
          - kmod-usb-net-asix-ax88179 # USB 3.0 NIC chip AX88179
          - kmod-usb-net-rtl8152 # USB 2/3 NIC RTL8152/3 chip
          - kmod-usb-net-sr9700 # USB 2.0 NIC SR9700 chip
          - kmod-usb-core # Enable USB support
      	  - kmod-usb-hid # USB keyboard/mouse
      	  - kmod-usb-ohci # OHCI support for old USB
      	  - kmod-usb-storage # Enable USB storage
      	  - kmod-usb-storage-extras
      	  - kmod-usb-uhci # UHCI support for old USB
      	  - kmod-usb2 # Enable USB2 support
      	  - kmod-usb3 # Enable USB3 support
    
    # Network tools
    Network:
      DownloadManager:
        - ariang # Aria2 management page
      FileTransfer:
        - curl # Add curl command
        - wget-ssl # Add wget command
      IP Addresses and Names:
      	- ddns-scripts-cloudflare # For DDNS
      	- drill	# DDNS
      VPN:
      	- wireguard-tools
    
    # Utilities
    Utilities:
      Compression:
        - bsdtar # tar packing tool
        - gzip # GZ compression suite
      Disc:
        - fdisk # Disk partitioning tool
        - lsblk # Disk viewing tool
      Filesystem:
        - f2fs-tools
        - ntfs-3g # NTFS read/write support
        - resize2fs # Partition resize
      Terminal:
        - screen # Add screen
      - losetup
      - pciutils # Add lspci command
      - qrencode # wireguard qrcode
      - usbutils # Add lsusb command
    
  • My current configuration:

    TargetSystem:
      - Broadcom BCM27xx
    Subtarget:
      - BCM2711 boards (64 bit)
    TargetProfile:
      - Raspberry Pi 4B/400/4CM (64bit)
    
    TargetImages:
      - squashfs
      - KernelPartitionSize: 64
      - RootFilesystemPartitionSize: 6144
    
    LuCI:
      Themes:
        - luci-theme-agron
    
      Applications:
        - luci-app-adguardhome
        - luci-app-autoreboot
        - luci-app-ddns
        - luci-app-filetransfer
        - luci-app-firewall
        - luci-app-nlbwmon
        - luci-app-opkg
        - luci-app-passwall
        - luci-app-ramfree
        - luci-app-sqm
        - luci-app-wol
      Protocols:
      	- luci-protocol-wireguard
    
    Network:
      IP Addresses and Names:
      	- ddns-scripts-cloudflare
      	- drill
      - tcpdump
    
    Utilities:
      - qrencode
    
  • A summary of Target Images:

    • If you want to run directly on physical hardware like Raspberry Pi with firmware on SD card, use squashfs.
    • If you want to package OpenWrt as a Docker image, select tar.gz.
    • If you want to run as a PVE virtual machine on a Mini PC, see Installing PVE on x86 Mini PC | Kunyang’s Blog.
    • If you haven’t decided on deployment yet, select all.
    • Different architectures have different options.
    • RootFilesystemPartitionSize is the system size after installation. I chose 6144M for my Pi’s 8GB SD card. If using PVE, you don’t need to worry about this as you assign disk size in PVE.
  • After configuration, select Save. This saves a .config file. Before the final installation step, install screen for persistent sessions (without it, closing SSH loses compilation progress):

    sudo apt install screen
    screen -S buildlede
    
  • Finally, download dl library with 8 threads, compile with 1 thread for first build. (I had trouble downloading on AWS Ubuntu, so switched to local Ubuntu and it worked):

    make download -j8
    make V=s -j1
    

Single Module Compilation

Sometimes you discover you need a plugin while using it. You can compile just that module:

  • Edit .config file:

    make menuconfig
    
  • Find the plugin you want to compile separately, like luci-app-diskman (for managing router disks/partitions). If you selected [*] the first time (built-in module), select [M] this time (module that can be unloaded):

    Compile Module

    Use this command to compile:

    make package/luci-app-diskman/compile V=s
    
  • Open OpenWrt, go to System → File Transfer to upload the file. Click Install in the bottom-right.

  • The newly installed plugin might not appear immediately - it took some time for me.

To compile kernel modules separately, like kmod-wireguard, select it as [M], then run:

make package/kernel/linux/compile V=s

Compilation finishes quickly. The compiled package is at bin/packages/<target>/<package-repo>/kmod-wireguard_xxx.ipk

Second Compilation

  • Pull the latest feeds:

    sudo sh -c "apt update && apt upgrade -y"
    git pull
    ./scripts/feeds update -a && ./scripts/feeds install -a
    
  • Clean old build artifacts (optional):

    make clean
    # Execute after major updates or kernel changes to ensure build quality
    # Deletes files in /bin and /build_dir
    
    make dirclean
    # For architecture changes from x86_64 to MediaTek Ralink MIPS, recommended to do deep clean
    # Deletes /bin, /build_dir, /staging_dir, /toolchain, /tmp, and /logs
    
  • Compile:

    make defconfig
    make download -j8
    find dl -size -1024c -exec ls -l {} \;
    make -j$(nproc) || make -j1 || make -j1 V=s
    

GitHub Actions Compilation

After familiarizing yourself with local compilation, use GitHub Actions to offload the work to the cloud. I found this repository and decided not to reinvent the wheel.

Note: if you want to auto-publish Artifacts to Release, grant PAT permissions in Settings → Developer Settings → Personal access tokens → Tokens (classic) → Your Token. Check workflow and write:packages:

GitHub PAT Permissions

Flashing

For direct flashing, select the image openwrt-bcm27xx-bcm2711-rpi-4-squashfs-factory.img.gz

Windows

Use Balena Etcher or other disk imager software to flash the image to your SD card. It’s very straightforward:

Balena Etcher for Windows

MacOS

MacOS can also use Balena Etcher, or use command line if you prefer:

  • Find the SD card’s disk number. Mine is /dev/disk4:

    diskutil list
    /dev/disk4 (external, physical):
       #:                       TYPE NAME                    SIZE       IDENTIFIER
       0:     FDisk_partition_scheme                        *7.9 GB     disk4
       1:             Windows_FAT_32 BOOT                    67.1 MB    disk4s1
       2:                      Linux                         109.1 MB   disk4s2
                        (free space)                         7.7 GB     -
    

    I had a previous OpenWrt without GUI, so the SD card had extra partitions. I’m reinstalling with GUI support.

  • First restore the partition (this also formats the SD card):

    diskutil eraseDisk FAT32 SDCARD MBRFormat /dev/disk4
    

    After restoring:

    diskutil list
    /dev/disk4 (external, physical):
       #:                       TYPE NAME                    SIZE       IDENTIFIER
       0:     FDisk_partition_scheme                        *7.9 GB     disk4
       1:                 DOS_FAT_32 SDCARD                  7.9 GB     disk4s1
    
  • Unmount (but don’t eject) the SD card to avoid “busy” errors:

    diskutil unmountDisk /dev/disk4
    
  • Decompress the downloaded image:

    gunzip ./openwrt-bcm27xx-bcm2711-rpi-4-squashfs-factory.img.gz
    
  • Use dd to write the decompressed .img file. Be very careful with the disk number - mistakes are irreversible:

    sudo dd if=/Users/xxx/Desktop/openwrt-bcm27xx-bcm2711-rpi-4-squashfs-factory.img of=/dev/disk4 bs=1M status=progress
    

    No errors usually means success.

  • Eject the SD card from your computer and insert it into the Raspberry Pi. Start the Pi and connect its ethernet port to your computer’s ethernet port. OpenWrt defaults to bridges the Pi’s eth0 to br-lan with IP 192.168.1.1. Configure your computer’s Ethernet interface to also be on the 192.168.1.x subnet (x can be 2-255):

    IP Config

    Once they’re on the same subnet, enter 192.168.1.1 in your browser to access OpenWrt’s GUI (LuCI). Default username and password are root and password.

  • Done!

    Initial Page

    Status Page

Packaging OpenWrt as a Docker Image

See: Creating OpenWrt as a Docker Image | Kunyang’s Blog

Connecting to Main Router

  • My home main router uses subnet 192.168.2.x. I need to change the Pi to this subnet.

Single Network Port

  • Since the Pi has only one eth0 port, I recommend setting it as the LAN port:

    vi /etc/config/network
    
    config interface 'lan'
            option device 'br-lan'
            option proto 'static'
            option netmask '255.255.255.0'
            option ip6assign '60'
            option ipaddr '192.168.2.66'
            option gateway '192.168.2.1'
            option dns '192.168.2.1'
    
  • Disable DHCP to avoid conflicts with the main router:

    vi /etc/config/dhcp
    
    config dhcp 'lan'
            option interface 'lan'
            option ignore '1'
    
  • Check firewall configuration:

    vi /etc/config/firewall
    
    config zone
            option name 'lan'
            list network 'lan'
            option input 'ACCEPT'
            option output 'ACCEPT'
            option forward 'ACCEPT'
    
  • Apply settings:

    /etc/init.d/network restart
    
  • Now your computer is on 192.168.1.x but the Pi is on 192.168.2.x, so connection is lost. Change your computer’s Ethernet to 192.168.2.x to reconnect.

  • Disconnect the Pi from your computer and connect it to the router’s LAN port. It should have normal network access, and your computer can access the Pi.

Setting up Bypass Router

The above steps just add the Pi as a network device. Your devices still route through the main router. To make it a bypass router:

  • Simply change your WiFi gateway from the main router’s default to the Pi’s IP. If my main router is 192.168.2.1, my computer is 192.168.2.54, and my Pi is 192.168.2.66:

    Windows Configure Gateway

  • Same for MacBook:

    MacBook Configure Gateway

    MacBook Configure DNS

  • iPhone configuration is similar.

  • I use this non-invasive approach to avoid breaking the entire network. Only affects devices with gateway set to the bypass router.

Tutorial video:

Installing Plugins

Uninstalling Plugins

  • Go to System → Software → Installed to uninstall plugins
  • Plugins compiled into the firmware cannot be uninstalled

Installing Plugins

Direct Installation

Foreign source ARM:

src/gz openwrt_core https://downloads.openwrt.org/releases/23.05.0/targets/bcm27xx/bcm2711/packages
src/gz openwrt_base https://downloads.openwrt.org/releases/23.05.0/packages/aarch64_cortex-a72/base
src/gz openwrt_luci https://downloads.openwrt.org/releases/23.05.0/packages/aarch64_cortex-a72/luci
src/gz openwrt_packages https://downloads.openwrt.org/releases/23.05.0/packages/aarch64_cortex-a72/packages
src/gz openwrt_routing https://downloads.openwrt.org/releases/23.05.0/packages/aarch64_cortex-a72/routing
src/gz openwrt_telephony https://downloads.openwrt.org/releases/23.05.0/packages/aarch64_cortex-a72/telephony

Foreign source x86:

src/gz openwrt_core https://downloads.openwrt.org/releases/23.05.0/targets/x86/64/packages
src/gz openwrt_base https://downloads.openwrt.org/releases/23.05.0/packages/x86_64/base
src/gz openwrt_luci https://downloads.openwrt.org/releases/23.05.0/packages/x86_64/luci
src/gz openwrt_packages https://downloads.openwrt.org/releases/23.05.0/packages/x86_64/packages
src/gz openwrt_routing https://downloads.openwrt.org/releases/23.05.0/packages/x86_64/routing
src/gz openwrt_telephony https://downloads.openwrt.org/releases/23.05.0/packages/x86_64/telephony

Domestic source ARM:

src/gz openwrt_core https://mirrors.tencent.com/lede/snapshots/targets/bcm27xx/bcm2711/packages
src/gz openwrt_base https://mirrors.tencent.com/lede/snapshots/packages/aarch64_cortex-a72/base
src/gz openwrt_luci https://mirrors.tencent.com/lede/releases/18.06.9/packages/aarch64_cortex-a72/luci
src/gz openwrt_packages https://mirrors.tencent.com/lede/snapshots/packages/aarch64_cortex-a72/packages
src/gz openwrt_routing https://mirrors.tencent.com/lede/snapshots/packages/aarch64_cortex-a72/routing
src/gz openwrt_telephony https://mirrors.tencent.com/lede/snapshots/packages/aarch64_cortex-a72/telephony

Domestic source x86:

src/gz openwrt_core https://mirrors.tencent.com/lede/releases/24.10.0-rc1/targets/x86/64/packages
src/gz openwrt_base https://mirrors.tencent.com/lede/releases/24.10.0-rc1/packages/x86_64/base
src/gz openwrt_helloworld https://mirrors.tencent.com/lede/releases/24.10.0-rc1/packages/x86_64/helloworld
src/gz openwrt_luci https://mirrors.tencent.com/lede/releases/24.10.0-rc1/packages/x86_64/luci
src/gz openwrt_packages https://mirrors.tencent.com/lede/releases/24.10.0-rc1/packages/x86_64/packages
src/gz openwrt_routing https://mirrors.tencent.com/lede/releases/24.10.0-rc1/packages/x86_64/routing
src/gz openwrt_telephony https://mirrors.tencent.com/lede/releases/24.10.0-rc1/packages/x86_64/telephony

Self Compilation

  • First compile the plugin on Ubuntu:

    make menuconfig
    

    In LuCI → Applications, select all plugins (building a firmware library). Modularize by pressing space to add M in brackets. Save and start compiling:

    make -j1 V=s
    
  • After compilation, find all compiled plugins in bin\packages in .ipk format.

Common Use Cases

DDNS

Ad Blocking

Accessing My Windows Desktop from Outside

Wireguard

ZeroTier

  • Required plugin:
    • luci-app-zerotier

OpenVPN

  • Required plugins:
    • luci-app-openvpn
    • luci-app-openvpn-server
    • luci-i18n-openvpn-server-zh-cn
    • luci-i18n-openvpn-zh-cn
    • open-vpn-easy-rsa
    • openvpn-openssl

Other Self-Hosted Services