Linksys AC Series Router Configuration Tips for OpenWRT
Jump to navigation Jump to search

This subject(s) of this article are the AC Series of routers manufactured by Linksys and the OpenWRT Firmware designed for them. The Linksys AC Routers include the WRT1200AC, WRT1900AC v1, WRT1900AC v2, WRT1900ACS v2, WR1900ACS v2, WRT3200ACM, and WRT32X. The WRT1900AC v2 is essentially a WRT1900ACS v1 and the WRT3200ACM and WRT32X are duplicate hardware models with different firmware (from Linksys) and the former blue / black and the latter black /gray. The models are sometimes referred to with out the suffix letters as WRT1200, WRT1900, WRT3200.

Information covered in this article was written for and tested on both the WRT1900ACS v1, WRT1900ACS v2, and WRT3200ACM. However the information applies to the other models as well.

All models are available on eBay and the ACS, ACM, and 32X series are available new as of the writing of this article in 2020. The most powerful and expensive models are the WRT3200ACM and the WRT32X. The best bargain used in terms of cost and "horsepower" is the ACS series. Occasionally it is possible to find a less than observant vendor on eBay selling an ACS model that is advertised as an AC model. Those are the best deals.

Details on each model are very nicely summarized on the OpenWRT website here:

As it started out, this article was intended to be a quick how to on a couple of items, but then grew to enormous proportions. There was some consideration on breaking it into smaller sections, but the Mediawiki interface with its table of contents mitigates that need to an acceptable level.

The information in this article comes from many sources and also from hard earned experience. It was collected in orderd to have a definitive repository of knowledge on the subject.


Quick C (as in Quick Configuration)

Because this article contains a lot of information in addition to "How to..." tutorials, this sections summarizes and provides links to the major "How to..." sections below.

  • Upgrade Firmware from Linksys to OpenWRT
  • Install a several basic software packages that add very useful utilities and access to USB and eSATA storage device (Flash Drive, HDD enclosures, and even mSATA and M.2 NGFF & NVMe SSDs in USB 3.0 enclosures). This includes backup software too.
  • Partition and Configure OpenWRT to use external storage drives, not just for storage, but also as a replacement / addition to the internal non-volitile storage



There are two hardware versions of the WRT1900AC, the v1 (version 1) and v2 (version 2). "v1" does not appear on the label, but is instead commonly used to differentiate between the original WRT1900AC and the version 2 model. Make sure to check the label on the bottom of the router and get the correct firmware.


There are two versions of the WRT1900ACS. As with the WRT1900AC, the term "v1" is only used to differentiate with the version 2 model and does not appear on the model sticker. Unlike the WRT1900AC, both versions of the ACS router use the same firmware.


As of the writing of this article on 7.2020, there is only one hardware version of the WRT3200ACM. The same is true for the WRT32X.

Storage (AKA Disk Drive) and File System

Another subject that OpenWRT is a bit opaque about is how information is stored on a router. It's not really their job, so let's go over it here.

A router is essentially a computer. It has all of the components of a computer, CPU, RAM, Network Adapter, Storage, etc. Unlike a computer, in a classic sense a router does not have a Disk Drive (unless one is attached via a USB or eSATA port), but it does have a way to store information which is Flash Memory. IE Flash Memory equals a Disk Drive (mechanical). In a more modern sense, it does have a disk drive in that modern disk drives in computers are SSD (Solid State Drives), which use a type of Flash Memory.

How OpenWRT handles that "Disk Drive" is much different than computers. Their explanation is here:

The part that OpenWRT doesn't explain very well is their "Overlay". Their Overlay is an abstraction layer that exposes a single interface to a user which is very similar to how a computer would present storage space to a user. On the other side is the Flash Memory which is broken down into two sections, firmware (equivalent to an Operating System) and storage space (equivalent to storage space on a disk drive or SSD for a computer). The firmware section is controlled by SquashFS and the storage space is controlled by JFFS/JFFS2

UBI = Unsorted Block Image, as in UBIFS (Unsorted Block Image File System)

Ethernet Switch

The Ethernet Switch typically transfers data at a sustained 90 MB/S for a Gigabyte Network Adapter.


REMEMBER: The AC Series of routers has dual boot partitions, so if you're installing firmware it will flash it to the non-active flash partition. The same occurs if upgrading existing OpenWRT firmware. So if one happens to be running OpenWRT on one partition and DD-WRT or the stock Linksys firmware on the other partition, if installing from the OpenWRT / LUCI GUI, it will overwrite the other partition.

Dual Booting

This allows for rebooting to the alternate partition;

  • opkg update
  • Advanced Boot: opkg install luci-app-advanced-reboot

Log out and log back in to see the new LuCI feature (System, Advanced Reboot) OR Refresh browser windows (in Firefox Shift+RefreshButton)

Switching Boot Partitions

Commands for OpenWRT

  • To determine which boot partition is active: /usr/sbin/fw_printenv -n boot_part
  • To change which boot partition is active: /usr/sbin/fw_setenv boot_part 1 OR /usr/sbin/fw_setenv boot_part 2

Commands for DD-WRT

  • To determine which boot partition is active:ubootenv get boot_part
  • To change which boot partition is active: ubootenv set boot_part 1

Power Switch

Per this site:

  • Reset the router by holding the reset button in until the PWR light starts to flash, appx. 15 seconds.
  • Once the power light stops flashing, you can power off the router with the power switch.
  • Turn the power back on and the PWR light will light. As soon as any other light turns on, power off the router with the power switch.
  • Turn the power back on and the PWR light will light. As soon as any other light turns on, power off the router with the power switch.
  • Turn the power back on and the PWR light will light. As soon as any other light turns on, power off the router with the power switch.
  • Turn the power back on and the PWR light will light. This time just let the router power all the way up. It should now be on the alternate

Per this site:

  • Start with the power switch off, then switch on. Watch the power LED:
  • Power LED: on (a few seconds)
  • Power LED: off (a second or two)
  • Power LED: on (immediately when the power light turns on, flip the power switch off)
  • That is 1 cycle of the 3 required to revert to the other partition. Repeat the above procedure two more times, making sure to flip the switch off as soon as the power LED comes on the second time.
  • The fourth time you turn the power switch on you can let the device boot and it should boot into the other partition.

After some experimentation, 4-5 seconds seems to be the sweet spot.

Here's what's happening "behind the scenes" when the the power switch is cycled in the above fashion. The observations were made with a TTL / Serial / USB cable attached to the header on a router board.

  • The Marvell firmware starts the boot process (equivalent to the BIOS of a PC)
  • There is a 2-3 second pause where one can press a key on the command console to instruct the router to boot into a very basic environment for loading firmware (sort of equivalent to a BIOS setup utility on a PC)
  • Before the 2-3 second window described above expires (and the boot process continues) is when the power button is turned off.

Below are a few of lines of information displayed during the boot process;

---below is the boot information after the "3nd power cycle"

BootROM - 1.73
Booting from NAND flash

General initialization - Version: 1.0.0
Detected Device ID 6820
High speed PHY - Version: 2.0

Init RD NAS topology Serdes Lane 3 is USB3
Serdes Lane 4 is SGMII
board SerDes lanes topology details:
 | Lane #  | Speed |  Type       |
 |   0    |  06   |  SATA0      |
 |   1    |  05   |  PCIe0      |
 |   2    |  06   |  SATA1      |
 |   3    |  05   |  USB3 HOST1 |
 |   4    |  05   |  PCIe1      |
 |   5    |  00   |  SGMII2     |
:** Link is Gen1, check the EP capability 
PCIe, Idx 0: Link upgraded to Gen2 based on client cpabilities 
:** Link is Gen1, check the EP capability 
PCIe, Idx 1: remains Gen1
High speed PHY - Ended Successfully
DDR3 Training Sequence - Ver TIP-1.26.0
mvSysEnvGetTopologyUpdateInfo: TWSI Read failed
DDR3 Training Sequence - Switching XBAR Window to FastPath Window 
DDR3 Training Sequence - Ended Successfully
Not detected suspend to RAM indication
BootROM: Image checksum verification PASSED
__   __                      _ _
|  \/  | __ _ _ ____   _____| | |
| |\/| |/ _` | '__\ \ / / _ \ | |
| |  | | (_| | |   \ V /  __/ | |
|_|  |_|\__,_|_|    \_/ \___|_|_|
         _   _     ____              _
        | | | |   | __ )  ___   ___ | |_ 
        | | | |___|  _ \ / _ \ / _ \| __| 
        | |_| |___| |_) | (_) | (_) | |_ 
         \___/    |____/ \___/ \___/ \__| 
 ** LOADER **

U-Boot 2013.01 (Mar 27 2015 - 16:50:46) Marvell version: 2014_T3.0p6

Boot version : v1.0.13

Board: RD-NAS-88F6820-DDR3
SoC:   MV88F6820 Rev A0
       running 2 CPUs
CPU:   ARM Cortex A9 MPCore (Rev 1) LE
       CPU 0
       CPU    @ 1600 [MHz]
       L2     @ 800 [MHz]
       TClock @ 200 [MHz]
       DDR    @ 800 [MHz]
       DDR 32 Bit Width, FastPath Memory Access, DLB Enabled, ECC Disabled
DRAM:  512 MiB

Map:   Code:                    0x1fea9000:0x1ff7632c
       BSS:                     0x1ffef6b4
       Stack:                   0x1f9a8f20
       Heap:                    0x1f9a9000:0x1fea9000
raise: Signal # 8 caught
U-ENV offset == 0x200000
raise: Signal # 8 caught
U-ENV offset == 0x200000
       U-Boot Environment:      0x00200000:0x00220000 (NAND)

NAND:  128 MiB
MMC:   mv_sdh: 0
DEVINFO offset == 0x900000
U-ENV offset == 0x200000
U-ENV offset == 0x200000
S-ENV offset == 0x240000

#### auto_recovery ####
[u_env] get auto_recovery == yes
[u_env] get auto_recovery == yes
[u_env] get boot_part == 1
[u_env] get boot_part_ready == 3
auto_recovery enabled:1, boot_part:1, boot_part_ready:3 

S-ENV offset == 0x240000
[boot_count_read] block:0x240000, size:128KB, records:64 
[boot_count_read_record] boot_count:2, next_record:53

[boot_count_write] erase:0, auto_recovery->block_offset:0x240000 offset=0x25A800

Updating boot_count ... 
[boot_count_write] offset:0x25A800 , length:2048

PCI-e 0 (IF 0 - bus 0) Root Complex Interface, Detected Link X1, GEN 2.0
PCI-e 1 (IF 1 - bus 1) Root Complex Interface, Detected Link X1, GEN 1.1
USB2.0 0: Host Mode
USB3.0 1: Host Mode
USB3.0 0: Host Mode
Board configuration detected:
mvEthE6171SwitchBasicInit init 
|  port  | Interface | PHY address  |
| egiga0 |   RGMII   |     0x01     |
| egiga1 |   SGMII   |     0x00     |
egiga0 [PRIME], egiga1
auto_recovery_check changes bootcmd: run nandboot 
Hit any key to stop autoboot:  2  <-- This is the countdown timer that starts at 3

--- and below is what it changes to after the "3rd power cycle / 4th power on" (minus all of the lines similar to above that come before it)

#### auto_recovery:2 ####
auto_recovery_check changes bootcmd: run altnandboot 
Hit any key to stop autoboot:  0

Upgrading the "Other Partition" from OpenWRT (be it another OpenWRT installation, Linksys firmware, DD-WRT, etc.)

As of 9.20.2020 much of the below is in question. It has been determined that when using the LuCI GUI and an upgrade firmware image (not Linksys Factory to OpenWRT) that the CURRENT partition (not the other partition) will be upgraded... Sometimes... ...but not always. The pattern seems to be very erratic. This is not good. Linksys Factory to OpenWRT seems to reliably flash the other partition. None of this is noted in the OpenWRT documentation.

Additionally, if flashing DD-WRT (there's a reason) to the other partition, per this site: and experimenting, it just does not seem possible to flash any recent version of DD-WRT to the other partition that works and doesn't create a "kernel panic" when booting. The solution?

  • From an OpenWRT partition, flash the other partition with OpenWRT
  • Get an old firmware version of DD-WRT (Linksys Factory to DD-WRT), version 37xxx or below, sometime in 2018, and flash that
  • The router won't reboot properly, but give it a minute or so to make sure the image is copied, then turn the router off, then on. It will then boot to DD-WRT
  • Note, if using Firefox or any other browser to access the DD-WRT GUI, it will probably keep redirecting to the LuCI GUI. Clear the browsing history or open a private tab in Firefox to solve that issue.
  • Get a more recent version of DD-WRT (upgrade version), flash that, good to go with OpenWRT on one partition and DD-WRT on the other.

OK, why DD-WRT? Well, as it turns out, DD-WRT has a bunch of development tools that OpenWRT does not. That means it is much, much easier to compile one's own sofware (packages, not firmware) on a router. This includes perl packages, etc. And, as tested, the binary / executables on DD-WRT are completely functional on OpenWRT as long as all the dependencies are in place. It is even possible to have a huge chunk of DD-WRT software in the /opt Directory available on OpenWRT. The easiest way to not run into conflicts is to only install software that is not available in OpenWRT in the /opt Directory. That way environment paths can be set up to search /opt first, then the normal OpenWRT binary / executables.

One thing to keep in mind about OpenWRT VS DD-WRT is how each refers to the CPU / SoC of the Marvell based hardware. OpenWRT refers to it as a Cortex A9. And it is. DD-WRT refers to it as ARMv7 and it is. Technically (see above section for details on the hardware). It's the same thing with both firmwares making a partial reference to the hardware's name. Arm, DD-WRT, and OpenWRT can all share the blame on this. See the chart on Wikipedia for some clarity:

Using LuCI to upgrade firmware, as of about 19.07.3, the upgrade process in the GUI has changed slightly and states: "Upload a sysupgrade-compatible image here to replace the running firmware." That might lead one to believe that the "running firmware", IE the currently booted and running version of OpenWRT will be upgraded. That is NOT the case. The LuCI GUI upgrade will upgrade the firmware on the other partition and then boot from the other partition. The OpenWRT message is probably related to the fact most routers do not have the special dual boot flash partitions that the AC Series has.

Using the command line to upgrade the firmware will upgrade the other partition, the subsequent boot will be to the current partition (IE, the one it was flashed from): sysupgrade -n -v -F /tmp/factory-to-ddwrt.bin (-n = do NOT keep current settings, -v = verbose, -F = Force)

So how does one upgrade OpenWRT firmware on the current / active boot partition when the process upgrades the other inactive partition? What about changing the boot partition to the inactive one and then upgrade the firmware (See the Switching Boot Partitions section of this article for the commands to view or change the boot partition)? After several attempts, this trick didn't work. Documentation exists that says this trick works with DD-WRT ( It seems the flashing of the NVRAM is left up to the Marvell SoS / CPU and there is no way around it via OpenWRT. Alternative?

The solution is to upgrade from the other partition. IE, if Partition 1 needs to be upgraded, boot to Partition 2 and perform an upgrade, which will then upgrade Partition 1. This will obviously work if OpenWRT is installed on both partitions. But how can one install DD-WRT on the other partition from OpenWRT?

Solution: Use the command line. IE, it won't work from the OpenWRT LUCI GUI.

  • Download the DD-WRT Factory Firmware (factory-to-ddwrt.bin) to the /tmp Directory
    • For WGET to work, this may be needed: opkg install libustream-mbedtls
  • Type the following command: sysupgrade -n -v -F /tmp/factory-to-ddwrt.bin (-n = do NOT keep current settings, -v = verbose, -F = Force)

The firmware will be installed on the other partition.

Remember: When attempting to utilize this within the LUCI GUI (if already logged in and connected), refresh the browser windows (CTRL Key plus Refresh Button in Firefox).

Only Upgrade versions of OpenWRT can be flashed via the GUI, not factory (unless the other partition is LinkSys firmware).

Use the OpenWRT Install / Factory image in this instance.

OpenWRT System Logging

In /etc/config/system, add the following lines;

  • option log_file '/var/log/messages'
  • option log_remote '0'

For additional information see: and

Storage: Internal NAND Flash Memory, USB Flash Drives, and eSATA Drives

Believe it or not, the stock installation of OpenWRT does not come with the capability to access USB or eSATA devices. Considering how prevalent a USB port is on routers these days, that's a bit baffling. Plus it's really frustrating for so many web sites that refer to the LuCI, System, Mount Point menu that doesn't exist unless the previously mentioned items are installed. Big woof on this one considering most newer routers have USB and / or eSATA ports.

Recommended Hardware Devices

The best recommendation for a USB Flash Drive is the SanDisk Ultra Fit USB 3.1 Flash Drive Series. And the recommendation is NOT because it is the fastest. They brag speeds up to 130 MB/S. Maybe downhill in a tornado, but under normal systems, that speed is a joke for this piece of hardware. So why recommend it? Well as it turns out, the fastest drive, USB, eSATA, or otherwise that has been tested on the AC Series is about 70 MB/S (this has been confirmed for eSATA) and around 45 MB/S for USB 3.0 (using a Patriot SuperSonic Rage Elite USB 3.1 Flash Drive that has been verified multiple times at over 200 MB/S sustained). Based on that and the below reviews it seems the Ethernet Switch may be topping out at about 70 MB/S, which is quite respectable.

Some reviews have the USB 3.0 speeds and eSATA speeds about the same at around 70 MB/S:

Others have the USB 3.0 speeds measured considerably slower at about 20 MB/S:

Anyway, the above mentioned SanDisk device tops out at about 70 MB/S on every system that the above mentioned Patriot device tops out at over 200 MB/S. Notice that 70 MB/S speed mentioned twice? Once for the SanDisk device and once for the AC Series. The next item to consider is price. The SanDisk is not the cheapest, but it is fairly low. When price and performance are both considered, it turns out the SanDisk device beats everyone. And since the AC series router and SanDisk USB Flash Drive both top out at around 70 MB/S, that makes it the perfect match.

If one is considering using the USB Flash Drive for other purposes, go with the Patriot USB Flash Drive. If using the USB flash drive as a dedicated device for an AC series routers then go with the SanDisk USB flash drive. Plus it's also much smaller and has a lower profile than the patriot device. Both drives claim speeds about double what they can deliver. The final joke is that the Patriot device is USB 3.0 and the SanDisk is a USB 3.1 device.

Another nice item, which isn't necessary, but makes nice neat way to connect several USB flash drives to a router is a Sabrent USB 3.0 Hub (model HB-RBM3). From Wal-Mart, only about $12. There are other similar device, but this one is much higher quality. Sadly, even with its ability to rotate, it won't plug into the router without blocking several of the Ethernet ports (including the WAN port) or the power connector. Thanks to the overhang on the rear of the AC Series router, it can't be rotated up.

Sabrent USB 3.0 Hub
Sabrent USB 3.0 Hub
USB 3.0 Extension
USB 3.0 Extension

But there is a solution... A USB 3.0 A Male to A Female Adapter (Part # 1206-N, UPC 848076012233) from a company named CMPLE. It is available from several places: Wal-Mart, eBAy, and from the company that appears to have it manufactured (in China), CMPLE. Even at about $3.00 it is a bit more expensive than other similar products (and there are only a few). But it has one advantage in that the orientation of the male and female part of the connector are arranged such that the above noted 3 Port USB 3.0 hub from Sabrent can connect and be in the "up" position. All other similar items found require that the hub be rotated to the left, right, or down. Down isn't a choice unless one's router is on the edge of a table. Left and right are good as the adapter provides enough clearance for the hub so it doesn't contact the power cord or the Ethernet cable on the WAN port.


Before getting into the "how" with an external storage device, it is worth pointing out one of the more useful features available in OpenWRT.

Whatever external storage device is chosen, be it an old USB 2.0 Flash Drive that's been sitting in a drawer to an 8 TB or more HDD in an eSATA enclosure, it can be used in the capacity of just a storage device. However, there is a nice feature that allows for additional software that acts in conjunction with the basic firmware of the router to be stored on an external storage device. To put it in terms of a computer, the router can be a computer that has two storage devices. One for the Operating System (Firmware in the case of a router) and the other for file storage. But what if the Operating System (AKA firmware) could also reside on an external storage device. With OpenWRT it can.

There are two choice to make in regards to relocating the OS of a router. The first choice, referred to as "Overlay", has part of the OS continuing to reside on the internal Flash Storage with the rest on an external storage device. The second choice, mounting the external storage device as the "root filesystem" can move almost all of the OS to the external storage device.

Details on the OpenWRT booting process, overlay, file systems, etc. can be read about at the below links. Don't do any of it yet, just read it for the technical background information;

Both choice offer almost unlimited expansion of the OS, limited only by the size of the storage device(s) connected, with neither offering a performance advantage over the other. The "Overlay" choice is the safer of the two if the external storage device malfunctions. If a malfunction does occur, the router will essentially revert to a "newly flashed" state. This allows for a new external flash drive to be connected and hopefully a backup restoration. The second choice is more dangerous in that any malfunction of the external storage device will result in the router being unresponsive to normal access methods.

Even with the huge (compared to other routers) amount of non-volatile Flash Storage space available on the AC Series of routers, sometimes it isn't enough. There's a total of 128 MB for the AC and ACS, and a whopping (relative to routers) 256 MB available on the WRT3200ACM. But... There's always a "but". Even with the ACM, typically only a single 80 MB partition is readily available. And of that, only about 70 MB is available as free space (half that for the AC and ACS series).

It is possible to access all of the internal Flash Storage space, as described below. But be careful when using it as it could make the router malfunction, be overwritten, etc. The available Flash Memory Storage could certainly have been utilized more efficiently. And don't blame OpenWRT for that. It is Linksys that designed the Flash Memory Storage design into the hardware.

Anyway, there is a nice solution to overcome the storage limitations of the router using a feature called "Overlay". In short, a USB Flash Drive or eSATA drive or mSATA drive (in a USB 3.0 enclosure) can be used instead.

REMEMBER: If using Overlay with a USB device, if the system is rebooted, when viewed in the LuCI GUI interface the "Enable Mount" will not be checked for the device that is mounted as an Overlay device, but it will be mounted. It can be checked and mounted for access at an additional /mnt point with no ill effects.

Software Needed for USB Flash Drives to Connect, Partition, Format, etc., with Other Configuration Tools and the LuCI GUI Interface

  • opkg update
  • opkg install block-mount e2fsprogs kmod-fs-ext4 kmod-usb-storage kmod-usb2 kmod-usb3 ntfs-3g usbutils gdisk cfdisk tune2fs kmod-fs-exfat dosfstools kmod-fs-vfat f2fs-tools kmod-fs-f2fs lsblk ntfs-3g-utils fdisk sfdisk wipefs blkidmkfs

Please note, all of the above packages are not necessary. But they do represent a broad range of tools that are very useful. And since they don't take up a lot of space, it's worth installing them. They don't run as active services or anything either, so no extra RAM or CPU usage unless one types the command. Reboot after installing all of the above software.

The above installed sofware provides many new commmands for "disk drives" (Flash Drive, SSD, HDD, etc.), including;

  • e2fsprogs: mkfs.ext2, mkfs.ext3, mkfs.ext4, etc.
  • kmod-fs-ext4: Includes ext2, ext3, and ext4
  • tune2fs: Changes a volume label
  • block-mount: Displays a volume label
  • df: Displays general partition information
  • cfdisk: A text GUI equivalent for gdisk or fdisk
  • lsblk: Shows the type of formatting
  • parted: A Linux utility that does not seem to be available with OpenWRT

Configuration with LuCI GUI Interface is located here: System, Mount Points

Partition Table, Partitioning, Formatting, and Performance Tuning a USB Flash Drive

A recommended method with the AC Series of routers is to create two EXT4 Partitions (one for each boot partition), an NTFS Partition (for compatibility with Windows), and a SWAP Partition. Also remember there is a difference between the MBR and GPT numbering of Partition types (IE, Linux Swap in MBR is 82 and 19 in GPT).

To switch from GPT to MBR without losing existing partitions, see this web site:

For a USB Flash Drive or eSATA drive on a router, MBR is absolutely fine. Several programs such as CGDISK (not CFDISK), GDISK, etc., insist on creating a GPT disk without giving the end user a choice. They demand it be done their way. If one is comfortable with being pushed around and forced to do something like that, fine. If not, choose a utility like CFDISK. Is a GPT partitioned drive better? Well, define better. It is newer, has more options, etc., but guess what? It's still a router with a Flash Drive or eSATA drive and MBR is fine. Is GDISK a better program? Well, it is way more powerful and has far more capabilities than CFDISK, so in that respect, yes. But in respect to giving the end user the final choice in what is done? Not so much.

Utilities to Display Information about Drives / Disks

  • df (Displays information about mounted file systems)
  • block info (Displays additional information about mounted file systems)
  • lsblk -l (Displays information about ALL available Drives / Disks)
    • The items shown as "mtdblockX" are different the different "partitions" for the routers internal Flash Drive (equivalent to a computer's disk drive, OpenWRT refers to it as NAND (Not AND) Flash Memory). These partitions are dictated by the hardware as Linksys designed and layed it out.
    • Anything starting with sd (sda, sdb, sdc, etc.) are the USB or eSATA devices connected to the router.
  • blkid (Similar to block info and lsblk)

Partition Table

For small USB 3.0 Flash Drives, use the MBR Partition Table. The following command will start things off with a clean slate. There are instances where a Flash Drive may have been previously configure to use a GPT Partition Table which can cause issues with GDISK and other partitioning Software;

  • wipefs -a /dev/sdX (If it isn't installed, use this command: opkg install wipefs

When starting CFDISK, if prompted to "Select label type", it means the Flash Drive or SSD has been initilized back to its most basic state. Choose DOS, which equates to MBR.


CFDISK is one of the easier utilities to use because of its "text GUI" style interface. I also aligns partitions on solid state devices correctly, as does most modern partitioning software. Don't forget to set the partition type too (7=NTFS, 83=Linux, 82=Linux Swap, etc.). The interface is fairly self explanatory, but in order to commit changes remember to select Write and confirm by typing "yes";

  • cfdisk /dev/sdX (Example cfdisk /dev/sda)

If the Partition Table does not exist, CFDISK will prompt for one to be selected. Choose DOS, which equates to MBR in "Linux Speak". One oddity after partitioning with CFDISK is that if the same device is viewed in GDISK, that program will complain that a partition table overlaps another one. This is not an issue with the partitioning at all. This is the GDISK program whining that it wasn't left space at the end of the SSD to create room to make the drive a GPT, and then trick other software and computers into thinking it is an MBR disk. That's deceptive and misleading. Use CFDISK, make an MBR based drive, good to go. Done.

To check proper partition alignment (if it starts on a boundary divisible by 1024, then it is properly aligned, newer partition software generally does this properly for flash based devices);

  • sfdisk -d /dev/sdX
  • fdisk -l -u /dev/sdX


Formatting an EXT4 Partition (remember to unmount before formatting if a drive is being used);

  • mkfs.ext4 -L WhatEverName -v /dev/sdaX (-L = Label, -v = Verbose)

Format an NTFS Partition;

  • mkntfs -f -L NTFS -v /dev/sdaX

Change a Volume Label;

  • tune2fs -L WhatEverName /dev/sdaX

Performance Tuning for ExtX

The below commands can be used to enhance performance for the ExtX File Systems, but are negligable according to this site:

  • tune2fs -o journal_data_writeback /dev/sdaX
  • tune2fs -O ^has_journal /dev/sdaX

Performance Tuning for NTFS

For NTFS volumes enabling "big_writes" makes a HUGE difference in performance. Some Linux systems claim this setting is deprecated, but for OpenWRT it works and makes a big performance difference. Real world file copy performance was measured at sustained 60 MB/S for a USB 3.0 Flash Drive and almost 90 MB/S for an eSATA HDD.

  • In the LUCI GUI, Mount Points, Mount Points, Edit, Advanced Settings, Mount Options add: big_writes
  • If compression is also desired, add this in the above noted location: big_writes,compression

Clone a Partition

It is recommended to make sure the destination partition is the same size or larger of course. Be prepared to wait a while, even on a USB 3.0 port.

  • dd if=/dev/sda1 of=/dev/sda2 status=progress

Note: After cloning, to save confusion and sanity, remove the source drive. It also may be necessary to reboot the router or dismount and mount the drive if it was already mounted to see the "cloned" directories and files. All of this is necessary because everything is cloned and OpenWRT may display two /dev/sdX devices that are exactly the same (IE sdb1 and sdb1 as two distinct, but duplicate device partitions).

Use an External Drive (USB Flash Drive, USB to mSATA) instead of internal Flash Memory using Overlay

In the LuCI GUI interface;

  • System, Mount Points, Mount Points, Add, General Settings (select the USB Flash Drive Partition)
    • Add by one of several methods, UUID displays device too (IE, /dev/sda1)*
    • Use as external overlay (/overlay)
  • ...Advanced Settings
    • File System: EXT4, NTFS, etc.
    • Mount Options
      • EXT4: barrier=0,data=writeback
      • NTFS: big_writes,compression

* Linux systems do not reliably discover sdX devices in the same order. So on an AC Router with multiple devices attached (IE, a USB 3.0 and eSata device OR mulitple USB 3.0 devices attached with a hub) there is no reliable method to predict which device will be sda, sdb, sdc, etc. IE a device on the USB 3.0 could be sda and a device on the eSATA port could be sdb on one boot. The next one might have them switched with the USB 3.0 device as sdb and the eSATA device as sda. With that in mind, use the UUID number when mounting a device to have it consistently attached to the same mount point (IE, /mnt/sda1, /mnt/sdb1, etc.) See the below sites for more information;

Access and Use an External USB Flash Drive

Install the drivers and LuCI interface as noted above, then in the LuCI GUI Interface;

  • System, Mount Points, Mount Points, Add, General Settings (select the USB Flash Drive Partition)
    • Add by one of several methods, UUID displays device too (IE, /dev/sda1)
    • Mount Point (type it manually): /mnt/WhatEverName (Match it to the device name, IE /dev/sda1 will be mounted as /mnt/sda1)
  • ...Advanced Settings
    • File System: EXT4, NTFS, etc.
    • Mount Options
      • EXT4: barrier=0,data=writeback
      • NTFS: big_writes,compression


  • If using a the USB 3.0 by itself (IE, nothing plugged into the eSATA / USB 2.0 port), the flash drive will be referred to as device SDA (with partitions SDA1, SDA2, etc.)
  • If the eSATA port / USB 2.0 port is used by itself, the same naming convention applies.
  • If both ports are used, but only the USB 3.0 device is mounted it will still be referred to as SDA (etc.)
  • BUT, and this is a tricky thing
    • If both ports are used, but only the USB 3.0 device is mounted, as soon as an eSATA / USB 2.0 port device is mounted it will be seen as SDB (etc.)
    • BUT, big BUT here, when the system is rebooted, the eSATA / USB 2.0 device can sometimes be mounted first, so SDA and SDB are reversed. WOOF!

Swap Partition or Swap File

A Swap Partition or Swap File can be used.

Most references to Swap Partitions or Files indicate performance is quite poor. There is considerable ancient / old /archived information about Swap Files and OpenWRT. But this may have been written during the USB 2.0 period and doesn't reflect the performance of USB3 or eSATA devices in 2020. That said, "Virtual RAM" is slow. Is it slower than RAM? Yes. Does one sometimes need more RAM than is physically available? Yes, sometimes. So for all the people that discourage the use of a Swap File, fine. But sometimes one needs it. Unlike other routers, the AC Series comes with an astounding amount of RAM (512 MB), so it may not be an issue. But here's how to do it...

Make sure there is an available empty partition for usage of a Swap File, then;

  • mkswap -L SWAP /dev/sdaX
  • Use the LuCI GUI interface


  • mkswap -L SWAP /dev/sdaX
  • swapon /dev/sdaX

It is recommended to use the GUI to be able to monitor it later. Check functionality with: HTOP

Inactive Internal Flash Memory Partitions and Linksys Reserved NVRAM / Flash Memory Partition Mounting and Information

Internal Flash Memory Partitions (mtd6 (rootfs1 UBI), mtd7 (rootfs2 UBI), and mtd9 (syscfg UBI), etc.) can also be mounted and accessed. For more information on the WRT3200ACM Flash Memory Layout, click here (other AC models are similar, but different sizes). Other mtdX Flash Memory sections can also probably be accessed, but are not addressed here.

One use for this would be to manually edit settings from the active partition to the inactive partition to fix some type of issue.

Viewing Available Internal Partitions and Information

NOTE: Most of the below information in this section is from the perspective of OpenWRT. DD-WRT has a slightly different "perspective" on the layout.

See,, and for Flash Memory Layouts of each AC Router Model. The Flash Memory (non-volatile RAM / NVRAM) Layout is directly comparable to Partitions on a Personal Computer's disk drive or SSD.

Various commands to "see" the available internal Flash Memory partitions;

  • ls -la /dev/ub* : A directory listing of UBI devices
  • cat /proc/mtd : A list of the various MTD (Memory Technology Device) Partitions
  • UBI (Unsorted Block Images) Commands;
    • ubinfo - provides information about UBI devices and volumes found in the system
    • ubiattach - attaches MTD devices (which describe raw flash) with UBI which creates corresponding UBI devices;
    • ubidetach - detaches MTD devices from UBI devices (the opposite to what ubiattach does);
    • ubimkvol - creates UBI volumes on UBI devices;
    • ubirmvol - removes UBI volumes from UBI devices;
    • ubiblock - manages block interfaces for UBI volumes. See here for more information;
    • ubiupdatevol - updates UBI volumes; this tool uses the UBI volume update feature which leaves the volume in "corrupted" state if the update was interrupted; additionally, this tool may be used to wipe out UBI volumes;
    • ubicrc32 - calculates CRC-32 checksum of a file with the same initial seed as UBI would use;
    • ubinize - generates UBI images;
    • ubiformat - formats empty flash, erases flash and preserves erase counters, flashes UBI images to MTD devices;
    • mtdinfo - reports information about MTD devices found in the system (not available in OpenWRT)

How the internal non-volatile flash memory (equivalent to a disk drive in the router) is arranged (Note: The WRT1900ACS and WRT3200ACM have slightly different numbering noted below as WRT1900ACS Name and Number / WRT3200ACM Name and Number;

  • mtd5 / mtd6*** (the first bootable flash memory partition)
    • Referred to as ubi with cat /proc/mtd if it is the active partition or rootfs1 if it is the inactive partition
    • Referred to as: rootfs1 in OpenWRT Documentation
    • Referred to mtdblock5 / mtdblock6*** in the LuCI GUI UUID drop down menu
    • Referred to as ubi0 in /sys/devices/virtual/ubi, which in turn includes ubi0_0 (kernel* image) and ubi0_1 (usable flash storage)
  • mtd7 / mtd8*** (the second bootable flash memory partition)
    • Referred to as ubi with cat /proc/mtd if it is the active partition or rootfs2 if it is the inactive partition
    • Referred to as: rootfs2 in OpenWRT Documentation
    • Referred to mtdblock7 /mtdblock8*** in the LuCI GUI UUID drop down menu
    • Referred to as ubi2 in /sys/devices/virtual/ubi, which in turn includes ubi2_0 (kernel* image) and ubi2_1 (usable flash storage)
  • mtd8 / mtd9*** (a flash memory partition used as a temporary storage location when new images are temporarily stored during the flash process)
    • Referred to as syscfg with cat /proc/mtd and the OpenWRT Documentation
    • Referred to mtdblock8 / mtdblock9*** in the LuCI GUI UUID drop down menu
    • Referred to as ubi2 in /sys/devices/virtual/ubi, which in turn includes ubi1_0 and ubi1_1 (typically ubi1_0 is detached by default, ubi1_1 has to be attached manually)

The WRT3200ACM has an extra partition, mtd4, labeled as sysdiag.

By default, the attached UBI partitions attached are;

  • ubi0: mtd4 / mtd5***
  • ubi0_1: Kernal Image portion of mtd4 / mtd5*** OR mtd6 /mtd7***, depending on which is active
  • ubi0_1: Root FS portion of mtd4 /mtd5*** OR mtd6 /mtd7***, depending on which is active
  • ubi1: mtd8 / mtd9*** is the partition used as a temporary storage location when new images are temporarily stored during the flash process
  • ubi1_0: same as UBI1, but use ubi1_0 when mounting
  • ubiX, ubiX_0, ubiX_1, etc. are additional UBI Partitions that are attached with the ubiattach command

It does not appear that the Kernal Image portion of mtd4 / mtd5*** OR mtd6 / mtd7*** can be mounted (IE, /dev/ubiX_0, for example /dev/ubi0_0, /dev/ubi1_0, etc., cannot be mounted), unless it is the mtd8 / mtd9*** partition used as temporary storage when flashing an image to the router.

*** Remember: mtdX / mtdY refers to the minor difference between the 1900 series and 3200 series of AC Routers. IE the 1900 series router's mtd4 is mtd5 on the 3200 series.

The full memory layout can be found here;

Remember, the flash memory layout of the AC Series was created by Linksys, not Marvell. And as noted by some, it seems a bit wasteful in how it was utilized.

The below information illustrates the difference in "perspective" between OpenWRT and DD-WRT in terms of how each of them "sees" the underlying partitions. The below information was obtained from a router with OpenWRT on partition 1 and DD-WRT on partition 2. The naming of the first four partitions is similar. The naming difference on mtd4 - mtd7 is a difference in naming conventions between the two firmwares. But notice the last "2 or 3" partitions... DD-WRT makes use of the "unused" mtd8 (from OpenWRT perspective) and divides it into two partitions (mtd8 and mtd9), nvram and dd-wrt.

There is no explanation for the size differences.

---OpenWRT (cat /proc/mtd)

dev:    size   erasesize  name
mtd0: 00200000 00020000 "u-boot"
mtd1: 00040000 00020000 "u_env"
mtd2: 00040000 00020000 "s_env"
mtd3: 00100000 00020000 "devinfo"
mtd4: 02800000 00020000 "kernel1"
mtd5: 02200000 00020000 "ubi"
mtd6: 02800000 00020000 "kernel2"
mtd7: 02200000 00020000 "rootfs2"
mtd8: 02600000 00020000 "syscfg"
mtd9: 00680000 00020000 "unused_area"

--DDWRT (cat /proc/mtd)

dev:    size   erasesize  name
mtd0: 00200000 00020000 "u-boot"
mtd1: 00040000 00020000 "u_env"
mtd2: 00040000 00020000 "s_env"
mtd3: 00100000 00020000 "devinfo"
mtd4: 02800000 00020000 "linux"
mtd5: 02500000 00020000 "rootfs"
mtd6: 02700000 00020000 "linux2"
mtd7: 02400000 00020000 "ubi"
mtd8: 00040000 00020000 "nvram"
mtd9: 02500000 00020000 "ddwrt"
mtd10: 00680000 00020000 "unused_area"

Mounting Internal Partitions

To view information about available UBI devices and partitions;

  • ls -la /dev/ub* : A directory listing of UBI devices
  • cat /proc/mtd : A list of the various MTD (Memory Technology Device) Partitions

See for additional information about UBI

The LuCI GUI cannot attach internal Flash Memory Partitions via the Mount Points MTDBLOCKx method, nor can the block mount /dev/ubiblockX command. Editing the /etc/config/fstab file is the only method that works (Note, not the /etc/fstab file) if the system is rebooted.

The below example of /etc/config/fstab file (which can be created manually or within the LuCI GUI) to mount the mt8 / rootfs2 partition does not work as OpenWRT will not mount it (The block mount command mounts the various items in the /etc/config/fstab file);

The below /etc/config/fstab Entry will NOT work;

config mount
        option device '/dev/ubi2_0'
        option target '/tmp/MTD8'
        option fstype 'squashfs'
        option enabled '1'

Instead, edit the /etc/rc.local file to to mount an the mtb8 / rootfs2 internal flash memory partition;

The following will mount the second flash memory partition (mtb8 / rootfs2) for a WRT3200ACM, adjust as noted above for the AC or ACS.  Also remember that if one of the mtd partitions is already attached an error will occur with the ubiattach command, so just go to the next command;

ubiattach -m 8
mkdir /mnt/mtd8
mount -t ubifs /dev/ubi2_1 /mnt/mtd8

The following will mount the mtb9 / syscfg partition (if it isn't already mounted)

ubiattach -m 9
mkdir /mnt/mtd9
mount -t ubifs /dev/ubi1_0 /mnt/mtd9

Another example for the WRT1900ACS model: What if the router is booting from the external USB flash drive and there is a need to switch back to booting from the internal flash drive (first partition)? Good luck trying that with the LuCI GUI (IE, it won't work). Solution? See below;

  • Attach and Mount the mtd5 / rootfs1 partition (see the "partition map" for the WRT1900ACS on the OpenWRT website)
ubiattach -m 8 (The odds are it is already attached.  If an error occurs, that indicates it is already attached)
mkdir /mnt/mtd5
mount -t ubifs /dev/ubi0_1 /mnt/mtd5 (ubi0_1 is the partition noted as "mtd5 rootfs1 (ubi)")

Just for information: ubi0 is the partition noted as kernel1 in the, ubi0_0 is the partition noted as "primary kernel image", neither of which can be mounted.

ubi0_0 and ubi0_1 will always be the current partition and ubi1_0 and ubi1_1 will be the inactive partition (assuming there are no USB flash drives attached)

Also keep in mind, as noted above, there is a minor difference between the partition layouts of the WRT1900AC/ACS and the WRT3200ACM routers.

  • Access the partition here: /mnt/mtd5/upper (the directory structure at this point is equivalent to how it would be seen when in use), then edit the /mnt/mtd5/upper/etc/config/fstab file and set the open enabled '1' to '0' for the option target "/overlay" partition.
  • Reboot and the router will boot from the internal flash drive, mtd5 partition.

Some Additional Commands to Attach Internal Partitions

  • To attach a UBI Partition: ubiattach -m 6 OR ubiattach -m 8 OR ubiattach -m 9 (an error will occur if a partition is already mounted)
  • To mount the second bootable partition;
    • mkdir /tmp/MTD8 (this follows the OpenWRT convention in terms of the location to mount it, instead of using the /mnt directory)
    • mount -t ubifs /dev/ubi2_1 /tmp/ubi2_1 (or MTDBLOCK8, etc)
  • An alternative method from here to mount the second bootable partition has a slightly different method which didn't seem to work quite right with the final command;
    • ubiattach -m 8
    • ubiblock --create /dev/ubi2_0
    • mount -t squashfs -o ro /dev/ubiblock2_0 mnt

To mount the syscfg partition (mtd9), if it isn't already mounted under /tmp/syscfg;

  • mkdir /tmp/MTD9 (this follows the OpenWRT convention in terms of the location to mount it, instead of using the /mnt directory)
  • mount -t ubifs /dev/ubi1_0 /tmp/MTD9

NOTE: The mounting of the mtb9 (syscfg UBI) for various models of the AC Series seems to be erratic, in that some automatically mount it and others don't. Even in ones where it is mounted, it isn't listed in the /etc/config/fstab file.

NOTE: The directory structure of the mtd8 / rootfs2 partition will not be the same as if it were the active partition. Look in the directory named "upper" for the /etc, /sbin, etc. directories.

WRT3200ACM UBI Layout

On a WRT3200ACM with both the mtd6 (rootfs1), mtd8 (rootfs2), and mtd9 (syscfg) partitions attached, ls -la /dev/ub* or cat /proc/mtd will show the following devices;

UBI Devices Attached


ubi0_0: The read only kernel / firmware image for mtd6 (under mtd5)

ubi0_1 (mtd6 / rootfs1): The squashfs / ubifs read / write partition

ubi1_0 (mtd9 / syscfg): The flash memory partition used as a temporary storage location for new firmware

ubi2_0: The read only kernel / firmware image for mtd8 (under mtd7)

ubi2_1 (mtd8 / rootfs1): The squashfs / ubifs read / write partition

See the OpenWRT documentation for the memory layout of the WRT3200ACM here.

Additional Information

/sys/devices/virtual/ubi/ubi0/mtd_num is a file that indicates the current / active partition, which is 6 (for mtd6) or 8 (for mtd8)

/sys/devices/virtual/ubi/ubi1/mtd_num is the file that indicates the mtd9 / syscfg partition, which is 9

Performance Thoughts

Performance Testing

In order to determine "end user speed", the below rates were measured using Windows Explorer between an M.2 SSD on a Windows 2016 Server and the below routers using Samba 4 (FD = Flash Drive and HDD = Hard Disk Drive). CPU, Flash Drive, HDD, Gigabit Switch connecting devices, etc. were all tested on other systems at faster speeds, so they are not the limiting factor. IE, the below tests reliably measure the bus speeds of the router(s);

Router Model -->
MB/S Read - Write
Port Connected to
WRT1900ACS WRT3200ACM with Flash Drive WRT3200ACM with eSATA in USB Enclosure
eSATA HDD NTFS 60 - 85
USB 3 FD ext2 50 - 70 - 14
USB 3 FD ext3 40ish - 40ish
USB 3 FD ext4 50 - 50 33 - 20 90 - 50
USB 3 FD NTFS 30 - 70 30 - 24 90 - 50
exFAT Forget It Didn't try
FSFS same as ext2
FAT32 4 GB size limit

It is worth noting the above Read - Write speeds are not reversed. Counter to what is normally experienced, Read speeds are regularly slower than Write.

In other testing using an FTP (vsFTPD) daemon on the router and WinSCP with an mSATA SSD connected to the USB 3.0 port and a Windows computer with a drive configured as RAID 0 with dual M.2 Samsung 970 EVO SSDs (IE, that is not the limiting factor) the speeds were higher than noted above. The computer and router were connected with a Dell PowerConnect Switch using link aggregation on the computer side with two ethernet connections (again, not a limiting factor on the computer end). Link aggregation does not seem to be a possibility on a router such as the AC Series, as with most routers, because even though there is a physical switch, there is only a single ethernet adapter connected to the switch from the SoC (on the LAN side, 2 if the WAN is counted). So data coming through the switch which moves to the USB 3.0 or eSATA port has to "pass through" a single ethernet adapter, because that's all that exists for the SoC (System on a Chip) hardware in the AC Series routers. Anyway, sustained read / write transfers to EXT4 formatted partitions were measured at almost 110 MB/S. NTFS formatted partitions were slightly slower, approaching 90 MB / S. This is probably a peak speed for the router as limiting factor observed during the file transfer was CPU usage. A 1.866 GHz WRT3200ACM was using above 80% of CPU resources for vsFTPD and other service, so a 1900 series router would be approaching 100% CPU usage. Transfers to a mechanical HDD on the eSATA port were only a couple of percentage points slower for both EXT4 and NTFS partitions when compared to the above mSATA connected to the USB 3.0 port.

Compatibility and Recommendations

For compatibility with Windows choose NTFS (and accept the speed hit on OpenWRT).

For OpenWRT Native Overlay use EXT4.

F2FS supposedly has issues, even though OpenWRT recommends it, so do NOT use it.

vFAT or any FAT is a joke and either doesn't work, performs like a dog, or has space limitations.

Cloning a USB Flash Drive

Cloning an OpenWRT USB Flash Drive with Acronis

Don't do it. Acronis will successfully clone a USB flash drive, but there is no guarantee it will put the partitions back in the same order

Cloning an OpenWRT USB Flash Drive with EaseUS (or another equivalent utility)

It works, but... It is dog slow, even for partitions and file systems that contained no data, files, or directories. The process took almost half an hour with two identical USB 3.0 Flash Drives. No detailed logs were available, but the odds are it went sector by sector. So that means a completely full USB Flash Drive would take just as long to copy as one that was partitioned and formatted, but contained no data.

Alternative Cloning Methods

OpenWRT doesn't have much in the way of backup or cloning software. There is no cloning software. The one piece of backup software, RESTIC, is a very functional piece of software, but it doesn't facilitate backing up from USB Flash Drive to another. The lack of OpenWRT software for cloning and backing up is probably because most hardware devices do not have multiple USB Ports. Additionally, most routers are probably not configured to boot from a USB Flash Drive using the Overlay functionality in OpenWRT, IE, they just boot from their internal non-volatile Flash Memory.

Clonezilla is a viable alternative, but requires booting a computer from a "Live CD" as it is not a Windows program.

Networking and Related Services

The OpenWRT article on Basic Networking, Aliases, etc. includes a lot of information. But they don't explain in a simple manner, what is occuring in some instances. Below are a few examples;

  • BR Term: The "br" part of br-lan name (seen in the LuCI GUI or when using the ifconfig command) is automatically assigned to a network interface if it's type is set to "bridge". OpenWRT refers to this as a pseudo interface. IE, if an interface defined in the /etc/config/network file is option type 'bridge' then "br" with a hyphen ( br- ) is prepended to the name of the interface ( interface 'lan' ) in the /etc/config/network file
  • Firewall Tip: Make sure each new "Interface" is include in the firewall setting (LuCI GUI: Interface, Firewall Settings, Assign Firewall Zone OR File: /etc/config/firewall, config zone (lan), option network, add the name of the interface)
  • Syntax Item: OpenWRT examples tend to vacillate between one of two different syntax in their examples, for instance;
    • option 'type' 'bridge' OR option type 'bridge' (the latter seems to reflect how the actual configuration files are done)
  • Alias or Second IP Address Tip: The option ifname item in the Alias or Secondary IP Address Network Configuration should be set to the above mentioned br-lan ( or if the default name has been changed from lan to lan1, then br-lan1 ). Do NOT set it to the option ifname 'eth0.1' (default name) or lan if the type is set to bridge as some examples give and don't emphasize the "in this example the interface is not configured as a bridge" note. The br-lan interface name doesn't exist in the /etc/config/network file, but it is if the IFCONFIG command is typed it does show the br-lan interface, and in LuCI it shows both (/etc/config/network name in large letters at the top and the IFCONFIG command name smaller on the bottom). How is one supposed to know? Well, as mentioned in the BR Term bullet point above, this information was discovered after a bit of experimenting. Thus the initial comment about the OpenWRT documentation leaving out a key detail to actually making things function.


  • Items in the above bullet points noted in italic represent configuration statements in a file.
  • Items below and above are referred to as Adapter(s) (NIC, Network Interface Card, etc.) and Interface(s) interchangabely, even though using the term Adapter is usually in reference to a piece of hardware and Interface usually refers to the Adapter as it is seen from an OS.

Default Network IDs, Labels, Configuration

WRT1900AS, WRT1900ASC, & WRT3200ACM IPv4
Port # (as labeled on back of router) Port # (from OpenWRT perspective) /etc/config/network Name ifconfig VLAN Assigned an IP Address
LAN 1 3 LAN br-lan (eth0.1 set to bridge mode) 1 Yes, and is assigned to br-lan
LAN 2 2 LAN br-lan (eth0.1 set to bridge mode) 1 Yes, and is assigned to br-lan
LAN 3 1 LAN br-lan (eth0.1 set to bridge mode) 1 Yes, and is assigned to br-lan
LAN 4 0 LAN br-lan (eth0.1 set to bridge mode) 1 Yes, and is assigned to br-lan
WAN 4 WAN eth1.2 2 Yes, depends on setting
N/A 5 / 5t (CPU for LAN) N/A eth0 1 No
N/A 6 / 6t (CPU for WAN) N/A eth1 2 No


  • The br-lan (a pseudo interface) is what OpenWRT adds to the LAN / eth0.1 interface if it is configured to option type 'bridge' in /etc/config/network
  • If the LAN / eth0.1 interface is not set to option type 'bridge', then the IP Address is assigned to eth0.1
  • The setting of eth0.1 to bridge or not bridge (OpenWRT documentation indicates the only option type is bridge) does not affect connectivity to the switch. It does affect connectivity to the wireless ethernet adapter(s) (see the next note)
  • Wireless Ethernet Adapters / Interfaces in OpenWRT are not assigned an IP Address. Instead they are "bridged" to eth0 and the switch via a "pseudo" bridge.
  • The eth0.1 and eth1.2 are named for the sake of the VLAN they belong to. In OpenWRT, the .1, .2, or whatever .Number following a standard ethernet interface name like eth0, eth1, eth2, etc. factor into how VLANs operate. A VLAN labeled as 1 will send traffic to ethX.1, a label of 8 would send it to ethX.8, etc.
  • The eth0.1 Interface when configured as a bridge becomes br-lan
  • lo is the loopback interface,

Conceptual View of OpenWRT and the AC Series of Routers "Network System"

The AC Series of routers has 2 "Wired" Ethernet Adapters (built into the SoC (System on a Chip)), 3 Wireless Ethernet Adapters (discrete components from the SoS), and 1 Switch (connected to the 5 Ethernet Ports on the rear of the unit). Both the eth0 and eth1 Ethernet Adapters are connected to the switch at a TCP/IP level. The VLAN capability of the switch is used to separate / isolate the WAN port from the LAN ports. Wireless Adapters are connected to LAN / br-lan and eth0 via a "pseudo" bridge and are not assigned a discrete IP Address, instead using the IP Address of the LAN / br-lan interface.

Multiple IP Addresses assigned to a Single (AKA Alias or Aliases in OpenWRT)

In the /etc/config/network File example below two IP Addresses are assigned to the LAN Bridge / eth0.1 Interface, where A.B.C.D and W.X.Y.Z are place holders for an IP Address

# When using IFCONFIG, this interface will be displayed as br-lan1 and eth0.1 will not
# have an IP Address

config interface 'lan1'
        option type 'bridge'
        option ifname 'eth0.1'
        option proto 'static'
        option netmask ''
        option ip6assign '60'
        option ipaddr 'A.B.C.D'

config interface 'lan2'
        option proto 'static'
        option ipaddr 'W.X.Y.Z'
        option netmask ''
        # The ifname needs to be set to the br-lan1 name, not eth0.1
        option ifname 'br-lan1'

...and don't forget;

  • Edit, Firewall Settings, Assign firewall zone, ...LAN
  • Save and Apply
  • service network reload.


For the AC Series, the ports as "seen" from OpenWRT*;

LAN Ports: Port 0, 1, 2, 3

WAN Port: Port 4

CPU Ethernet for LAN: Port 5 / 5t

CPU Ethernet for WAN: Port 6 / 6t

* NOTE: The above port numbers are how OpenWRT "sees" the ports. The physical labeling of the ports as numbered on the back of the router are reversed. IE, OpenWRT Port 3 is labeled as LAN 1 on the router label. This is possibly due to how Marvell numbers their switches and manufacturers like Linksys wishing to have the ports numbered left to right.

VLAN Related Commands

  • To show the bridge name: brctl show (use the OpenWRT GUI to configure)
  • To show the available switches: swconfig list (usually returns: switch0)
  • To show the current configuration: swconfig dev switch0 show
  • To show what can be configured: swconfig dev switch0 help (again, use the OpenWRT GUI to configure)
  • To show what is currently configured on router: ls -l /sys/class/net

More information from OpenWRT is available here.

Configuration File



Network, Switch

Configuring Individual Physical Ports with Unique IP Addresses on Separate VLANs

  • Configure an additional VLAN with LuCI GUI
  • Edit the /etc/config/network File as follows (VLAN number 9 was randomly chosen, and could be any number, but they need to match in all instances of the below example, IE, wherever there is a 9, use 5 or 4 in all the same places if using a different number);
Do NOT use any special characters in the "config interface 'WhatEverName'" field like a dot ( . ), dash ( - ), etc.

config device
	option type '8021q'
	option ifname 'eth0'
	option vid '9'
	option name 'LAN9'
config interface 'LAN9'
	option ifname 'eth0.9'
	option proto 'static'
	option ipaddr 'A.B.C.D'
	option netmask ''
  • In the LuCI GUI, Network Interfaces, WhatEverNewName, Edit, Firewall Settings Tab, add it to the LAN Zone
  • Save and Apply in the LuCI GUI
  • Type: service network restart (as the Save and Apply apparently doesn't do that step) OR Restart Button in the LuCI GUI

Forwarding between VLANs

Use the Network, Firewall LuCI GUI

Multiple WAN Ports with MWAN3

Be sure to read the Additional Notes section at the end of the MWAN3 Section


Install MWAN3: opkg install mwan3 luci-app-mwan3 (The luci-app-mwan3 is under Network, Load Balancing)

Optional: opkg install kmod-macvlan (A utility that allows a single port to function as two ports with two IP Addresses and different MAC Addresses. IE, the WAN port could be configured with two IP Addresses)


First, make sure there are two functional WAN Ports with distinct IP Addresses. This can be configured with the below /etc/config/network example.

In LuCI, Load Balancing, Interfaces Tab, WhatEverNameOfInterface, MWAN Interface Configuration sub-tab, set the following (as a minium);

  • Enabled: Checked
  • Initial State: Online
  • Tracking Host Name IP Address: -.-.-.- (This is an IP Address to Ping to test whether the interface is up / working)

Members sub-tab is not really important in the below example.

Policy sub-tab;

  • The granular details of this sub-tab have to be configured in the /etc/config/mwan3 file as LuCI doesn't allow detailed configuration, just selecting existing policies
  • Set up two that represent each WAN Port

Rules sub-tab can be used to explicitly configure a client machine behind the router use a specific interface;

  • Source Address: Whatever device should use this interface
  • Destination address: (if not configured it won't work properly)
  • Policy assigned: Whatever Policy that says use "interface X"
  • Sticky "suggests" that subsequent connections should use the same interface (in the below example it doesn't affect anything, but in some circumstances could affect secure connections to bank web sites as they are very picky about stuff, as it should be.)

In the below example (/etc/config/mwan3) there are two physical WAN Ports (the WAN Port and Port 4 has been removed from the LAN VLAN and assigned to its own WAN VLAN and the WAN Firewall Zone in the /etc/config/network after the mwan3 example). It is a very simple example that has two WAN Ports. No load balancing or failover is configured. The example would be useful in a case where all client computers utilized one WAN for internet access and web servers could use the other WAN, so either WANs usage would not affect the other.;

Code Block
config rule 'https'
	option sticky '1'
	option dest_port '443'
	option proto 'tcp'
	option use_policy 'balanced'

config rule 'Win8_Test'
	option src_ip ''
	option proto 'all'
	option dest_ip ''
	option use_policy 'WAN2_only'
	option sticky '0'

config rule 'default_rule_v4'
	option dest_ip ''
	option use_policy 'balanced'
	option family 'ipv4'

config globals 'globals'
	option local_source 'LAN1'
	option mmx_mask '0x3F00'
	option rtmon_interval '5'

config member 'WAN1_m1_w1'
	option interface 'WAN1'
	option metric '1'
	option weight '1'

config member 'WAN2_m2_w2'
	option interface 'WAN2'
	option weight '2'
	option metric '2'

config policy 'WAN1_only'
	list use_member 'WAN1_m1_w1'
	option last_resort 'unreachable'

config policy 'WAN2_only'
	list use_member 'WAN2_m2_w2'
	option last_resort 'unreachable'

config policy 'balanced'
	list use_member 'WAN1_m1_w1'
	list use_member 'WAN2_m2_w2'
	option last_resort 'unreachable'

config policy 'WAN1_WAN2'
	list use_member 'WAN1_m1_w1'
	list use_member 'WAN2_m2_w2'
	option last_resort 'unreachable'

config policy 'WAN2_WAN1'
	list use_member 'WAN1_m1_w1'
	list use_member 'WAN2_m2_w2'
	option last_resort 'unreachable'

config interface 'WAN1'
	option initial_state 'online'
	option family 'ipv4'
	option track_method 'ping'
	option reliability '1'
	option count '1'
	option size '56'
	option max_ttl '60'
	option check_quality '0'
	option timeout '2'
	option failure_interval '5'
	option down '3'
	option up '3'
	list track_ip ''
	option recovery_interval '60'
	option interval '60'
	option enabled '1'
	list flush_conntrack 'connected'

config interface 'WAN2'
	option initial_state 'online'
	option family 'ipv4'
	option track_method 'ping'
	option reliability '1'
	option count '1'
	option size '56'
	option max_ttl '60'
	option check_quality '0'
	option timeout '2'
	option failure_interval '5'
	option recovery_interval '5'
	option down '3'
	option up '3'
	list track_ip ''
	option interval '60'
	option enabled '1'

In the below /etc/config/network example, all of the other LAN, etc. configuration is not included. The -.-.-.- indicates one's own IP Address, subnet mask, etc. information be used. The below example uses Port 4 (as labeled on the back of the router, but is Port 0 from OpenWRT's "perspective") for the second WAN / WAN2 port. VLAN numbers can be anything, as long as when they are changed, they match in a similar manner to what is below and do not interfere with existing LAN VLANs. The metric for WAN1 is set lower so it is always favored for clients behind the router as long as it is functional.

Code Block
config device
	option type '8021q'
	option ifname 'eth1'
	option vid '11'
	option name 'WAN1'

config interface 'WAN1'
	option ifname 'eth1.11'
	option proto 'static'
	option ipaddr '-.-.-.-'
	option netmask '-.-.-.-'
	option gateway '-.-.-.-'
	list dns '-.-.-.-'
	list dns '-.-.-.-'
	option metric '10'

config device
	option type '8021q'
	option ifname 'eth1'
	option vid '12'
	option name 'WAN2'

config interface 'WAN2'
	option ifname 'eth1.12'
	option proto 'static'
	option ipaddr '-.-.-.-'
	option netmask '-.-.-.-'
	option gateway '-.-.-.-'
	list dns '-.-.-.-'
	list dns '-.-.-.-'
	option metric '20'

config switch
	option name 'switch0'
	option reset '1'
	option enable_vlan '1'

config switch_vlan
	option device 'switch0'
	option vlan '11'
	option ports '4 6t'
	option vid '11'

config switch_vlan
	option device 'switch0'
	option vlan '12'
	option ports '0 6t'
	option vid '12'
Additional Notes

Whenever the DNSMASQ service is started it overwrites the /tmp/resolve.conf file with it's own version of that same file. It will also delete any symbolic link at /tmp/resolv.conf which typically points to /tmp/ When the DNSMASQ service is stopped it "politely" recreates that symbolic link. An explanation is given here: Basically the site is saying that if the DNSMASQ service is started and you have your own "DNS Service", why do you need to use external DNS Servers (which makes sense).

A side effect of the above behavior is it overwrites MWAN3 settings that are stored in /tmp/ If one has custom external DNS servers enabled for multiple WAN ports they will no longer be used. This is not a flaw with OpenWRT, just a behavior to be aware of. If one needs to configure specific upstream DNS servers, any custom DNS servers configured with MWAN can be configured within DNSMASQ. Again, this is just something to be aware of.

The following is not an issue IF a custom /etc/dhcpd.conf file exists (IE, if the default OpenWRT method for configuring DHCPD is used via the /etc/config/dhcp file): There is a problem if one wishes to use DHCPD and NAMED / BIND instead of DNSMASQ as the DHCPD service is not as "polite" as the DNSMASQ service (NAMED / BIND does not cause any conflict). When the DHCPD service starts, as with DNSMASQ, the /tmp/resolv.conf file is replaced. The settings DHCPD configures in the file are the same as DNSMASQ. However, when the DHCPD service is stopped, as noted above, it is as "polite" as DNSMASQ because the symbolic link that directs /tmp/resolv.conf to /tmp/ is not recreated. This leaves the /tmp/resolv.conf file configured with the setting nameserver This can be an issue with BIND / NAMED if it is not configured to "answer" (listen and do recursive lookups) on 127.0.01 IP Address. So make sure the BIND / NAMED configuration file includes IP Address in both the allow-recursion and listen-on-port sections.

Oddly, when doing a Google, Bing, etc search for these three terms: "resolvfile" "openwrt" "isc_dhcpd" NOTHING exists on the internet. Until now that is.

Additional Information


When installing, be sure to disable or uninstall DNSMASQ. Make sure DHCPD is installed if removing DNSMASQ (see DHCPD section below)

  • service stop dnsmasq
  • opkg remove dnsmasq


  • Use the LuCI GUI, under System, Software, Installed Tab to uninstall


  • set the DNSMASQ port to Port 0 in /etc/config/dhcp dnsmasq section to disable DNS


opkg update

opkg install bind-server bind-tools (bind-tools includes: bind-rndc bind-check, plus dependencies)

Configure via text files in /etc/bind/... (see example file below)

Enable and start the service (all of this is done automatically when the above packages are installed;

  • service named enable (the OpenWRT documentation contains information that applies to older versions and states: enable /etc/init.d/named)
  • service named start

Check to see if the service is running: pidof named


If using Slave Zones, make sure permissions are set correctly for the Directory;

  • chown bind /etc/bind/slaves
  • chgrp bind /etc/bind/slaves

This is the command line OpenWRT uses (CHROOT is not employed): /usr/sbin/named -u bind -f -c /etc/bind/named.conf (-u = User, -f = Run in the Foreground not as a Daemon, -c = Configuration File)

  • To disable IPv6, add the following to the command line: -4

Logging: see section on OpenWRT System Logging

For additional information: (Note: The OpenWRT documentation makes references to /etc/named.conf, but the files are in /etc/bind/...)

For command line information:

For logging information: and

Example Configuration;

Code Block
options {

	directory "/tmp";
		// If your ISP provided one or more IP addresses for stable 
		// nameservers, you probably want to use them as forwarders.  
		// Uncomment the following block, and insert the addresses replacing 
		// the all-0's placeholder.
		// forwarders {
		// };
	auth-nxdomain no;    # conform to RFC1035
	allow-recursion {
	allow-transfer {
	listen-on port 53 {
	querylog yes;


// Use with the following rndc.conf in named.conf, adjusting the allow list as needed:
// Generate with this command: rndc-confgen
key "rndc-key" {
      algorithm hmac-sha256;
      secret "zrb7APg1fyNhfwr/c1Fy8slvbd7BkIAzw9U8gUoJE90=";

controls {
      inet port 953
               allow {; } keys { "rndc-key"; };

// These Items are in the Default OpenWRT named.conf File
// be authoritative for the localhost forward and reverse zones, and for broadcast zones as per RFC 1912

zone "." {
	type hint;
	file "/etc/bind/db.root";

zone "localhost" {
	type master;
	file "/etc/bind/db.local";

zone "" {
	type master;
	file "/etc/bind/db.127";

zone "" {
	type master;
	file "/etc/bind/db.0";

zone "" {
	type master;
	file "/etc/bind/db.255";


zone "" {
	type slave;
	masters {
	file "/etc/bind/slaves/A.B.C.D.rev";
	allow-query {

zone "WhatEverZone" {
	type slave;
	masters {
	file "/etc/bind/slaves/WhatEverZone.hosts";
	allow-query {

zone "WhatEverZone" {
	type slave;
	masters port 53 {
	file "/etc/bind/slaves/WhatEverZone.hosts";

logging {
     channel default_log {
          file "/var/log/named/default" versions 3 size 20m;
          print-time yes;
          print-category yes;
          print-severity yes;
          severity info;

     channel zone_transfers_log {
          file "/tmp/log/named/zone_transfers" versions 3 size 20m;
          print-time yes;
          print-category yes;
          print-severity yes;
          severity dynamic;
     category notify { zone_transfers_log; };       
     category xfer-in { zone_transfers_log; };       
     category xfer-out { zone_transfers_log; };


Additional Information

Make sure the BIND / NAMED configuration file includes IP Address in both the allow-recursion and listen-on-port sections. This can cause issues with DHCPD if it is not configured correctly. See the MWAN3 and DHCPD sections for additional information.

DHCPD (AKA isc-dhcp-server-ipv4, etc.)

There are two versions of DHCPD, ISC and KEA. ISC is the older server and KEA is the newer. For simple or small networks, ISC will work fine and eliminates some configuration considerations. Read here for more information:

Another item to be aware of is the somewhat convoluted way the DHCPD service is configured within the OpenWRT "UCI Infrastructure" (Google OpenWRT and UCI for additional information). It isn't as straight forward as DHCPD is in CentOS, or other Linux distributions. But there is a reason for this, so please keep reading.

Prerequisites & Things to Keep in Mind

Remember the /etc/resolv.conf file is a symbolic link to /tmp/resolv.conf. That means changes to the file will not be preserved when the router is rebooted. To make permanent changes for the /etc/resolv.conf file, make equivalent setting changes in the /etc/config/dhcpd file. See the end of this section for an exception.

DNSMASQ normally provides DHCP service (and DNS), so disable DHCP functionality for DNSMASQ, disable DNSMASQ, or uninstall DNSMASQ. If uninstalling DNSMASQ be sure to install the BIND / NAMED service to replace the DNS functionality DNSMASQ provides. If the DNSMASQ service is removed, the LuCI GUI interface for it remains as that part of the GUI seems to be built into the core LuCI services instead of being an add-on module.

The nice people at OpenWRT realized that since DNSMASQ provides default DHCP services, it might be nice if settings from the DNSMASQ service were used with DHCPD. They seemed to get part way there with that concept, but not all the way. The DHCPD service in OpenWRT does indeed extract information from the /etc/config/dhcp file (this is the OpenWRT DNSMAQ configuration file). However, the only information it extracts from the /etc/config/dhcp file are the settings that are added via the /etc/uci-defaults/dhcpd.defaults file when the DHCPD service is installed. An example is the option domain 'lan' setting in the "config dnsmasq" section of the /etc/config/dhcp file. That setting is used to configure the "domain" setting in the /etc/resolv.conf file (this is just a symbolic link to /tmp/resolv.conf). However, because that setting is not copied (nor set) to the " config isc_dhcpd 'isc_dhcpd' " section of the /etc/config/dhcp file during the installation of DHCPD, that setting dissapears from the /etc/resolv.conf file after DHCPD is installed. It can of course be added manually in the isc_dhcpd section of the dhcp file. In fact, the entire dnsmasq section is ignored as far a DHCP is concerned. Worse than that, several settings that are used for DNSMASQ such as server do not work in the isc_dhcpd section of the dhcp file. It would be useful if it did as the /etc/init.d/dhcpd startup script echos its own settings into the /etc/resolv.conf file. A nice feature OpenWRT might add to the DHCPD package would be to configure settings like server in the /etc/config/dhcp file to work instead of hard coding a change in the DHCPD startup script. The resolvfile setting doesn't work either. But it doesn't work for DNSMASQ either.

As noted at the beginning of this section, changes made in the /etc/resolv.conf file will not persist across reboots of a router. Some settings can be set in the /etc/config/dhcp file to overcome this. However, since the section for DHCPD in the /etc/config/dhcp does not respect some settings such as server or resolvfile the only way to change settings like that are in the /etc/init.d/ startup scripts.


Watch out for the package titled "dhcpcd", as the "d" at the end might lead one to believe the "d" stands for "daemon" (AKA service). It does not. It is client software, hence the "c" in the name of the package. See this for more information:

  • opkg update
  • opkg install isc-dhcp-server-ipv4

Configuration & Management

Default Configuration File used during DHCPD package installation (and is then erased once those settings are applied to the /etc/config/dhcp file): /uci-defaults/dhcp.defaults

Default Configuration File (remember, this is a temporary file, so settings will not persist across router reboots): /tmp/run/dhcpd.conf

The Default Configuration File can be over-ridden by placing the DHCPD configuration file here: /etc/dhcpd.conf

Default Leases File: /tmp/dhcpd.leases

DHCPD Executable / Binary File: /usr/sbin/dhcpd

Command for checking DHCPD configuration files: dhcpd -cf WhatEverConfigurationPathAndFile -lf /WhatEverPathToDHCPdLeasesFile

If one wants to stay within the OpenWRT methodology of configuring the DHCPD service, it must be done by putting settings in the config isc_dhcpd 'isc_dhcpd' section of the /etc/config/dhcp File. Why? One, as noted above settings made here will not persist across reboots. Plus the /tmp/run/dhcpd.conf file is overwritten every time the DHCPD Service is restarted with settings from the /etc/config/dhcp File. And two, the dhcpd.conf file is stored in the /tmp Directory so settings put in that file will be lost if the router is restarted. This makes it impossible to use a GUI like Webmin to manage DHCP settings. But...

Since there is no LuCI GUI interface for DHCPD, the options available for the DHCPD service in the /etc/config/dhcp file are not documented (Note, the "DHCP Settings at the following website apply to DNSMASQ, not DHCPD: , and the settings that do exist seem to be "wonky", there is very little reason to remain locked inside of the OpenWRT DHCPD configuration paradigm. That requires changing settings in the /etc/init.d/dhcpd startup script.

And it opens a whole new world in the ease of configuring and managing DHCPD with Webmin, persistent settings in a dhcpd.conf style file that is similar to other Linux distributions, etc. The following steps make this possible (plus it is fairly easy thanks to the way the /etc/init.d/dhcpd startup script is written);

  • Create an /etc/dhcpd.conf file (the /etc/init.d/dhcpd script has provisions to search for this file)
  • There is NO need to modify the /etc/init.d/dhcpd startup script file as one might think, because as noted above, the startup script has provisions for this situation;
    • Orginal line: config_file=/tmp/run/dhcpd.conf
    • New line: config_file=/etc/dhcpd.conf

But also keep in mind the settings changes in the /etc/init.d/dhcpd startup script only affect the DHCPD service. The /etc/resolv.conf File still derives its settings from the /etc/config/dhcp File when the DHCPD service is restarted or the router is rebooted (same for DNSMASQ). IE, the /etc/config/dhcp File should not be completely dismissed as useless.

Special Note

Whenever the DNSMASQ service is started it overwrites the /tmp/resolve.conf file with it's own version of that same file. It will also delete any symbolic link at /tmp/resolv.conf which typically points to /tmp/ When the DNSMASQ service is stopped it "politely" recreates that symbolic link. An explanation is given here:

Not so for DHCPD (see the above end of the MWAN section above for more information on this subject)

Another irritating issue is that no method to manually configure a nameserver setting within the /etc/resolv.conf (this file is a symbolic link to /tmp/resolv.conf) if using the /etc/config/dhcp method of configuring DHCPD (HINT: Use the above described method of having a custom /etc/dhcpd.conf file). The /etc/resolv.conf file is overwritten each time the DHCPD (or DNSMASQ) service is restarted. The /etc/init.d/dhcp startup script sets the nameserver variable in /etc/resolv.conf with this line: echo "nameserver" >> /tmp/resolv.conf. Even if the echo command in the startup script is disabled, setting option server 'W.X.Y.Z' in the isc_dhcpd 'isc_dhcpd' section does not work. The only way to set nameserver in the /etc/resolv.conf file is to manually edit the /etc/init.d/dhcp startup script line that echos the setting into resolv.conf. Again, all of this paragraph assumes a custom /etc/dhcpd.conf file is NOT being used (again, HINT: Use a custom /etc/dhcpd.conf file, can't write it enough).

Additional Notes

There are a couple of items lacking in the OpenWRT DHCPD /etc/init.d/dhcpd startup script file;

  • The PID file that is created in /var/run/ file is created when the service initially starts and never goes away, even if the service is stopped.
  • If a custom /etc/dhcpd.conf file is NOT being used and the standard OpenWRT method of using /etc/config/dhcp method is used (again, HINT: Use a custom /etc/dhcpd.conf file), the DHCPD startup script erases the symbolic link that connects /tmp/resolv.conf --> /tmp/ in favor of its own custom /tmp/resolv.conf file (/etc/resolv.conf). This can break DNS settings for networking in general and MWAN3.

Solution? Add the following lines to the /etc/init.d/dhcpd startup script;

	ln -sf "/tmp/" /tmp/resolv.conf
	rm /var/run/

The ln command corrects the symbolic link issue mentioned above. And the rm command corrects the PID file issue that never goes away, again mentioned above. Also note that if the DHCPD package is ever updated, the script will need to be modified again. A startup script could be written, but haven't had time to write that yet. This post gives a fairly goot hint on how to write it: Although regular expressions wouldn't be necessary, just a check to see if "stop_service" exists anywhere in the dhcpd startup script and if it doesn't, insert it at the end.

PPTP (Point to Point Tunneling Protocol) for Clients

OpenWRT defines the use of PPTP Clients on the LAN side of a router that wish to connect to a PPTP server via the internet as NAT traversal for PPTP. Default installations of OpenWRT do not have the capability to facilitate PPTP connections by clients. The following software package must be installed;

  • opkg update
  • opkg install kmod-nf-nathelper-extra

The instructions on enabling the capability is a bit lacking on the OpenWRT site, so below is an improved explanation. After installing the above package, do the following;

  • Create a file named 20-nf-conntrack-helper.conf in /etc/sysctl.d: nano /etc/sysctl.d/20n-nf-conntrack-helper.conf
  • Add a single line of code in the 20-nf-conntrack-helper.conf file to enable the program: net.netfilter.nf_conntrack_helper = 1
  • Save the file: CTRL + O, then exit nano: CTRL + X
  • Restart the sysctl service: service sysctl restart

PPTP should now work for clients wishing to use PPTP connections.

As has been mentioned and will continue to be mentioned, it is understandable that the OpenWRT documentation may be lacking in some ways. Creating and writing good documentation is difficult and time consuming. The nice people responsible for OpenWRT spend most of their time making things work, improving functionality, adding new firmware for new routers, etc.. This leaves little time for good documentation. So for all the nice people that work so hard on OpenWRT, thank you. And no offense meant. The rather cryptic several lines written by the author of the below noted article for more information very likely uses that "shortcut" to create files or may have thought it was helpful to present it in that way. And it may work for some people. But it was decided to present it here slightly differently as done above.

More information on enabling the feature can be found here:

LAMP (sort of) - Web Server (Apache, LighttpD, Nginx, and / or uHTTPd) MariaDB (MySQL), and PHP

OpenWRT has four different web server platforms available. Apache, LighttpD, and Nginx are all full featured, whereas uHTTPd is more limited in its functionality. uHTTPd also serves as the web server for the LuCI GUI interface for OpenWRT. Apache does not have CGI or FastCGI built into the binary executable, but both Lighttpd and Nginx have CGI and FastCGI capability built in, making addon modules unecessary.


The Apache package in OpenWRT appears to only have CGI capability as the FastCGI module is not available. However, there are additional proxy modules included with Apache in OpenWRT that allow for PHP-FPM functionality with FastCGI.

Installation for Apache

opkg update

opkg install apache apache-utils apache-mod-ssl

Configuration for Apache

There is no LuCI GUI interface, so use text configuration files and / or Webmin (see below section on Webmin)

  • Initilization Script: /etc/init.d/apache2
  • Configuration File: /etc/apache2/apache2.conf
  • Default Server Root: /usr
  • Default Document Root: /usr/share/apache2/htdocs
  • Executables / Binaries: /usr/lib/apache2
  • User / Group (/etc/group): apache / apache

Below is working configuration file for Apache with CGI capability;

Code Block
ServerRoot "/usr"


TimeOut 3600

#LoadModule mpm_event_module lib/apache2/
LoadModule mpm_prefork_module lib/apache2/
#LoadModule mpm_worker_module lib/apache2/
LoadModule authn_file_module lib/apache2/
#LoadModule authn_dbm_module lib/apache2/
#LoadModule authn_anon_module lib/apache2/
LoadModule authn_dbd_module lib/apache2/
#LoadModule authn_socache_module lib/apache2/
LoadModule authn_core_module lib/apache2/
LoadModule authz_host_module lib/apache2/
LoadModule authz_groupfile_module lib/apache2/
LoadModule authz_user_module lib/apache2/
#LoadModule authz_dbm_module lib/apache2/
#LoadModule authz_owner_module lib/apache2/
#LoadModule authz_dbd_module lib/apache2/
LoadModule authz_core_module lib/apache2/
#LoadModule authnz_ldap_module lib/apache2/
LoadModule access_compat_module lib/apache2/
LoadModule auth_basic_module lib/apache2/
#LoadModule auth_form_module lib/apache2/
#LoadModule auth_digest_module lib/apache2/
#LoadModule allowmethods_module lib/apache2/
#LoadModule file_cache_module lib/apache2/
#LoadModule cache_module lib/apache2/
#LoadModule cache_disk_module lib/apache2/
#LoadModule cache_socache_module lib/apache2/
#LoadModule socache_shmcb_module lib/apache2/
#LoadModule socache_dbm_module lib/apache2/
#LoadModule socache_memcache_module lib/apache2/
#LoadModule socache_redis_module lib/apache2/
#LoadModule watchdog_module lib/apache2/
#LoadModule macro_module lib/apache2/
#LoadModule dbd_module lib/apache2/
#LoadModule dumpio_module lib/apache2/
#LoadModule echo_module lib/apache2/
#LoadModule buffer_module lib/apache2/
#LoadModule data_module lib/apache2/
#LoadModule ratelimit_module lib/apache2/
LoadModule reqtimeout_module lib/apache2/
#LoadModule ext_filter_module lib/apache2/
#LoadModule request_module lib/apache2/
#LoadModule include_module lib/apache2/
LoadModule filter_module lib/apache2/
#LoadModule reflector_module lib/apache2/
#LoadModule substitute_module lib/apache2/
#LoadModule sed_module lib/apache2/
#LoadModule charset_lite_module lib/apache2/
#LoadModule deflate_module lib/apache2/
LoadModule xml2enc_module lib/apache2/
LoadModule proxy_html_module lib/apache2/
LoadModule mime_module lib/apache2/
#LoadModule ldap_module lib/apache2/
LoadModule log_config_module lib/apache2/
#LoadModule log_debug_module lib/apache2/
#LoadModule log_forensic_module lib/apache2/
#LoadModule logio_module lib/apache2/
#LoadModule lua_module lib/apache2/
LoadModule env_module lib/apache2/
LoadModule mime_magic_module lib/apache2/
#LoadModule expires_module lib/apache2/
LoadModule headers_module lib/apache2/
#LoadModule usertrack_module lib/apache2/
#LoadModule unique_id_module lib/apache2/
LoadModule setenvif_module lib/apache2/
LoadModule version_module lib/apache2/
#LoadModule remoteip_module lib/apache2/
#LoadModule proxy_module lib/apache2/
#LoadModule proxy_connect_module lib/apache2/
#LoadModule proxy_ftp_module lib/apache2/
#LoadModule proxy_http_module lib/apache2/
#LoadModule proxy_fcgi_module lib/apache2/
#LoadModule proxy_scgi_module lib/apache2/
#LoadModule proxy_uwsgi_module lib/apache2/
#LoadModule proxy_fdpass_module lib/apache2/
#LoadModule proxy_wstunnel_module lib/apache2/
#LoadModule proxy_ajp_module lib/apache2/
#LoadModule proxy_balancer_module lib/apache2/
#LoadModule proxy_express_module lib/apache2/
#LoadModule proxy_hcheck_module lib/apache2/
#LoadModule session_module lib/apache2/
#LoadModule session_cookie_module lib/apache2/
#LoadModule session_crypto_module lib/apache2/
#LoadModule session_dbd_module lib/apache2/
#LoadModule slotmem_shm_module lib/apache2/
#LoadModule slotmem_plain_module lib/apache2/
#LoadModule ssl_module lib/apache2/
#LoadModule dialup_module lib/apache2/
#LoadModule http2_module lib/apache2/
#LoadModule md_module lib/apache2/
#LoadModule lbmethod_byrequests_module lib/apache2/
#LoadModule lbmethod_bytraffic_module lib/apache2/
#LoadModule lbmethod_bybusyness_module lib/apache2/
#LoadModule lbmethod_heartbeat_module lib/apache2/
LoadModule unixd_module lib/apache2/
#LoadModule heartbeat_module lib/apache2/
#LoadModule heartmonitor_module lib/apache2/
#LoadModule dav_module lib/apache2/
LoadModule status_module lib/apache2/
LoadModule autoindex_module lib/apache2/
#LoadModule asis_module lib/apache2/
#LoadModule info_module lib/apache2/
#LoadModule suexec_module lib/apache2/
<IfModule !mpm_prefork_module>
#LoadModule cgid_module lib/apache2/
<IfModule mpm_prefork_module>
LoadModule cgi_module lib/apache2/
#LoadModule dav_fs_module lib/apache2/
#LoadModule dav_lock_module lib/apache2/
LoadModule vhost_alias_module lib/apache2/
#LoadModule negotiation_module lib/apache2/
LoadModule dir_module lib/apache2/
LoadModule actions_module lib/apache2/
#LoadModule speling_module lib/apache2/
#LoadModule userdir_module lib/apache2/
LoadModule alias_module lib/apache2/
LoadModule rewrite_module lib/apache2/

<IfModule unixd_module>

User apache
Group apache


ServerName wrt3200acm.fullspectrum.lan:80

DocumentRoot "/usr/share/apache2/htdocs"
<Directory "/usr/share/apache2/htdocs">
	DirectoryIndex index.php index.html index.htm

    Options Indexes FollowSymLinks

    AllowOverride None

    Require all granted

<IfModule dir_module>
    DirectoryIndex index.html

<Files ".ht*">
    Require all denied

ErrorLog "/var/log/apache2/error_log"

LogLevel warn

<IfModule log_config_module>
    LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
    LogFormat "%h %l %u %t \"%r\" %>s %b" common

    <IfModule logio_module>
      LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio

    CustomLog "/var/log/apache2/access_log" common


<IfModule alias_module>

    ScriptAlias /cgi-bin/ "/usr/share/apache2/cgi-bin/"


<IfModule cgid_module>
Scriptsock /var/run/cgid.sock

<Directory "/cgi-bin">
    AllowOverride None
    Options None
    Require all granted

<IfModule headers_module>

    RequestHeader unset Proxy early

<IfModule mime_module>
    TypesConfig /etc/apache2/mime.types

    AddType application/x-compress .Z
    AddType application/x-gzip .gz .tgz


MIMEMagicFile /etc/apache2/magic

# Supplemental configuration
# The configuration files in the /etc/apache2/extra/ directory can be 
# included to add extra features or to modify the default configuration of 
# the server, or you may simply copy their contents here and change as 
# necessary.

# Server-pool management (MPM specific)
#Include /etc/apache2/extra/httpd-mpm.conf

# Multi-language error messages
#Include /etc/apache2/extra/httpd-multilang-errordoc.conf

# Fancy directory listings
#Include /etc/apache2/extra/httpd-autoindex.conf

# Language settings
#Include /etc/apache2/extra/httpd-languages.conf

# User home directories
#Include /etc/apache2/extra/httpd-userdir.conf

# Real-time info on requests and configuration
#Include /etc/apache2/extra/httpd-info.conf

# Virtual hosts
#Include /etc/apache2/extra/httpd-vhosts.conf

# Local access to the Apache HTTP Server Manual
#Include /etc/apache2/extra/httpd-manual.conf

# Distributed authoring and versioning (WebDAV)
#Include /etc/apache2/extra/httpd-dav.conf

# Various default settings
#Include /etc/apache2/extra/httpd-default.conf

# Configure mod_proxy_html to understand HTML4/XHTML1
<IfModule proxy_html_module>
Include /etc/apache2/extra/proxy-html.conf

# Secure (SSL/TLS) connections
#Include /etc/apache2/extra/httpd-ssl.conf
# Note: The following must must be present to support
#       starting without SSL on platforms with no /dev/random equivalent
#       but a statically compiled-in mod_ssl.
<IfModule ssl_module>
SSLRandomSeed startup builtin
SSLRandomSeed connect builtin

<Files ".user.ini">
    <IfModule mod_authz_core_module>
        Require all denied
    <IfModule !mod_authz_core_module>
        Order allow,deny
        Deny from all
        Satisfy All

<IfModule alias_module>
	ScriptAlias /php /usr/bin

# Either the AddType or AddHandler Directive can be used
# AddType application/x-httpd-php .php
AddHandler application/x-httpd-php .php
Action application/x-httpd-php /php/php-cgi

<Directory "/usr/bin">

	AllowOverride None
	Options none
	Order allow,deny
	Allow from all


<Directory "/usr/share/apache2/htdocs/phpMyAdmin">

	AllowOverride All
	Options none
	Order allow,deny
	Allow from all


    <FilesMatch "\.php$">
        SetHandler application/x-httpd-php
    <FilesMatch "\.phps$">
        SetHandler application/x-httpd-php-source

The above configuration file also includes settings for PHP and CGI.

Also make sure the following lines exist or are not commented out in the /etc/apache2/apache2.conf file for CGI functionality;

LoadModule mpm_prefork_module lib/apache2/
LoadModule cgi_module lib/apache2/

ScriptAlias /cgi-bin /usr/share/apache2/cgi-bin

<Directory /cgi-bin>
    AllowOverride None
    Options None
    Require all granted

Set permissions for the Apache document directory;

chown -R apache:apache /usr/share/apache2

find /usr/share/apache2 -type d -exec chmod 755 {} \;
find /usr/share/apache2 -type f -exec chmod 644 {} \;
Notes for Apache

In other installations, such as Redhat or CentOS, apache or apache2 is referred to as HTTPD in binary / executables, configuration files, commands, etc.

To test Apache configuration file: apachectl configtest

The below settings do NOT work or are NOT available in OpenWRT for Apache, so do NOT attempt to enable them in /etc/apache2/apache2.conf

  • LoadModule proxy_fcgi_module lib/apache2/ (Module does NOT exist for OpenWRT)
  • LoadModule proxy_scgi_module lib/apache2/ (Module does NOT exist for OpenWRT)
  • LoadModule cgid_module lib/apache2/ (does NOT seem to work, even when setting the ScriptSock Directive)


In the OpenWRT packages Lighttpd has CGI and FastCGI capability unlike Apache which only has CGI capability. OpenWRT has PHP 7 packages for CGI and FastCGI (opkg install php7-fastcgi) available to make use of the Lighttpd capabilities. The FastCGI capability also allows Lighttpd to utilize the PHP FPM capbability covered in several sections below.

Installation of Lighttpd

opkg update

opkg install lighttpd lighttpd-mod-cgi lighthttpd-mod-fastcgi

Configuration of Lighttpd

Configuration Files: /etc/lighttpd/lighttpd.conf

Additional Configuration Files: /etc/lighttpd/conf.d (see PHP sections below for additional information)

Service Command: service lighttpd (stop / start / restart)

Be Aware;

  • The OpenWRT Lighttpd package sets the default document directory to the same directory used by uHTTPd (the web service that provides the LuCI GUI). It is recommended modify the setting to a directory such as /usr/share/lighttpd (which follows the Apache directory convention used by OpenWRT).
  • The port number is set to 81 by default. This is done so as to not interfere with uHTTPd and LuCI. This can be changed to port 80, but the uHTTPd port must be changed to a different (non port 80) port in /etc/config/uhttpd and the uhttpd service restarted.

Below is a working /etc/lighttpd/lighttpd.conf configuration file;

Code Block
server.document-root        = "/usr/share/lighttpd"
server.port                 = 80
server.upload-dirs          = ( "/tmp" )
server.errorlog             = "/var/log/lighttpd/error.log"             = "/var/run/"
server.username             = "http"
server.groupname            = "www-data"

index-file.names            = ( "index.php", "index.html",
                                "index.htm", "default.htm",

#dir-listing.activate	    = "enable"
#server.dir-listing          = "enable"
#dir-listing.encoding        = "utf-8"

# Prevents a web browser from offering to download the file in text form
static-file.exclude-extensions = ( ".php", ".pl", ".fcgi" )

# To enable PHP with the Lighttpd Module, this line is the minimum necessary for it to function and should be placed in the /etc/lighttpd/conf.d/30-cgi.conf file;
# cgi.assign			= ( ".php"  => "/usr/bin/php-cgi" )

### Options that are useful but not always necessary:
#server.chroot               = "/"
#server.bind                 = "localhost"
#server.tag                  = "lighttpd"
#server.errorlog-use-syslog  = "enable"      = "writev"

### Use IPv6 if available
#include_shell "/usr/share/lighttpd/"

include "/etc/lighttpd/mime.conf"
include "/etc/lighttpd/conf.d/*.conf"

The above configuration file also contains settings relevant to additional items such as CGI and PHP which is covered in several below sections.

A new user (http in /etc/passwd) and a new group (www-data in /etc/group) are configured, so be sure to change the permissions and owner appropriately for a new root directory for Lighttpd;

chown -R http:www-data /usr/share/lighttpd

find /usr/share/lighttpd -type d -exec chmod 755 {} \;
find /usr/share/lighttpd -type f -exec chmod 644 {} \;
Notes for Lighttpd

To see the various modules compiled within the Lighttpd binary: lighttpd -V (that's a CAPITAL "V")

CGI and FastCGI

See the below PHP section for Lighttpd

php-cgi -b


First the bad news (which really isn't bad news): The mod_php module is not available for Apache. But that's OK, because there are several Apache Proxy Modules and PHP Modules that allow for PHP functionality with Apache using CGI, FastCGI, and PHP-FPM (see below for several external links that discuss the differences between the technologies).

The php-cgi (opkg install php7-cgi) package is available from OpenWRT and is necessary for PHP function with any of the above mentioned web servers. The guide at: leaves out a LOT of Apache configuration that is necessary to have PHP function correctly. Additionally, it adds some items that do not seem necessary. Of course this could be due to changes in the settings for the Apache package over the years or differences between router platforms, so the previous comments are not a criticism of OpenWRT or its documentation.

PHP Installation

opkg update

opkg install php7 php7-cgi php7-cli php7-fastcgi php7-fpm The php-cli (PHP Command Line) is not necessary, but is useful for troubleshooting. Most examples utilizing the PHP command line program refer to it as just php, not php-cli. OpenWRT installs it as php-cli, so instead of having to remember that, it maybe useful to create a symbolic link with this command: ln -s /usr/bin/php-cli /usr/bin/php

PHP Configuration in /etc/php.ini

Comment out or change the line in /etc/php.ini;

  • doc_root


  • #doc_root = WhatEver

The guide at: states the following should be put in the php.ini file, but is unnecessary;



  • extension=/usr/lib/php/

If the php7-mod-gd (opkg install php7-mod-gd) is installed, then the extension may be useful. It is related to graphics. And it isn't necessary to add that setting after the php7-mod-gd is installed, because when the package is installed it includes the /etc/php7/20_gd.ini file. The OpenWRT PHP binary / executable file is configured to automatically scan that directory for additional php module settings (-config-file-scan-dir=/etc/php7' is the included setting).

PHP Configuration for CGI

There are no specific settings for a "PHP CGI Service" as there are for the FastCGI PHP and PHP-FPM services. There are additional settings needed for Apache, Lighttpd, or Nginx to execute PHP scripts with their CGI capability (see below sections)


The php7-mod-fastcgi is configured as a service named php7-fastcgi and configured in /etc/config/php7-fastcgi. There are only two settings. One that enables the service and the other that sets the listening port (port 1026).

Additional Information about CGI, FastCGI, and PHP-FPM

CGI (Common Gateway Interface), FastCGI (Fast Common Gateway Interface), and PHP-FPM are different methods that each of the web servers included with OpenWRT can handle PHP script files. CGI is the oldest, easisest to setup, and slowest (although in low load environments, it will suffice). FastCGI and PHP-FPM require additional software packages and configuration.

Below are a couple of websites that discuss the differences, advantages, etc. of each technolgy;

PHP for Apache
Installing and Configuring Apache for PHP using CGI

Configuration Files;

  • Apache: /etc/apache2/apache2.conf
  • Apache Optional: /etc/apache2/extra/WhatEverAdditionalFile.conf
  • PHP: /etc/php.ini and /etc/php7

Service Commands;

  • service apache2 (stop / start / restart / reload)

Add and make sure the following settings exist in /etc/apache2/apache2.conf;

# When using PHP with "plain" CGI, the mpm_event_module must be disabled in favor of the mpm_prefork_module.  The mpm_event_module is utilized with php-fpm.
#LoadModule mpm_event_module lib/apache2/
LoadModule mpm_prefork_module lib/apache2/
LoadModule cgi_module lib/apache2/
LoadModule actions_module lib/apache2/

ScriptAlias /php /usr/bin

# AddHandler application/x-httpd-php .php
# Choose / Uncomment either the above or below setting.  They are functionally equivalent.
# AddType application/x-httpd-php .php

Action application/x-httpd-php /php/php-cgi

The above configuration settings are not the only ones that should be present in the /etc/apache2/apache2.conf file. They are only related to PHP functionality with CGI and are in addition to a functional apache.conf file that contains <Directory> and <VirtualHost> Directives along with other settings that allow for static .htm or .html files made available by Apache.

Notes on PHP for Apache and CGI

The cgi_module is necessary for for Apache to utilize the PHP binary / executable php-cgi file (the program that makes PHP function).

In addition to the similar functionality it shares with the Alias Directive, the ScriptAlias Directive designates the directory alias as containing PHP files that will be handled by CGI.

As noted in the comments in the above Code Block, either the AddHandler or AddType Directive can be used to configure what Apache does with files that end with the .php extension. The AddHandler Directive, the "application/x-httpd-php" name is a lablel that is used in the Action Directive to associated it with a binary. Some examples use a trailing slash ( / ) and quotes ( " ), but after experimentation, the trailing / isn't necessary and as long as spaces aren't used in a path, quotes aren't needed either.

The guide at: states the following should be put in the apache2.conf file, but was found to be unnecessary;

  <Directory "/usr/bin">
    AllowOverride None
    Options none
    Order allow,deny
    Allow from all
PHP for Lighttpd
Installing and Configuring Lighttpd for PHP using CGI (see FastCGI below too)

The lighttpd, lighttpd-mod-cgi, php7, and php7-cgi packages should be installed as noted above in the Lighttpd and PHP Installation Sections.

Configuration Files;

  • Lightttpd: /etc/lighttpd/lighttpd.conf
  • Lighttpd CGI: /etc/lighttpd/conf.d/30-cgi.conf
  • PHP: /etc/php.ini and /etc/php7

Service Commands;

  • service lighttpd (stop / start / restart)

Remember, the configuration file OpenWRT creates for CGI settings is /etc/lighttpd/conf.d/30-cgi.conf, not /etc/lighttpd/lighttpd.conf. It can be configured in the lighttpd.conf file, but to adhere to the OpenWRT convention it is recommended to place it in the 30-cgi.conf file.

Only the following lines are needed in the /etc/lighttpd/conf.d/30-cgi.conf ".php"  => "/usr/bin/php-cgi", see example below;

server.modules += ( "mod_cgi" )

cgi.assign                 = ( ".pl"  => "/usr/bin/perl",
                               ".cgi" => "/usr/bin/perl",
                               ".rb"  => "/usr/bin/ruby",
                               ".erb" => "/usr/bin/eruby",
                               ".php" => "/usr/bin/php-cgi",
                               ".py"  => "/usr/bin/python" )

The instructions also note the following setting be configured in the /etc/php.ini file, but it is already enabled by default in the OpenWRT php7 package: cgi.fix_pathinfo = 1

The remaining lines in the default configuration file are related to the default document directory chosen by OpenWRT for the Lighttpd installation. As recommended earlier, unless there are limited hardware resources available for a router, the location should be changed, thus negating the need for the additional settings.

Notes on PHP for Lighttpd and CGI

/usr/bin/php-cgi (with a bit of foreshadowing): The php-cgi binary / executable included with the php7-cgi OpenWRT package also includes FastCGI functionality. The php7-fastcgi package does not contain an additional binary. When installed, the php7-cgi package creates a symbolic link named /usr/bin/php-fcgi that points to the php-cgi file in the same directory. Additionally, a configuration file is inluded in /etc/config/php7-fastcgi package that enables FastCGI functionality. Type the following command to view the modules /usr/bin/php-cgi has available: php-cgi -m (this includes modules compiled in the php-cgi executable / binary file as well as added modules that are in separate files).

The instructions at indicate the above configuration is added to the /etc/lighttpd/lighttpd.conf file, but as noted, the /etc/lighttpd/conf.d/30-cgi.conf is the correct location for the AC Series of routers. If the instructions are followed it will cause a "Validation failed" error when starting the Lighttpd service because of two cgi.assign statements, as it is already present in the 30-cfi.conf file. It is possible the instructions are old or written for a different router platform, or the CGI configuration was separated and put into a different file at a later point.

Installing and Configuring Lighttpd for PHP using FastCGI

The lighttpd, lighttpd-mod-cgi, lighttpd-mod-fastcgi, php7, php7-cgi, and php7-fcgi packages should be installed as noted above in the Lighttpd and PHP Installation Sections.

Configuration Files;

  • Lightttpd: /etc/lighttpd/lighttpd.conf
  • Lighttpd FastCGI: /etc/lighttpd/conf.d/30-fastcgi.conf
  • PHP: /etc/php.ini and /etc/php7
  • PHP FastCGI: /etc/config/php7-fastcgi

Service Commands;

  • service lighttpd (stop / start / restart)
  • service php7-fastcgi (stop / start / restart)

Verify the following settings in the /etc/lighttpd/conf.d/30-fastcgi.conf file; and remove the comment hash tag (#) to enable them;

Code Block
fastcgi.server = ( ".php" =>

    # Be careful: lighty does *not* warn you if it doesn't know a specified option here (make sure you have no typos)
      # To enable FastCGI PHP functionality, enable the below host and port settings (default port for FastCGI is 1026)
      #"host" => "" ,
      #"port" => "1026" ,
      # To use FPM, disable the above host and port and enable either the port or socket method below (only one)
      # Socket Method
      "socket" => "/var/run/php7-fpm.sock",                 # either socket or host+port
      # Port Method (default port for PHP-FPM is 9000)
      #"host" => "" ,
      #"port" => "9000" ,
      # Which to use (Port or Socke)?
      # Research indicates there is less overhead associated with a socket.  A disadvantage for using a socket instead of a port is functionality is limited to a local server with some potential issues that occur with high usage situation.  A Port is also technically noted to be a type of socket with a disadvantage of slightly higher overhead and potential exhaustion of usable TCP ports.
      #"bin-path" => "/usr/bin/php-fpm",    # optional 
      #"bin-environment" => <array>,         # optional 
      #"bin-copy-environment" => <array>,    # optional 
      #"mode" => <string>,                   # optional
      #"docroot" => <string> ,               # optional if "mode" is not "authorizer" 
      #"check-local" => <string>,            # optional
      #"max-procs" => <integer>,             # optional - when omitted, default is 4
      #"broken-scriptfilename" => <boolean>, # optional
      #"fix-root-scriptname" => <boolean>,   # optional, since 1.4.23 (option didn't work before 1.4.23)
      #"disable-time" => <integer>,          # optional
      #"allow-x-send-file" => <boolean>,     # optional, (deprecated since 1.4.40)
      #"x-sendfile" => <boolean>,            # optional, since 1.4.40
      #"x-sendfile-docroot" => <array>,      # optional, since 1.4.40
      #"kill-signal" => <integer>,           # optional, default is SIGTERM(15) (v1.4.14+)
      #3"tcp-fin-propagate" => <boolean>      # optional, propagate TCP FIN to backend (since 1.4.50) (default: disabled)
    )     = ( ".php3" => ".php",
                               ".php4" => ".php",
                               ".php5" => ".php",
                               ".phps" => ".php",
                               ".phtml" => ".php" )

The above example includes comments and settings related to PHP FPM (see below). And remember, most examples given by OpenWRT note the above settings in /etc/lighttpd/lighttpd.conf file, but that is not the case for the AC series of routers. An more detailed explanation of the above settings can be found here: If additional FastCGI extensions other than .php, such as .php3, .php4, etc ensure the following items are configured in /etc/lighttpd/conf.d/30-fastcgi.conf;

Code Block     = ( ".php3" => ".php",
                               ".php4" => ".php",
                               ".php5" => ".php",
                               ".phps" => ".php",
                               ".phtml" => ".php" )

And finally, in order to ensure FastCGI is handling the PHP calls, disable or delete the /etc/lighttpd/conf.d/30-cgi.conf file.

Notes on PHP for Lighttpd and FastCGI

As noted above, if CGI (not FastCGI) is left enabled and everything is left in the default configuration order supplied by OpenWRT, the CGI interface will intercept PHP files before FastCGI. And as noted, the solution is to disable CGI (not really desireable) or change the order in the /etc/lighttpd/conf.d file by changing the name of the file from "30-cgi.conf" to "31-cgi.conf" so the settings in the "30-fastcgi.conf" file will take precidence. Why did OpenWRT not name it this way in the first place? Not sure, but it seems like it might be a good idea to change it at some point.

/usr/bin/php-cgi (with a bit of foreshadowing): The php-cgi binary / executable included with the php7-cgi OpenWRT package also includes FastCGI functionality. The php7-fastcgi package does not contain an additional binary. When installed, the php7-cgi package creates a symbolic link named /usr/bin/php-fcgi that points to the php-cgi file in the same directory. Additionally, a configuration file is inluded in /etc/config/php7-fastcgi package that enables FastCGI functionality. Type the following command to view the modules /usr/bin/php-cgi has available: php-cgi -m (this includes modules compiled in the php-cgi executable / binary file as well as added modules that are in separate files).

There does not seem to be a good way to verify whether CGI or FastCGI are handling PHP functionality for Lighttpd. Adding the single line of: <?php phpinfo(); ?> into a file named "info.php" will return an abundant amount of information including a line that states: Server API: CGI/FastCGI, whether using CGI or FastCGI, so it isn't very helpful. A method to confirm FastCGI is being used instead of CGI would be to disable or delete the /etc/lighttpd/conf.d/30-cgi.conf file.

Installing and Configuring Lighttpd for PHP using FPM (which relies on FastCGI)

The lighttpd, lighttpd-mod-cgi, lighttpd-mod-fastcgi, php7, php7-cgi, php7-fcgi, and php-fpm packages should be installed as noted above in the Lighttpd and PHP Installation Sections.

Configuration Files;

  • Lightttpd: /etc/lighttpd/lighttpd.conf
  • Lighttpd FastCGI: /etc/lighttpd/conf.d/30-fastcgi.conf
  • PHP: /etc/php.ini and /etc/php7
  • PHP FastCGI: /etc/config/php7-fastcgi
  • PHP FPM: /etc/config/php7-fpm, /etc/php7-fpm.conf, and /etc/php7-fpm.d

Service Commands;

  • service lighttpd (stop / start / restart)
  • service php7-fastcgi (stop / start / restart)
  • service php7-fpm (stop / start / restart)

Modify the settings in /etc/php7-fpm.d/www.conf as follows;

; A Port or Socket can be defined for the php7-fpm Service (only choose one)
; And remember to change the settings in the Lighttpd 30-fastcgi.conf file depending on which choice is made.
; Port
; listen =
; Socket
listen = /var/run/php7-fpm.sock

; If the Socket method above is chosen, the following items must also be set, otherwise a "Permission denied socket" error will occur when the php7-fpm service is started.
listen.owner = http = www-data
listen.mode = 0666

Do not make the mistake of using hash tags ( # ) for comments as they will prevent the php7-fpm service from running. Modify the settings in /etc/lighttpd/conf.d/30-fastcgi.conf noted in the above section as follows;

#"host" => "" ,
#"port" => "1026" ,
"socket" => "/var/run/php7-fpm.sock",
Notes on PHP for Lighttpd and FPM (with FastCGI)

Make sure FastCGI is functioning correctly before FPM is added and configured. Adding the single line of: <?php phpinfo(); ?> into a file named "info.php" will now include useful information about what service is handling PHP requests: Server API: FPM/FastCGI

Additional Information about PHP with CGI VS PHP with FastCGI VS PHP with FPM can be found here;

Testing PHP Functionality

Create and save a PHP file (test.php) with this single line of code in it: <?php phpinfo(); ?>

PHP functionality can be tested with that file;

  • From a command line type the following: php-cgi /WhatEverPath/test.php
  • Place the file in a directory served by Apache (/usr/share/apache2/htdocs) and navigate to that file

As noted previously, but worth mentioning again, OpenWRT names the interactive command line interface for PHP php-cli. Most sites give examples that use the command php, so to make it easier create a symbolic link with this command: ln -s /usr/bin/php-cli /usr/bin/php

MariaDB Server

  • opkg update
  • opkg install mariadb-server mariadb-client libaprutil-dbd-mysql mariadb-server-extra mariadb-client-extra (dependencies are automatically installed)
  • Change the "option enabled '0'" to a '1' to enable in the /etc/config/mysqld file
  • Modify the following items in the /etc/mysql/50-server.cnf file;
    • Use the ARIA database engine instead of the default InnoDB to streamline RAM usage in the [mysqld] category of the file: default-storage-engine = aria (after finishing configuration, check at the MySQL command prompt with this command: SHOW ENGINES;
    • Move the database to an external eSATA drive: datadir        = /mnt/sdb3/mysql
    • Move the tmp directory to an external eSATA drive: datadir        = /tmp (This directory is relative to the datadir, in that it will be created at the same level as the mysql directory, so this is not an abolute path where it will utilize the /tmp directory in the root of the file system)
  • To create the default database: mysql_install_db --force --basedir=/usr
  • Start the service: service mysqldb start
  • To create a password for the current user (blank if not configured): /usr/bin/mysqladmin -u root password 'new-password'
  • Log into the command line for the database: mysql -u root -p or use phpMyAdmin see below
Optimizing for a Low Memory Footprint with the ARIA Engine


Importing and Migrating Data from Other SQL Servers

To take advantage of the ARIA database engine, any databases imported should not have any information about engine="WhatEverDBengine". If they do, the database engine defined for each table will be used. If they do not have any information about which engine is assigned to a database, the default engine for the database server will be used. Use the below command to export a .sql database file (no method appears to be available with phpMyAdmin to export a database without the engine information included);

  • mysqldump -u root -p --skip-create-options WhatEverDatabaseName > WhatEverDatabaseFile.sql;
  • If using phpMyAdmin to import the database note the following
    • It is far slower and far more resource intensive (on the order of about 25 times) than using the command line to import a database.
    • For Apache web servers, when importing large databases, the TimeOut Directive should be set to a higher value to avoid a "Gateway Timeout" error. The default is 60 seconds.
    • This setting in the phpMyAdmin configuration file,, can be set too, but isn't necessary: $cfg['ExecTimeLimit'] = 3600;
    • Alternatively, use this command to import a database via the command line: mysql -u root -p WhatEverDatabaseName < /PathTo/DatabaseFile
General Information

Default database location: /mnt/data/mysql/ Default TEMP directory: /tmp Default database engine: InnoDB

Memory footprint..., Aria see,, and the MariaDB Cookbook

Storage engines: innodb is the default, MyISAM is older, but has the smallest footprint, Aria seems to be the middle road (

Show available storage engines: SHOW ENGINES\G or show engines;


  • opkg update
  • opkg install php7-mod-mbstring php7-mod-json php7-mod-hash php7-mod-ctype php7-mod-zip php7-mod-gd php7-mod-mysqli php7-mod-session php7-mod-snmp zoneinfo-northamerica (if one is in North America, if not, choose another zone and remember, phpMyAdmin will display a blank page with no error if a zoneinfo-WhatEverZone is not installed in addition to the zoneinfo-core package, see additional information below, dependencies will also be installed automatically).

Make sure the /usr/share/apache2/htdocs/phpMyAdmin/tmp has 777 permissions, otherwise Apache based phpMyAdmin sites may stop responding: chmod 777 /usr/share/apache2/htdocs/phpMyAdmin/tmp

The following item is VERY important, hence it's typeface in BOLD CAPITAL letters. If the appropirate additional time zone module is not installed it can cause a completely invisible error (IE, no error in Apache, Lighttpd, or PHP logs). IE, it only displays a blank page. Even using a command line instance of PHP will not reveal the error. This line in the /phpMyAdmin/libraries/classes/Core.php file: date_default_timezone_set(@date_default_timezone_get()); is the source of the issue (Note, this is not the fault of phyMyAdmin, but it would be nice if they wrote a bit of code to address this situation). The error message that can be coaxed out of Lighttpd by taking that line of code and placing it in a file by itself is: Timezone database is corrupt – this should never happen! (thanks to this site for a key bit of information on that issue:

  • ALSO MAKE SURE TO INSTALL THE APPROPRIATE TIME ZONE MODULE, IN ADDITION TO THE DEFAULT zoneinfo-core: opkg install zoneinfo-northamerica (for example)
  • To install all of the php7-mod packages if desired, but not necessary:opkg list | grep php7-mod-| awk '{print $1}' | xargs opkg install
  • wget (or whatever the latest version is)
  • If not installed, wget needs: opkg install libustream-mbedtls20150806 (or whatever other version, type opkg list libustream* to see available packages)
  • tar -xzvf phpMyAdmin-4.9.5-english.tar.gz
  • mv WhatEverUnTarredDirectory /usr/share/apache/htdocs OR WhatEverLighttpd Directory
  • Change the permissions to what they should be, see CHOWN, etc. in the above Lighttpd section
  • Browse to: http://WhatEverURL/phpMyAdmin/setup/index.php, or use the below configuration file (/WhatEverPath/
Code Block

/* Servers configuration */
$i = 0;

/* Server: WRT3200ACM [1] */
$cfg['Servers'][$i]['verbose'] = 'WRT3200ACM';
$cfg['Servers'][$i]['host'] = '';
$cfg['Servers'][$i]['port'] = '3306';
$cfg['Servers'][$i]['socket'] = '';
$cfg['Servers'][$i]['auth_type'] = 'cookie';
$cfg['Servers'][$i]['user'] = 'root';
$cfg['Servers'][$i]['password'] = 'WhatEverPassword';
$cfg['Servers'][$i]['MemoryLimit'] = '-1';

/* End of servers configuration */

$cfg['blowfish_secret'] = '\'ci.NDxXw@1QB^Y!x(`QY0<&e!|)XG`?';
$cfg['DefaultLang'] = 'en';
$cfg['ServerDefault'] = 1;
$cfg['UploadDir'] = '';
$cfg['SaveDir'] = '';
  • The file permissions have to be set to whatever the web server is: chown apache:apache OR http:www-data (for Apache OR Lighttpd) and chmod 644
  • REMEMBER: If using Lighttpd with PHP-FPM, restart the php7-fpm service as it does not automatically restart when Lighttpd is restarted (unless configured)
  • Also to remember to configure proper security for the phpMyAdmin within Apache or Lighttpd to restrict access to say only local IP Addresses.
  • It will also prompt to set up a phpMyAdmin table within the database, just click on the links and it will automatically create the database
  • Configure a TEMP folder for phpMyAdmin to use in the file: $cfg['TempDir'] = '/tmp/phpMyAdmin'; (as an example, make sure chmod 777 /tmp/phpMyAdmin, and to create the directory and set permissions when the router is rebooted in the rc.local file as everything in the /tmp directory will be deleted after a reboot of a router)
  • Also consider increasing php.ini settings for memory, upload, etc.
    • memory_limit = 100M
    • file_uploads = On
    • upload_max_filesize = 128M
    • post_max_size = 128M
    • max_file_uploads = 20
  • To diagnose any issues when attempting to access the phpMyAdmin setup this will display the error message (look for the line that says WarnMissingExtension to spot missing modules): php-cli /usr/share/apache2/htdocs/phpMyAdmin/setup/index.php
LetsEncrypt / ACME

opkg update

opkg install acme luci-app-acme

Additional Reading for OpenWRT and LAMP

A nice summary and comparison of CGI, FastCGI, and PHP-FPM:

Other Software, Utilities, Drivers, & System Configuration, etc.

Package Installation with OPKG

opkg is the package management utility on OpenWRT.

Useful Utilities & Features

General Utilities

Superior text editor to VI: nano

TAR: For .tar files, BusyBox has a builtin tar command, however opkg install tar will install the full TAR suited allowing for extraction of many more types of .tar files beyond ones that are compressed with .gz / gunzip, including .xz among others.

Enhanced version of TOP (AKA Task Viewer): htop

GUI for Web Server (uHTTPd) that facilitates LuCI (the OpenWRT Web GUI): luci-app-uhttpd

"HTTPS capability" for WGET (WGET is installed by default but does not support HTTPS): libustream-mbedtls20150806 (or whatever current package name, or alterntively: opkg install libustream-mbedtls*, NOTE: the SSL version will not work)

For proper time zone detection by PHP and other scripts be sure to install whatever local time zone module is appropriate in addition to the core timezone software package (zoneinfo-core): zoneinfo-northamerica (as an example, there are other packages for the rest of the world)

To install all of the above noted utilities;

  • opkg update
  • opkg install htop restic luci-app-uhttpd libustream-mbedtls20150806 zoneinfo-northamerica

Full Versions of Commands available in BusyBox (but limited in BB due to size constraints)

  • opkg list coreutils*
  • opkg list shadow*
  • opkg list procps*

Additional commands are hidden in various other non-intuitive locations. If a desired command or utility isn't available, search for it by name in the LuCI GUI interface, System, Software, Filter Field and then install the package it is contained in. Use caution as some package names and descriptions are a bit misleading and may install undesired programs.

Alternate Shells

OpenWRT uses the ASH (put in CAPS to make it stand out, but technically correctly referred to as ash) as the default shell within the BusyBox Binary / Executable. There are other choices. See the following two articles for an excellent explanation;

To install the chsh utility: opkg install shadow-chsh

Network Tools for Diagnostics

A tool to see all the ports a router is listening on: lsof -i -P -n | grep LISTEN (install the package with this command: opkg install lsof)

To see services listening on specific ports: netstat -lnp | grep WhatEverPortNumber

To install all of the above noted utilities;

  • opkg update
  • opkg install lsof

File Transfer Programs


Copy files between Linux machines using SCP, which in turn uses the SSH protocol (IE, nothing has to be installed on the client)

To copy from one router to another: scp -r /local/directory UserName@RemoteIPAddress:/remote/


A free Windows based program that enables easy Explorer like file transfers between a Windows Computer and a router via the SSH protocol (built into OpenWRT and enabled by default):

Note: SCP is not the fastest file transfer method, as it uses a copious CPU amount, but it is convenient. For large file transfers configure SAMBA (see below).

Samba Server and File Sharing

There are two versions of Samba Server available, 3.6.25 and 4.x.

  • opkg update
  • opkg install samba36-server OR opkg install samba4-server samba4-utils
  • opkg luci-app-samba OR opkg install luci-app-samba4
  • smbpasswd -a root (or whatever user is desired)

The stock OpenWRT Samba Server Configuration (in LuCI) can be replaced with something similar to below (LUCI GUI, Service, Network Shares, Edit Template Tab);

Code Block
        netbios name = OpenWRT
        server string = Samba on OpenWRT
        workgroup = WORKGROUP
        guest account = nobody
        security = user
        map to guest = Bad User
        guest ok = yes
        guest only = no
        timestamp logs = no
        preserve case = yes
        short preserve case = yes
        log level = 0
        syslog = 0
        passdb backend = smbpasswd
        smb encrypt = disabled
        smb passwd file = /etc/samba/smbpasswd

Below is the default OpenWRT configuration for Samba Server 3

Code Block
	netbios name = |NAME| 
	display charset = |CHARSET|
	interfaces = |INTERFACES|
	server string = |DESCRIPTION|
	unix charset = |CHARSET|
	workgroup = |WORKGROUP|
	bind interfaces only = yes
	deadtime = 30
	enable core files = no
	invalid users = root
	local master = no
	map to guest = Bad User
	max protocol = SMB2
	min receivefile size = 16384
	null passwords = yes
	passdb backend = smbpasswd
	security = user
	smb passwd file = /etc/samba/smbpasswd
	use sendfile = yes

A key to getting Samba 4 to work properly with Windows 10 is this: map to guest = Never The below is an actual functional smb.conf file for Samba 4 that works with Windows 10. Thanks to for the key piece of information. Click here for the default OpenWRT configuration for Samba 4.

Code Block
	netbios name = |NAME| 
	interfaces = |INTERFACES|
	server string = |DESCRIPTION|
	unix charset = |CHARSET|
	workgroup = |WORKGROUP|
        security = user
        timestamp logs = no
        preserve case = yes
        short preserve case = yes
        log level = 0
        syslog = 0
        passdb backend = smbpasswd
        smb passwd file = /etc/samba/smbpasswd
        # Below is the key to getting Samba Server to work with Windows 10
        map to guest = Never

There are so many different sources that babble about solving the Samba / Windows 10 issues that include ntlm = true, server min protocol = SMB3, min protocol = SMB3, blah, blah, blah. Nothing works. All of these items seem to be set correctly with default values as of a version of Samba sometime after 2019, so they do not fix the issue. For the "You can't access this shared folder because your organization's security policies block unauthenticated guest..." Error Message, the above noted map to guest = Never solves the issue

Then dd a Network Share: In LUCI GUI, Service, Network Shares, General Settings or Edit Template Tab, enter a Name and a Path, the other defaults are fine.

If any attempts are made to edit the /etc/samba/smb.conf file directly, it will be overwritten each time by OpenWRT as that's the way it functions in OpenWRT. It can be prevented, but it is recommended not to do that in order to preserve the standard functionality of OpenWRT.

And lastly, remember if one attempts to share the "Root Directory" ( / ), none of the sub directories will open, because of the way the OpenWRT file system works.


First a warning so no one gets frustrated. Right out of the box, the configuration for PPTPD from OpenWRT is broken. The hint was found here: And as of 8.2020 it is still busted. How to fix it? Well, follow the below directions.

option 'logwtmp' '0'


opkg install pptpd ppp (dependencies will automatically be installed if just pptpd is installed)

There is no LuCI GUI available

Configuration and other PPTPD Related File Locations

OpenWRT PPTPD Configuration File: /etc/config/pptpd

PPTPD Configuration File: /etc/pptpd.conf* (BIG Asterisk here, see below)

(This can be seen in the /etc/init.d/pptpd startup script where the actual location is /tmp/etc/pptpd.conf. This makes sense if PPTPD within the OpenWRT configuration paradigm)

PPP Configuration Files: /etc/ppp

chap-secrets (AKA User Names and Passwords for PPTPD): /etc/ppp/chap-secrets (/tmp/etc/chap-secrets)

Resolve File: /etc/ppp/resolv.conf (/tmp/resolv.conf.ppp)

NOTE: Several of the above files are symbolic links. The original files are noted in parenthesis ( ).

Configuring PPTPD

First, configure the /etc/config/pptpd file. Below is a working example;

config service 'pptpd'
	option 'enabled' '1'
	option 'localip' 'W.X.Y.Z-ABC'
	option 'remoteip' 'W.X.Y.Z-ABC'
	option 'logwtmp' '0'

config 'login'
	option 'username' 'WhatEverUserName'
	option 'password' 'WhatEverPassword'

config 'login'
	option 'username' 'AnotherUserNameETC'
	option 'password' 'AnotherPaswordETC'

Notice the option 'logwtmp' '0' line. It MUST be included for the service to start (or the startup script has to be modified). And of course substitute the W.X.Y.Z and ABC with your own IP Address range.

The above noted "logwtmp" setting is NOT included in the default pptpd file. That's odd, because the /etc/init.d/pptpd startup script explicilty checks for the existence of that setting and will show an "sh: out of range" error message if it is not included. And the main OpenWRT documentation page for PPTPD does not mention it at all. It's almost like the nice people at OpenWRT don't want PPTPD to be used. It is a somewhat "old & busted" VPN protocol (Google it), so using a more modern alternative like OpenVPN would be a good choice. But sometimes it is necessary to support older protocols such as this.

From there everything gets better. The following files can be manually configured and the PPTPD startup script copies them to the /var/etc directory for the service to use when it starts up;

  • /etc/pptpd.conf (see below for a working version of this file, slightly different than the default OpenWRT version)
  • /etc/ppp/options
  • /etc/ppp/options.pptpd (see below for a working version of this file, slightly different than the default OpenWRT version)

Below is a working example of the /etc/pptpd.conf file;

#speed 115200
#stimeout 10
#localip & remoteip are not needed, ip management is done by pppd

# The above lines are the default OpenWRT settings for /etc/pptpd.conf.  The last comment is not very accurate.
# Translating the above geek talk, look in /etc/ppp for the options.pptpd file for additional options.

# The Webmin PPTP VPN Server Module stores information here in this file, /etc/pptpd.conf

# The below option setting may be redundant as it is included in the /etc/init.d/pptpd startup script in OpenWRT
# But for the sake of including it so it is displayed within the Webmin interface, it is included here.

option	/etc/ppp/options.pptpd
pid-file /var/run/
connections 5

# If using just the /etc/config/pptpd method to configure PPTPD, then the below two items are not necessary
# However, if the PPTPD Webmin Module is being used, those settings should be included here.
localip	W.X.Y.Z
remoteip W.X.Y.Z

# Also, if Webmin is being used, the redundant information above should be removed from the /etc/config/pptpd file

Below is a working example of the /etc/ppp/options.pptpd file;

logfile /var/log/pptp-server.log


ms-dns W.X.Y.Z
ms-wins W.X.Y.Z

# This option is NOT supported by the OpenWRT PPTPD
# require-mppe-128

# Name of the local system for authentication purposes 
# (must match the second field in /etc/ppp/chap-secrets entries)
# The default OpenWRT PPTPD name used in the autogenerated chap-secrets file is pptp-server 
name pptp-server

### Additional settings from the Original OpenWRT configuration file shown here as disabled

## lcp-echo-failure 3
## lcp-echo-interval 60
## default-asyncmap
## mtu 1482
## mru 1482
## nobsdcomp
## nodeflate

And for both of the above examples, include your own IP Addres information where W.X.Y.Z is noted.

Don't for get to configure firewall settings such that it allows PPTP connections from the internet. After all, that's what it is for. Below are the settings to include in the /etc/config/firewall file or to configure within the LuCI GUI, Network, Firewall, Traffic Rules Tab;

config rule
	option dest_port '1723'
	option src 'wan'
	option name 'PPTP'
	list dest_ip 'W.X.Y.Z'
	list dest_ip 'W.X.Y.Z'
	option target 'ACCEPT'
	option family 'ipv4'
	option proto 'tcp'

config rule
	option target 'ACCEPT'
	option name 'GRE for PPTP'
	option src 'wan'
	option proto '47'

The above list dest_ip 'W.X.Y.Z' are only needed if using MWAN3 and can be eliminated from firewall configurations that don't have to consider multiple WAN ports.

And one last thing to configure are couple of things the startup / shutdown script does not do.

  • It does not delete / clean up the /var/run/ file
  • It does not delete the /etc/var/chap-secrets file that is generated. The interesting fallout from this is that every time the PPTPD service is stopped an started, it appends the information in the 'login' section of the /etc/config/pptpd file to /var/etc/chap-secrets. If there are several user names and the service is restarted a couple of times, the number of redundant logins increases quite quickly.

Insert the following code into the /etc/init.d/pptpd file to correct those issuea;

stop_service() {
	rm /var/run/
	rm /var/etc/chap-secrets

Please note, that if the service is ever upgraded, that bit of code will need to be reinserted. But given that the PoPtOp Daemon hasn't been updated since October of 2013, there probably aren't additional updates on the horizon (

Additional Information

The information on the OpenWRT site on PPTP is a bit misleading, because as noted above /etc/pptpd.conf is not the true configuration file. It is actually generated dynamically as many OpenWRT services are. It also references an issue with the /etc/init.d/pptpd startup script that no longer seems to exist.

This option for the /etc/ppp/options.pptpd is NOT supported by the OpenWRT PPTPD service: require-mppe-128 (an In file /var/etc/options.pptpd: unrecognized option 'require-mppe-128' error will occur if it is included). It should also be noted that the mppe-128 is built into the OpenWRT /usr/sbin/pptpd binary / executable file, thus making the setting unneccessary as it is enabled by default (pptp-server.log if enabled shows this: MPPE 128-bit stateless compression enabled).


This section is written for people that are experienced with OpenVPN.

The LuCI interface provides a nice interface for keeping track of OpenVPN Server and Client configuration, plus editing and enabling and disabling a specific Server or Client configuration file. OpenVPN for OpenWRT operates as it did for CentOS 6 where a single "OpenVPN Service" would "spawn" multiple instances of the OpenVPN binary / executable depending on how many Server and Client configuration files there are. CentOS 7 and newer has it configured such that each instance of an OpenVPN Server and / or Client configuration file requires a separate service.


  • opkg update
  • opkg install openvpn-easy-rsa openvpn-openssl (Any dependencies will automatically be installed, also see Notes section below)
  • Install the LuCI GUI interface for OpenVPN manually (see note below on the LuCI, System, Software installation for the OpenVPN LuCI GUI below)
    • opkg download luci-app-openvpn
    • opkg install WhatEverTheFileNameThatGetsDownloaded

Files & Directories

  • /etc/config/openvpn: File for OpenVPN connections configured within the LuCI GUI interface AND "includes" for additional OpenVPN configuration files
  • /etc/openvpn: Directory for storing all other OpenVPN settings and OpenSSL settings related to OpenVPN
  • /etc/openvpn/keys: Common directory name for storing OpenVPN certificates. Manually create.
  • /etc/openvpn/ccd: Common directory name for storing OpenVPN client configuration settings. Manually create.
  • /etc/openvpn/client: Unused by the OpenWRT version of OpenVPN, sometimes used with other Linux distributions (CentOS, etc.). It is recommended to store all Server and Client configuration files in /etc/openvpn as that is the only directory scanned by the /etc/init.d/openvpn OpenVPN Service startup script.
  • /etc/openvpn/server: Unused by the OpenWRT version of OpenVPN, sometimes used with other Linux distributions (CentOS, etc.). It is recommended to store all Server and Client configuration files in /etc/openvpn as that is the only directory scanned by the /etc/init.d/openvpn OpenVPN Service startup script.
  • etc/openvpn/openvpn-ssl.cnf: Common configuration file name for OpenSSL settings when creating certificates for OpenVPN


OpenWRT LuCI Configuration File (/etc/config/openvpn) for a single OpenVPN Service instance;

config openvpn 'Server'
	option config '/etc/openvpn/Server.conf'
	option enabled '1'

The LuCI GUI can be used in a myriad of ways. The most basic of which is to manage OpenVPN configuration files that are created in a text editor.

Working example of an OpenVPN Server configuration file (not to be confused with the OpenWRT Luci configuration file, see above);

dev tun2
port 1194
proto udp
verb 3
push "route"
client-config-dir ccd
keepalive 15 120
ca /etc/openvpn/keys/CA.for.WRT3200ACM/ca.crt
cert /etc/openvpn/keys/CA.for.WRT3200ACM/server.wrt3200acm.crt
key /etc/openvpn/keys/CA.for.WRT3200ACM/server.wrt3200acm.key
dh /etc/openvpn/keys/CA.for.WRT3200ACM/dh2048.pem

In the above configuration file, it is assumed the local subnet is and that keys have already been generated (see below section for using Webmin to generate certificates). The above storage location for keys is just an example that can be customized to any directory.


And don't forget to open up the appropriate ports on the firewall;

  • Use the LuCI GUI, Network, Firewall, Traffic Rules Interface to configure


  • Edit the /etc/config/firewall File

The standard OpenVPN Server Port is 1194 UDP

Certificate Management for OpenVPN with Webmin (see Webmin Section below)

First the reminders;

  • Do NOT use Webmin for OpenVPN settings. Instead use the LuCI GUI and / or edit text files (starting and stopping the service is fine)
  • ONLY use it for Certificate management for OpenVPN.
  • Watch out when clicking the "Keys list" link as it is very close to the Remove link. If the Remove link is clicked, there is no confirmation about deleting the entire Certificate infrastructure.
Configuring a Certificate Authority Infrastructure (Certificate Authority, Server Certificate, Client Certificate(s)

For some odd reason (possibly troubleshooting), it is possible to create an OpenVPN infrastructure that transmits information without encryption. That's a bit too "open". In order to encrypt communication one must create a "Certificate Infrastructure". This includes first, a Certificate Authority (CA), then a certificate for a Server, then certificate(s) for clients.

There are many tutorials on this, all of them use the command line. Webmin makes it very easy to do and keep track of certificates. Even with that capability, keeping things in an organized structure is important. This includes naming conventions. A CA could be named Mary Poppins. But that isn't very helpful as a name for a CA if others are involved in managing an infrastructure.

If the Webmin module is configured as noted below, the entire certificate infrastructure (minus OpenSSL settings) will be stored in /etc/openvpn/keys

  • Create a Certificate Authority

Webmin for OpenVPN and Certificate Management

Only some features of the Webmin Module are useful. First and foremost is the Certificate management. Works great. As noted above, watch out when clicking the "Keys list" link as it is very close to the Remove link. If the Remove link is clicked, there is no confirmation about deleting the entire Certificate infrastructure. Bad design, oh, well.

Between the LuCI GUI and Certificate Management portion of Webmin, all aspects of OpenVPN can be conveniently controlled via a GUI interface.

The log display doesn't work properly, even when log files are configured properly.

Editing and managment of the OpenVPN service

The Webmin module for OpenVPN & Certificate management is not a "standard module".

  • Install in the Webmin interface: Webmin, Webmin Configuration, Webmin Modules, Install from Local File, Select File, Install Module.
  • By default, the OpenVPN... Module is located in Servers. Given that it deals with Networking and an equivalent Module (PPTP) is located in Networking, it makes sense to relocate the Module to Networking
    • Webmin, Webmin Configuration, Reassign Modules, OpenVPN..., Networking, Save

Below is a working configuration file for the OpenVPN & Certificate Authority Module (/etc/webmin/openvpn)

start_cmd=/etc/init.d/openvpn start
stop_cmd=/etc/init.d/openvpn stop


  • Use the OpenSSL version of OpenVPN (openvpn-openssl), not the mbedTLS (openvpn-mbedtls), and definately not openvpn-nossl (there is no security, but possibly good for testing configuration files). See here for additional information
  • If the /etc/config/openvpn file contains any sort of syntax error (if the file has been modified in a text editor for example), the configuration file will upload, but it will not be displayed as available in the LuCI OpenVPN GUI.
  • There's a bit of an issue with the OpenVPN LuCI interface when using the OVPN configuration file upload. When the Browse button is clicked, the initial "Choose File to Upload" dialogue selects .ovpn as the default file extension. This might lead one to believe that any files uploaded should have a file name that ends in .ovpn. This is not the case. A quick inspection of the /etc/init.d/openvpn file for the OpenVPN service reveals that it scans for files ending in .conf. So make sure any files uploaded via the LuCI GUI interface for OpenVPN end in .conf.
  • The /etc/openvpn Directory contains two sub-directories: client and server. These are default OpenVPN directories, but it also implies that Server and Client configuration files should be placed in these directories. This is not the case. An examination of the /etc/init.d/openvpn OpenVPN configuration file revealse that it only scans the /etc/openvpn Directory for configuration files. Additionally, the LuCI GUI interface for OpenVPN places the files in /etc/openvpn and does not scan the sever and client sub-directories for additional configuration files.
  • As of 8.2020, there is also an issue with the version number of of the LuCI GUI for OpenVPN (luci-app-openvpn). The package version displayed via the System, Software page in the LuCI GUI displays git-2.229... Downloading the IPK file manually (opkg download luci-app-openvpn) results in version git-2.234... Additionally, the installation or upgrade via the LuCI GUI for the OpenVPN LuCI GUI interface seems to be unreliable. The recommendation is to download manually (opkg download luci-app-openvpn) and install the downloaded file (opkg install WhatEverTheNameOfTheFileIs)
  • Sadly, possibly due to space constraints and the desire to have the smallest binary / executable file possible for OpenVPN, the OpenWRT version does not contain any "help" information (IE, openvpn --help produces no output)

To install OpenVPN with OpenSSL and the LUCI GUI for it (under VPN)

  • opkg update
  • opkg install openvpn-openssl openvpn-easy-rsa luci-app-openvpn luci-ssl-openssl (openssl-util and other dependencies will automatically install)
  • OpenVPN will be available under LuCI GUI, VPN, OpenVPN (Remember to refresh the web browser window to display the new category (Firefox: CTRL + Refresh) or log out and log back into the LuCI GUI)


ProFTPD does not seem to be available as an OpenWRT package anymore. At some point (appx. 2012 or earlier) it was, as evidenced by:

Use vsFTPD instead.



opkg update

opkg install vsftpd


Configuration File: /etc/vsftpd.conf

  • Be sure to read the
  • The default configuration file (/etc/vsftpd.conf) for VSFTPD will never work under any circumstances for an OpenWRT router that is in a "normal" / default configuration in regards to its firewall and several other items. It is understood that the OpenWRT developers have better things to do than configuring an old FTP server, but they may as well leave the configuration file blank or perhaps include all of the options, but comment everything out rather than having a configuration file that does nothing more than give an end user false hope.
  • The OpenWRT Package creates an /etc/vsftpd Directory, but it isn't used. Case in point: The default userlist_file name for the OpenWRT version of VSFTPD is /etc/vsftpd.user_list. For other platforms such as CentOS, that file is located in the /etc/vsftpd Directory, but for OpenWRT it is located in the /etc Directory. So why is the /etc/vsftpd Directory created (with nothing in it)? Best guess is that since other Platforms like CentOS that put configuration files in the /etc/vsftpd Directory, there might be some "template" in the vsftpd source code that creates that Directory by default and the OpenWRT developers forgot to disable that function.
  • The /etc/init.d/vsftpd startup script is very simple. So simple in fact that it requires a setting (listen=YES) in the .conf file for vsFTPD for vsFTPD that documentation indicates is set to "yes" if vsFTPD is NOT run via an init.d script. In OpenWRT's case, the startup script is so simple it essentially runs vsFTPD as if it were starting from the command line. This causes no issues, but is a bit counter intutive if one reads the vsFTPD documentation on the "listen" directive.

Below is a working configuration file;


# Remember to configure Firewall settings with equivalent values


# OpenWRT Oddity: Even though the vsFTPD Service / Daemon is started via an init.d script, it is a very simple script that essentially does the same thing as starting vsFTPD from the command line, so the following must be set to YES;

# Banner display does not appear to function in an modern web browser




# Equivalent to "Run As" Service / Daemon

# Set logged items go to the vsFTPD log instead of the system message log



# In OpenWRT, the default location is: userlist_file=/etc/vsftpd.user_list (this is very odd given that OpenWRT creates an /etc/vsftpd Directory)
# On other platforms, like CentOS, the default location is /etc/vsftpd/vsftpd.conf
# Do NOT create the list in anything other than VI or NANO (IE, don't use Windows Explorer, Directory Opus, etc. to create a new file) as there is an issue with Carriage Return / Line Feeds.
# Editing with TextPad later is fine as it seems to respect how the file was created in terms of using CR/LF VS just LF.

In the above working example, of course replace W.X.Y.Z with an appropriate IP Address. Astute readers will notice all the file names that might generally start have "vsftpd" in their names instead have "vsftpd1". The reason for that is because the above working configuration file was used in a situation where a router is configured with two WAN interfaces, with two IP Addresses on two different networks. See the section on Dual WAN vsFTPD for additional information.

The /etc/vsftpd1.user_list contains a list of users that will be allowed to login if the userlist_enable=YES and userlist_deny=NO settings are present.

NOTE 1: If any of the above referenced files (vsftpd1.user_list, etc.) are not present, the vsftpd service will start and appear to be functioning (PS, TOP, HTOP, etc. will all show it as running), but... There will be nothing displayed on client FTP software.

NOTE 2: Users and Groups can be managed by editing the /etc/passwd (User File) and /etc/group (Group File). If Webmin (see below) is installed and properly configured, Users & Groups can be managed through its interface. The useradd command can be added with: opkg install shadow-useradd

NOTE 3: Remember, OpenWRT also uses the /etc/shadow file to store user passwords with MD5 ($1) encryption.


Below are the pertienent settings for vsFTPD in the /etc/config/firewall file;

config rule
	option dest_port '20'
	option src 'wan'
	option name 'FTP_TCP_20'
	list dest_ip 'W.X.Y.Z'
	option target 'ACCEPT'
	option family 'ipv4'
	list proto 'tcp'

config rule
	option dest_port '21'
	option src 'wan'
	option name 'FTP_TCP_21'
	list dest_ip 'W.X.Y.Z'
	option target 'ACCEPT'
	option family 'ipv4'
	list proto 'tcp'

config rule
	option src 'wan'
	option name 'FTP_PASV'
	list dest_ip 'W.X.Y.Z'
	option target 'ACCEPT'
	option family 'ipv4'
	list proto 'tcp'
	option dest_port '10012:10021'

And as usual, substitute a functional IP Address for W.X.Y.Z. The above configuration includes settings necessary for Passive FTP (see here for an explanation) used by clients behind a firewall.

Internet Explorer Workaround

If one is using Internet Explorer's FTP capability, there will be an issue if userlist_enable=YES and userlist_deny=NO are set. Solution? Add the users 'anonymous' in the vsftpd.user_list file. Thanks to a top tip from a user named JAYCLEN here:

vsFTPD for a dual WAN router

According to documentation, the vsFTPD Service / Daemon can only "listen" on a single IP Address (listen_address=W.X.Y.Z). This also appears to apply to Passive FTP settings (pasv_address=W.X.Y.Z). There is a solution. Run multiple instances of vsFTPD. Easy to say, but a bit more complex to accomplish.

Because of the simplicity of the /etc/init.d/vsftpd startup script, it is not possible to use the same binary / executable File (/usr/sbin/vsftpd) for multiple vsFTPD instances. The solution is to create two symbolic links to the /usr/sbin/vsftpd binary / executable File. Be sure to set the permissions on the new startup script to 755: chmod 755 WhatEverScriptFileName (chmod 755 /etc/init.d/vsftpd)

  • ln -s /usr/sbin/vsftpd /usr/sbin/vsftpd1
  • ln -s /usr/sbin/vsftpd /usr/sbin/vsftpd2

This allows one to create two startup scripts in /etc/init.d for vsFTPD (vsftpd1 and vsftpd2) that contain the following (below is the vsftpd1 example);

#!/bin/sh /etc/rc.common
# Copyright (C) 2006-2011

# Remember: There are two symbolic links in /usr/sbin, vsftpd1 and vsftpd2, that point to /usr/sbin/vsftpd


start() {
	# /var/run/vsftpd is the secure_chroot_dir default value that vsFTPD requires to run
	# It can be shared amongst multiple instances of vsFTPD
	mkdir -m 0755 -p /var/run/vsftpd
	service_start /usr/sbin/vsftpd1 /etc/vsftpd1.conf

stop() {
	service_stop /usr/sbin/vsftpd1

For the other startup script (vsftpd2), copy and change the above references of vsftpd1 to vsftp2. Be sure to enable (service vsftpd1 enable AND service vsftpd2 enable) both scripts for automatic startup. The reason for needing the above symbolic links can be seen in the above init.d startup script. Specifically the "service_stop /usr/sbin/vsftpd" (minus the 1 or 2 naming convention). If there were two startup scripts using the same /usr/sbin/vsftpd reference, two instances could be started, but when stopping the service / daemon, weird things happen.

Make sure there are two configuration files for each vsFTPD service / daemon as they'll have some unique settings, like IP Addresses, etc.

Also make sure any additional files that are referenced (userlist_file=/etc/vsftpd1.user_list, etc) are duplicated (userlist_file=/etc/vsftpd2.user_list) for each service.

And finally, make sure the /etc/config/firewall file has the additional IP Address included. Simply insert an additional list dest_ip 'A.B.C.D' line after each list dest_ip 'W.X.Y.Z' line in the above firewall example (of course substitute A.B.C.D with an appropriate IP Address).


Download the module using WGET: wget

Install using the Webmin interface: Webmin, Webmin configuration, Webmin Modules, Install from, From local file

Available under: Server, vsftpd

Webmin configuration;


Also note that vsFTPD module has a behavior where it will add items that are left blank in the GUI interface as commented out configuration items in the /etc/vsftpd.conf file.

For multiple vsFTPD instances, Webmin allows for cloning modules. Remember to change the configuration file location if taking advantage of this feature.


  • If the configuration of vsFTPD includes the use of userlist_enable or userlist_deny, make sure that the /etc/vsftpd.user_list File is created with VI or NANO as opposed to a Windows utility through Samba. The reason is vsFTPD will not be able to read the file properly if it contains CR/LF (Carriage Return / Line Feeds).
  • If one reads any documentation about the CentOS (possible others) version of vsFTPD, there are references to using the included "user_list" file and a custom named version of the file. After some experimentation, it was determined that it may not work in the fashion noted for the OpenWRT version of vsFTPD as it does for other platforms. Feel free to experiment.
  • It is worth repeating this warning: If any of the files (/var/run/vsftpd, vsftpd1.user_list, etc.) referenced in a vsFTPD configuration file are not present, the vsftpd service will start and appear to be functioning (PS, TOP, HTOP, etc. will all show it as running), but... There will be nothing displayed on client FTP software.
  • If the background= setting is configured as background=NO (as one might do for troubleshooting), it will prevent a router from starting any services after vsFTPD. Since vsFTPD's "start order" is 50, any services after that will not start.
  • Several older forum postings and other web sites, as far back as 2007, make references to installing various additional pieces of software such as kmod-nf-ipvs-ftp along with other kernel modules. They are not necessary.
  • Remember, OpenWRT provides two different vsFTPD packages, one without FTPS capability (opkg install vsftpd) and one with FTPS capability (opkg install vsftpd-tls)

Notes & Questions

It seems very odd that the choice for FTP server that OpenWRT provides is vsFTPD as the latest version is half a decade old. Why not use something that still gets updated on a regular basis like ProFTPD? Perhaps the developers of OpenWRT are attempting to send a quiet message that FTP is not a good thing to use because it is not encrypted. But if that's the case, why not remove every FTP server package that doesn't contain SFTP (SSH FTP) or FTPS (SSL/TSL FTP) functionality?

Tips for Troubleshooting

As with anything related to computers, it can be difficult to figure out what is wrong with a configuration of a service and why it isn't working as expected. vsFTPD is no exception. To eliminate a potential issue, namely the firewall, consider configuring vsFTPD to listen on a LAN interface. This will eliminate problems related to PASV / Passive FTP issues. Also consider using a command line version of FTP as opposed to a browser version. Command line versions of FTP will often times display more error information than a web browser that has FTP capability.


TelnetD is supported (and works) on DD-WRT, but OpenWRT has essentially discontinued use of telnet in the name of security. It is possible to build a custom version of the OpenWRT firmware that supports telnetd (and telnet the client), but they've effectively made it very difficult (sad, but probably as it should be). The below section of the source configuration file for OpenWRT says it all;

Code Block
bool "telnetd"
  A daemon for the TELNET protocol, allowing you to log onto the host
  running the daemon. Please keep in mind that the TELNET protocol
  sends passwords in plain text. If you can't afford the space for an
  SSH daemon and you trust your network, you may say 'y' here. As a
  more secure alternative, you should seriously consider installing the
  very small Dropbear SSH daemon instead:

  Note that for busybox telnetd to work you need several things:
  First of all, your kernel needs:

  Next, you need a /dev/pts directory on your root filesystem:

          $ ls -ld /dev/pts
          drwxr-xr-x  2 root root 0 Sep 23 13:21 /dev/pts/

  Next you need the pseudo terminal master multiplexer /dev/ptmx:

          $ ls -la /dev/ptmx
          crw-rw-rw-  1 root tty 5, 2 Sep 23 13:55 /dev/ptmx

  Any /dev/ttyp[0-9]* files you may have can be removed.
  Next, you need to mount the devpts filesystem on /dev/pts using:

          mount -t devpts devpts /dev/pts

  You need to be sure that busybox has LOGIN and
  FEATURE_SUID enabled. And finally, you should make
  certain that Busybox has been installed setuid root:

        chown root.root /bin/busybox
        chmod 4755 /bin/busybox

  with all that done, telnetd _should_ work....

Finding a version of BusyBox that includes TelnetD will not suffice as there are additional items that need to be configured for it to work. However, a telnet client program seems appropriate. See the "signoff" on TELNET here: But there is an alternative (see the next section)


opkg update

opkg install netcat

Use as a Telnet Client: nc -T -v W.X.Y.Z (-T = Answer using telnet negotiation, -v = Verbose)

Instead of simply pressing the Enter Key in NETCAT, one must instead using the following key commands: CTRL+V, CTRL+M, ENTER (That equates to pressing the ENTER Key. OpenWRT's version of NETCAT in BusyBox does not include the -C switch which allows for easy "carriage returns")



Task Scheduling with Cron

Additional Information:



opkg install restic

To create a backup repository: restic init --repo "WhatEverRepositoryPath"

To make a backup: restic -r "WhatEverRepositoryPath" --verbose backup /WhatEverPathToBackUp

  • Example: restic -r "/mnt/sdb2/RESTIC/WRT3200ACM/" --verbose --tag "What Ever Note" backup /overlay

To view backups: restic -r "WhatEverRepositoryPath" snapshots

  • Example: restic -r "/mnt/sdb2/RESTIC/WRT3200ACM/" snapshots

To restore a backup: restic -r "WhatEverRepositoryPath" restore ID --target /WhatEverPathToRestoreTo (the ID can be obtained from the above "snapshots" command, the target does not have to be the original source, --verbose doesn't work)

Additional Information: (Note: In some of their examples a tilde ( ~ ) is used, which is a user's home directory)


Another program that functions as an effective cloning utility is dd (noted in an earlier section). Ideally an additional USB Flash drive should be used. Note, to utilize the full dd program, instead of the one built into BusyBox: opkg install corutils

  • dd if=/dev/sdXy of=/dev/sdXy bs=64K conv=noerror,sync status=progress (if = source, of = destination, bs=block size (IE amount to copy at a time), noerror=Don't stop on read errors, sync=If an error occurs use zeros or nuls to pad file, progress=show the progress)

To copy to a compressed file;

  • dd if=/dev/sdXy conv=sync,noerror bs=64K status=progress | gzip -c > /WhatEverPath/WhatEverFile.img.gz (-c=Do not change files)
  • Example: dd if=/dev/sdb1 conv=sync,noerror bs=64K status=progress | gzip -c > /mnt/sdb2/DD/EXT4a-9.20.2020.img.gz

Everything will be cloned, including the UUID of the partition. If the second flash drive is being used for the sole purpose of backing up settings, as opposed to replacing a bootable flash drive, then to prevent confusion with the source USB Flash Drive or Partition, change the UUID;

  • tune2fs -U random /dev/sdXy*


  • tune2fs -U UUID /dev/sdXy* (where UUID is the actual UUID)

To verify the change, use the following command;

  • blkid /dev/sdXy

In the above examples X and y should be replaced with actual mount point references. IE, sda1, sdb3, sde2, etc.

Border Mail System (Postfix, MailScanner, MailWatch, ClamD,


Files & Permissions

Configuration: /etc/postfix (that's a directory, not a file)

Startup Script: /etc/init.d/postfix

Main Binary / Executable Files: /usr/sbin/post*

Additional Binary / Executable Files: /usr/sbin/sendmail* (sendmail related compatibility)

Other Binary / Executalbe Files: /usr/bin/mailq, mailq.postfix, newaliaases, newaliases.postfix (sendmail related compatibility)

Library (sub-function) Files: /usr/libexec/postfix

There is no LuCI GUI or any sort of OpenWRT configuration paradigm. Everything can be configured via text files and all safely done with Webmin.

Postfix User and Group items are configured in /etc/passwd and /etc/group automatically.

Owner for /etc/postfix: root:root

Permissions for /etc/postfix: 644


  • postconf -d (configuration settings)
  • postmap /etc/postfix/transport (updates the transport.db file)
    • Note: Most linux distributions name the transport database file transport.db, but by default the OpenWRT version of Postfix names it transport.cdb
  • postfix reload (after changes are made to file, or just restart the service)


The below warning message(s) are displayed each time Postfix is started. This is because OpenWRT left the default setting smtputf8_enable = 0 when Postfix was compiled. The smtputf8_enable setting relates to other text encoding (UTF8), etc. According to documentation it creates a much larger binary / executable for Postfix. Since OpenWRT focuses on small and compact service files this makes sense. But the fix is easy. Add this line to the /etc/postfix/ file: smtputf8_enable = no

postfix: warning: smtputf8_enable is true, but EAI support is not compiled in
postsuper: warning: smtputf8_enable is true, but EAI support is not compiled in
postfix/postlog: warning: smtputf8_enable is true, but EAI support is not compiled in
postfix/postfix-script: starting the Postfix mail system


Download the latest version from: (The year this was written was 2020, so if they've moved onto v6, check the URL)

tar -xvzf WhatEverTheNameOfTheTarGzFile

The installation script ./ relies on the full BASH shell (OpenWRT includes the ASH shell by default): opkg install bash, then type the command bash ./ (plain ASH won't work, they even explicitly state the shebang of their file as #!/bin/bash, not #!/bin/sh, and just for the fun of it attempted to run it with ASH, and it errors out) Read here for more information or to change it permanently:


Webmin can be successfully installed on OpenWRT, AND IT IS USEFUL. The end of the previous sentence is in all CAPS and BOLD because of the large number websites and posts that do nothing more than question why anyone would want to install Webmin on OpenWRT instead of just answering the original question of how to install it. Sometimes it is just nice to have a GUI. The editor for config files alone is worth it.

There is however a word of caution to address: Do NOT use Webmin for any OpenWRT services that have an associated LuCI GUI or /etc/config/WhatEverConfigurationFile because modifications made by Webmin will be wiped out by changes made via LuCI or the /etc/config/Files... There are many, many services such as BIND / NAMED, Apache / HTTPD, ProFTPD, OpenSSL for OpenVPN Certificate generation that have no LuCI GUI, nor are they "controlled" or configured via the /etc/config/ Files. That means these services are safe to configure via text or by GUI.

Pre-Installation Tasks for Installing Webmin

Download the Webmin ...tar.gz file: wget

Unzip and UnTAR the file;

  • The location chosen when unzipping and untarring Webmin can be the installation directory where the program runs;
    • Typical installation locations for other Linux distributions (do NOT use the /tmp directory or it will be gone when the router reboots);
  • gunzip webmin-1.955.tar.gz and tar xvf webmin-1.955.tar


  • tar zxvf webmin-1.955.tar

(be patient, there are a LOT of files, even on a fast USB 3.0 flash drive it takes a couple of minutes.

  • If "untarred" a directory other than the installation, do one of the following;
    • Move the untarred directory to the desired location
    • When installing use the command (not yet): ./ /WhatEverPath
  • Before running the setup program;
    • Add the bin Group to /etc/group using this: bin:x:10000:
    • Make sure PERL is installed with necessary modules
      • opkg update
      • opkg install perl perlbase-http-tiny coreutils-stty perlbase-gdbm-file perlbase-extutils perlbase-storable
    • Possible Errors & Solutions during and after Installation;
      • "Perl Socket module not installed" Error will occur if perlbase-http-tiny is not installed.
      • "stty: not found" / "Login password: ./ line 396: stty: not found" (the line number may be different depending on the version of the setup script an Webmin being installed) Error will occur if coreutils-stty is not installed
      • "The Perl SSLeay library is not installed. SSL not available" Error will occur because the PERL SSLeay module is not available in OpenWRT
      • "Can't locate Time/ in" / "you may need to install the Time::Local module" will occur if the perlbase-time module is not installed
      • "No dbm on this machine at" error will occur if perlbase-gdbm-file
      • "Error - Perl execution failed  Undefined subroutine &main::get_miniserv_config called at /usr/local/webmin/authentic-theme/session_login.cgi line 17" and / or ""GET / HTTP/1.1" 500 166" (in miniserv.log file) error occurs if perlbase-storable is not installed
      • "Can't locate ExtUtils/ in @INC (you may need to install the ExtUtils::CBuilder module" error occurs if perlbase-extutils is not installed
      • " can't open '/var/log/webmin/': No such file or directory" error occurs when stopping Webmin with /etc/webmin/stop

A Special note on HTTPS (not the Module) for Webmin: Do NOT worry about it. Forget it. Almost impossible to get working.

During installation, Webmin states the Net::SSLeay Perl Module is necessary for HTTPS to work. If not, the Webmin site is only accessible via HTTP.

The instructions on the Webmin site for enabling this functionality are here (Hint: It won't work):

Here's why;

  • The Net::SSLeay Perl Module is not available in OpenWRT, nor is and trying to build said modules results the error "fatal error: EXTERN.h: No such file or directory". OpenWRT does not include some of the GCC files necessary. Several sites ( mention using an external cross compile computer as a method of solving the issue
  • Crypt::SSLeay is not available either, becuase there seems to be an issue ( with the Crypt-SSLeay-0.72.tar.gz version that is attempted to download during compile. But even the newer version ( doesn't work either. Downloading the newer version ( and changing the Makefile.PL line ( unless( require( catfile qw(inc IO Interactive ) ) { ) to ( unless( require( catfile qw(IO Interactive ) ) { ), to get rid of the inc corrects the issue. But then there's a "fatal error: openssl/opensslv.h" issue that is similar to the above mentioned Net:SSLeay issue where OpenWRT does not make certain Devel files available, in this case for OpenSSL, so the cross compiling method is the only solution available.
  • Some information suggests IO::Socket::SSL as an alternative (, but in order to build it, the Net:SSLeay Module is necessary, so that's a circular issue.

Installing Webmin

Run the setup and configuration questions during setup (Note: OpenWRT does not provide the NET::SSLeay Perl Module, so SSL will not be available for Webmin);

  • Detailed instructions to install "The Old Fashion Way..." can be found here:
  • In chosen Webmin installation directory, run: ./ /WhatEverPathToInstallWebmin (see above for potential locations)
    • Config Directory: /etc/webmin
    • Log file directory: /var/log/webmin (NOTE: This directory is actually a symbolic link for /tmp, so it will not persist across reboots of a router. If permanent logs for Webmin are desired, change the path)
    • Full path to perl: /usr/bin/perl
    • MiniServe Configuration (the web process for webmin): /etc/webmin/miniserv.conf
    • Configure OS as: 110 - Generic Linux
      • OS Choices available when installing Webmin: Pick 110) Geric Linux for OpenWRT;
  1) Pardus Linux           2) SmartOS                3) Sun Solaris          
  4) Lycoris Desktop/LX     5) Caldera OpenLinux eS   6) Caldera OpenLinux    
  7) Asianux Server         8) Asianux                9) Whitebox Linux       
 10) Tao Linux             11) CentOS Linux          12) Springdale Linux     
 13) Virtuozzo Linux       14) Scientific Linux      15) Gralinux             
 16) NeoShine Linux        17) Endian Firewall Linu  18) Oracle Enterprise Li 
 19) Oracle Linux          20) Oracle VM             21) XenServer Linux      
 22) CloudLinux            23) MostlyLinux           24) Cloudrouter Linux    
 25) Sangoma Linux         26) Citrix Hypervisor     27) Redhat Enterprise Li 
 28) Redhat Linux Desktop  29) AlphaCore Linux       30) X/OS Linux           
 31) Haansoft Linux        32) cAos Linux            33) Wind River Linux     
 34) Amazon Linux          35) Redhat Linux          36) Fedora Linux         
 37) White Dwarf Linux     38) Slamd64 Linux         39) Slackware Linux      
 40) Xandros Linux         41) APLINUX               42) BigBlock             
 43) Ubuntu Linux          44) Mepis Linux           45) Devuan Linux         
 46) Raspbian Linux        47) Linux Mint            48) Debian Linux         
 49) SuSE OpenExchange Li  50) SuSE SLES Linux       51) SuSE Linux           
 52) United Linux          53) Corel Linux           54) TurboLinux           
 55) Cobalt Linux          56) Mandrake Linux Corpo  57) pclinuxos Linux      
 58) Mageia Linux          59) Mandrake Linux        60) Mandriva Linux       
 61) Mandriva Linux Enter  62) Conectiva Linux       63) ThizLinux Desktop    
 64) ThizServer            65) MSC Linux             66) SCI Linux            
 67) LinuxPPC              68) Trustix SE            69) Trustix              
 70) Tawie Server Linux    71) TinySofa Linux        72) Cendio LBS Linux     
 73) Ute Linux             74) Lanthan Linux         75) Yellow Dog Linux     
 76) Corvus Latinux        77) Immunix Linux         78) Gentoo Linux         
 79) Secure Linux          80) OpenNA Linux          81) SoL Linux            
 82) Coherent Technology   83) Playstation Linux     84) StartCom Linux       
 85) Yoper Linux           86) Caixa Magica          87) openmamba Linux      
 88) FreeBSD               89) DragonFly BSD         90) OpenBSD              
 91) NetBSD                92) BSDI                  93) HP/UX                
 94) SGI Irix              95) DEC/Compaq OSF/1      96) IBM AIX              
 97) SCO UnixWare          98) SCO OpenServer        99) macOS Catalina       
 100) macOS Mojave          101) macOS High Sierra     102) macOS Sierra         
 103) OS X                  104) Mac OS X              105) Darwin               
 106) OpenDarwin            107) Cygwin                108) Sun Java Desktop Sys 
 109) Synology DSM          110) Generic Linux         111) Windows
  • Version: 4

The running Webmin service when viewed by PS or equivalent: {} /usr/bin/perl /usr/local/webmin/ /etc/webmin/miniserv.conf

Post Installation

Webmin seems to have an issue detecting ARM CPUs in the Marvell SoC with OpenWRT. This results in an Error 500 Perl execution failed... ...proc::list_processes. To correct the issue modify the /overlay/webmin/proc/ File as follows (It disables the Webmin Processor Module because that module does not run correctly on OpenWRT for the AC Series of routers) by removing the generic-linux or *-linux setting;

Original Line: os_support=solaris generic-linux hpux freebsd osf1 irix unixware openserver macos aix netbsd openbsd windows


Original Line: os_support=solaris *-linux hpux freebsd osf1 irix unixware openserver macos aix netbsd openbsd windows

Modified Line: os_support=solaris hpux freebsd osf1 irix unixware openserver macos aix netbsd openbsd windows

Verify the /etc/webmin/config file contains the following settings;


Alternative Method of Configuring Webmin settings in /etc/webmin/config file;


...however, this necessitates that any Webmin modules that require certain operating systems (apache, bind, etc.) need to have their files modified to include the os_type of linux.

And again, the /overlay/webmin/proc/ will need to be modified as above.

Also, most of the Webmin modules will need to be custom configured for the OpenWRT environment in order to function properly. See below...

Adding and Configuring Webmin Features & Modules

Before any modules are moved from the Unused-Modules Category, they must be properly configured for Webmin to detect.

Date and Time

The LuCI GUI does not provide a method to manually change the date or time (see The reason appears to be that the AC Series of routers, among many other router models, lacks the hardware capability to maintain an internal clock when the router is off or unplugged. Instead, it syncronizes with a known NTP (Network Time Protocol) server after booting up. This seems to be confirmed, in that during booting, part of the boot process is to set the clock to midnight January 1, 1970 (see

Once booted, the the Webmin interface provides a relatively easy method to configure the date and time when the module is properly configured properly. In the default Webmin Dashboard, Time on System;

  • CLOCK, Settings Icon (the gear at the top left of the configuration payne), System configuration, System time setting format, YYYYMMDDHHMM.SS Radio Button


  • /etc/webmin/config: dateformat=dd/mon/yyyy

Remember, the modified time will not persist across reboots. The setting for the format in Webmin will persist, but the AC series of routers, as most others, does not maintain an internal clock when off or unplugged. The time is set by accessing an NTP server when the router boots up.

Users and Groups

System, Users and Groups, Settings;

Password File (User & Password File): /etc/passwd (/etc/passwd- seems to be the OpenWRT template file for passwd)

Group file: /etc/group

Webmin Performance

To decrease the Webmin CPU load on the OpenWRT router (this isn't really necessary for the AC router series as there is "horsepower" to spare);

  • Disable Real-Time Monitoring: Webmin, Webmin Configuration, Themes, Real-time monitoring options, Enable real-time monitoring, NO
  • Reduce Real-Time Monitoring Refresh: Interval for performing update, 10000 (Increasing the default value of 1000 (ms) will also cause delays in information in certain categories, such as Network I/O to be displayed slowly)

Other Notes for Webmin

Some modules, such as NAMED / BIND, may not accurately show the Stop / Start status after a stop or start until after a screen refresh, which is possibly related to the Monitoring Refresh time mentioned above, if increased.

Apache / Apache2 / HTTPD Webmin Module (/etc/webmin/apache/config)

Code Block
apply_cmd=/etc/init.d/apache2 restart
stop_cmd=/etc/init.d/apache2 stop
start_cmd=/etc/init.d/apache2 start
graceful_cmd=/etc/init.d/apache2 reload

BIND / BIND8 / NAMED Webmin Module (/etc/webmin/bind8/config);

The below Code Block contains the settings to customize the Webmin interface for BIND / NAMED;

Code Block
restart_cmd=/etc/init.d/named reload
start_cmd=/etc/init.d/named start
stop_cmd=/etc/init.d/named stop

Sadly, for the BIND / NAMED module, it didn't seem that OpenWRT included the named-compilezone command. However, after some quick research with a major hint (from here: which included a notation that the named-compilezone command was a symbolic link, then a quick check on a CentOS system which showed the /usr/sbin/named-compilezone pointing to /usr/sbin/named-checkzone, which confirmed the utility as a standalone file does NOT exist, but is simply a softlink to another file. The solution is to add this line to the rc.local file: ln /usr/sbin/named-checkzone /usr/sbin/named-compilezone That way the command is available to Webmin.

PPTP VPN Server Webmin Module (AKA PPTPD / POPTOP)

This module can be used for everything except the PPP Accounts (It can be used, but any changes will not persist across router reboots). The reason is that the /etc/ppp/chap-secrets file (actually a symbolic link to /tmp/etc/chap-secrets) that it accesses is dynamically configured by the /etc/init.d/pptpd startup script based on information in the /etc/config/pptpd file. The Webmin module can be used to view the information, but as noted, do NOT use it to modify user names and passwords for PPTPD. Instead change user names and passwords in the /etc/config/pptpd file.

As noted above in the PPTPD section, OpenWRT does not support the require-mppe-128 option in the /etc/ppp/options.pptpd file. Webmin will insert that value if the "Use 128-bit MPPE encryption?" is set to "Must be used" and that will "break" PPTPD. Leave it set to Default (Allowed). It should also be noted that the mppe-128 is built into the OpenWRT /usr/sbin/pptpd binary / executable file, thus making the setting unneccessary as it is enabled by default (pptp-server.log if enabled shows this: MPPE 128-bit stateless compression enabled).

Below are settings for the PPTPD Module (etc/webmin/pptp-server/config);

start_cmd=/etc/init.d/pptpd start
stop_cmd=/etc/init.d/pptpd stop

The Active Connections feature also appears to be broken for the same reason Webmin can't show processor information with the PROC module. It results in an error of: HTTP/1.0 500 Perl execution failed Server: MiniServ/1.955 Content-type: text/html; Charset=utf-8 Connection: close. Error - Perl execution failed, Undefined subroutine &proc::list_processes called at ./

DHCPD Webmin Module (/etc/webmin/dhcpd/config)

As noted in the main DHCPC section, there is no LuCI GUI, nor is there any good reason to stay within the OpenWRT managment paradigm (at least for DHCPD). Unlike some other instances like Samba Server where it makes sense to maintain the "OpenWRT management style" of services, with DHCPD every aspect of Webmin can be utilized. Below are the configuration settings for the DHCPD Webmin Module;

start_cmd=/etc/init.d/dhcpd start
stop_cmd=/etc/init.d/dhcpd stop
restart_cmd=/etc/init.d/dhcpd reload

Items such as dhcpd_version can be modified to reflect whatever version of DHCPD is available in the future. No modifications need to be made to the /overlay/webmin/dhcpd/ (assuming the root path of Webmin is /overlay) file as this Module seems to be compatible with every version of DHCPD on every Linux distribution.

Samba Server Webmin Module (/etc/webmin/samba/config)

First, if it hasn't already been stated, a LuCI GUI (Services, Network Shares) for Samba exists. AND it makes sense to stay within the OpenWRT management / configuration paradigm for services (/etc/config/samba3 or samba4). Having noted that, the LuCI GUI does not have all the bells and whistles of Webmin, but what is there looks a whole lot better. So for this one, a hybrid approach is best.

Making so Webmin recognizes the Samba Module as an active module requires editing the /overlay/webmin/samba/module file (assuming /overlay is the root of the Wemin installation path chosen). For some reason the wildcard version of Linux (*-linux) setting is not respected with OpenWRT / Webmin. That makes it necessary to add the full name of the os_type setting in the /etc/webmin/config file (which should be generic_linux) into the /overlay/webmin/samba/module file os_support setting. See below;

  • Original line: os_support=solaris *-linux aix hpux freebsd osf1 irix openserver unixware openbsd macos netbsd
  • New line: os_support=solaris generic-linux *-linux aix hpux freebsd osf1 irix openserver unixware openbsd macos netbsd

The below configuration for the Samba Webmin Module allows for management of Samba features not included in the LuCI GUI. The Webmin GUI for Samba also provides a path to overstep what should be configured with Samba via Webmin, so use the "restraint" items noted below the configuration section;

list_printers_command=lpc status | grep "[A-z0-9]:" | sed -e 's/://g'
stop_cmd=/etc/init.d/samba4 stop
start_cmd=/etc/init.d/samba4 start
restart_cmd=/etc/init.d/samba4 restart

Notice a key item in the above configuration settings: smb_conf=/etc/samba/smb.conf.template (NOT smb.conf). This is the key in allowing the Samba Webmin Module to control many Webmin settings. The down side of this is that none of the shared resources will be displayed. But that's OK, because the LuCI GUI interface does display shared resources. Plus any changes made with the Samba Webmin Module would not be persistent and would be overwritten each time the Samba service or router is restarted.

The general rule of what NOT to configure within Webmin is as follows;

  • If it can be configured within the LuCI GUI interface, do NOT configure it with Webmin.
  • If there is an item / setting within the /etc/samba/smb.conf.template of visible within Webmin that is deliniated with a leading and trailing pipe symbol ( | ), do NOT configure it with Webmin.
  • If the Webmin Module is configured correctly with the /etc/samba/smb.conf.template file as the configuration file, not the /etc/samba/smb.conf file, then configuration of shared resources (directories, printers, etc) will not be an issue as they will not be available within the Webmin interface for configuration.

Additional information can be found here: It also illustrates the limits of the what the LuCI GUI interface can and can't do. And it demonstrates at which point editing of the smb.conf.template via a text editor (available within the LuCI GUI on the Edit Template Tab) or in this case Webmin is necessary.

Postfix Server Webmin Module (/etc/webmin/postfix/config)

There is no OpenWRT LuCI GUI interface for Postfix. Nor is there any sort of OpenWRT service managment paradigm implimented in /etc/config for Postfix as there is for many other services. That means it is 100% OK to administer with Webmin with no limitations or fear of interfering with anything else. PERIOD

Below are the configuration settings for the Webmin Postfix Module;

mailq_cmd=/usr/sbin/postqueue -p
reload_cmd=/etc/init.d/postfix reload
stop_cmd=/etc/init.d/postfix stop
start_cmd=/etc/init.d/postfix start

Third Party Modules (OpenVPN Certificate Authority, not OpenVPN itself as that is configured via LuCI or /etc/config, etc)

Install via the Webmin GUI and remember to configure the file if necessary and settings

OpenVPN (/etc/webmin/openvpn/config);

Code Block
status_cmd=systemctl status openvpn@%s
start_cmd=/etc/init.d/openvpn start
stop_cmd=/etc/init.d/openvpn stop openvpn@%s

Starting and Stopping Webmin

Start: /etc/webmin/start

Stop: /etc/webmin/stop

Additonally, /etc/webmin/start can be added to the /etc/rc.local file to automatically start Webmin at boot.

A service can even be created in /etc/init.d/webmin with the following code;

#!/bin/sh /etc/rc.common


reload() {

restart() {

start() {
        mkdir -p -m 0750 /var/log/apache2

stop() {


Startup Scripts


LuCI, System, Startup, Local Startup

Some useful startup items;

# In order to make the named-compilezone command work for webmin, add the following line (research indicated it was a symbolic link)
ln /usr/sbin/named-checkzone /usr/sbin/named-compilezone

# Create a TEMP Folder for phpMyAdmin
mkdir /tmp/phpMyAdmin
chmod 777 /tmp/phpMyAdmin

# If it is desirable to have the non-active Flash Memory RootFS2 partition available on a WRT3200ACM, then do the following;
#ubiattach -m 8
#mkdir /mnt/MTD8
#mount -t ubifs /dev/ubi2_1 /mnt/MTD8

# If an external drive is used as the overlay, the mtb9 / syscfg partition is attached and mounted by default as /tmp/syscfg as UBI1, so these commands aren't needed, but achieve the same result.  This appears to be a minor flaw in the OpenWRT boot process.;
#ubiattach -m 9
#mkdir /tmp/MTD9
#mount -t ubifs /dev/ubi1_0 /tmp/MTD9

# Webmin Related
# Added as a SERVICE, so not needed
#mkdir /tmp/log/webmin

# OpenWRT puts the Apache directory in an unusual location for those with a CentOS / RedHat background.  Instead of modifying all of the default
# locations, it is easier to set up a softlink to the more familiar CentOS locations.  Remember, VAR redirects to TMP, hence the mkdir /tmp/www instead
# of mkdir /var/www
mkdir /tmp/www
ln -s /usr/share/apache2/htdocs /var/www/html
ln -s /usr/share/apache2/cgi-bin /var/www/cgi-bin
ln -s /usr/share/apache2/error /var/www/error
ln -s /usr/share/apache2/icons /var/www/icons

Console Connectivity

Console connectivity on the AC Series of routers can be made via a 6 pin JST-PH 2.0 electrical connector (2.0 refers to the 'pitch' or space between the pins, not a version number) that provides a port with serial communication capability.

Unlike many models of routers that require a similar connector be soldered to a circuit board, the AC Series of routers has this feature installed during manufacturing. Even though the cost is quite small per unit, it can add up to a significant amount of money with a large production run. This implies Linksys was anticipating the router would be used by a modding community. So thank you to the Linksys engineers and management that made sure that feature was included with the router. On the cynical "bean counter" side of things, including a feature which makes it easier to salvage a "bricked" router, also probably cuts down on the number customers attempting to return "failed" units to Linksys.

Serial Ports and TTL Serial Communication

Even thought this port provides serial communication, it should not be confused with a Serial Port (DE-9, AKA DB-9 or DB9) as found on older personal computer or with a USB to Serial Port adapter. A Serial Port on a computer utilizes the RS-232standard for communication. The port on the AC Series of routers uses a similar single-ended signaling method, but with lower voltages (typically 3.3 V - 5.0 V VS voltages up to 15 V for RS-232) often referred to as a TTL or more accurately as a TTL Serial Port or Port using TTL Serial Communication. Many SOC (System on a Chip) and MCU (MicroController Unit) systems besides Linksys use TTL Serial ports as a method of communication and control.

CAUTION: If one connects an RS-232 Serial Port directly to a "TTL Serial Port", at best gibberish will be displayed by whatever terminal / serial console software is being used (PuTTY, SecureCRT, Windows HyperTerminal, etc.). At worst, the higher voltage may permananently damage electronic components on the router's circuit board, rendering it unusable.

Connection with a PC

There are several methods of connecting a PC (Windows, Linux, etc.) to an AC Series router. The simplest of which is a USB to TTL Adapater (originally created by FTDI). USB Adapters typically have a Fanout Pigtail (a term often used when referring to Fiber Optic cables) which allows individual connections to pins on a circuit board port as there is no standard ordering of pins of a TTL Port between manufacturers. Another method utilizes a Serial to TTL Adapter which will likely include a MAX232 (or descendant) IC.

The COM port settings are as follows;

  • 115200 bits per second
  • Data bits: 8
  • Parity: None
  • Stop bits: 1
  • Flow Control: None

The Real Pin # 1

Many website tutorials, YouTube videos, diagrams, and even images on the OpenWRT website show the TTL Serial Port for the AC series of routers numbered from left to right, starting with "pin 1", as viewed from the top / front of the circuit board. This is NOT correct, although both the names / labels of the pins and what their function is (Ground, TX (Transmit), and RX (Receive)), are correct. It is an industry standard to identify "Pin 1" on a circuit board in several manners. The most common methods includes a triangle printed on the circuit board closest to "Pin 1" and a square solder connection (as viewed from the bottom). Another convention that is typically followed, but is not an absolute rule, is putting "Pin 1" closest to the nearest edge of a circuit board. The AC Series of routers all have a square solder connection on the bottom and a triangle printed on top of the circuit board for "Pin 1" on the right side of the connector, as viewed from the top. Since there is no pinout standard for that type of connector, the manufacturer (Linksys in this case) gets to define where "Pin 1" is located.

Additional Information

OpenWRT article for WRT3200ACM that applies to other models too:

For a detailed explanation of Serial Ports:

JST Connector Specifications:

Various comparisons between RS-232 and TTL:

A general tuturial on configuring connectivity with an AC Series router:


One question that has never been precisely determined is this: Which version of Linux is OpenWRT based on? Yes, it is known that the Linksys WRT54G started it all, but what version of Linux in the all the different distributions and branches is OpenWRT based on? OpenWRT is on the chart at the bottom, but no lines are drawn to it.

Perhaps a better question would be: What did Linksys use way back in the early noughties as the basis of their OS for the WRT54G?

Here are some of the first discussions on the subject;

One aptly named project that preceeds the WRT54G and OpenWRT is this:

The Linux distribution that would seem to be the most modern descendant and perhaps relative of OpenWRT is Alpine Linux.