liminix

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

tutorial.adoc (12526B)


      1 == Tutorial
      2 
      3 Liminix is very configurable, which can make it initially quite daunting
      4 - especially if you're learning Nix or Linux or networking concepts at
      5 the same time. In this section we build some "worked example" Liminix
      6 images to introduce the concepts. If you follow the examples exactly,
      7 they should work. If you change things as you go along, they may work
      8 differently or not at all, but the experience should be educational
      9 either way.
     10 
     11 === Requirements
     12 
     13 You will need a reasonably powerful computer running Nix. Target devices
     14 for Liminix are unlikely to have the CPU power and disk space to be able
     15 to build it in situ, so the build process is based around
     16 "cross-compilation" from another computer. The build machine can be any
     17 reasonably powerful desktop/laptop/server PC running NixOS. Standalone
     18 Nixpkgs installations on other Linux distributions - or on MacOS, or
     19 even in a Docker container - also ought to work but are untested.
     20 
     21 === Running in Qemu
     22 
     23 You can try out Liminix without even having a router to play with. Clone
     24 the Liminix git repository and change into its directory
     25 
     26 [source,console]
     27 ----
     28 git clone https://gti.telent.net/dan/liminix
     29 cd liminix
     30 ----
     31 
     32 Now build Liminix
     33 
     34 [source,console]
     35 ----
     36 nix-build -I liminix-config=./examples/hello-from-qemu.nix \
     37  --arg device "import ./devices/qemu" -A outputs.default
     38 ----
     39 
     40 In this command `+liminix-config+` points to the desired software
     41 configuration (e.g. services, users, filesystem, secrets) and `+device+`
     42 describes the hardware (or emulated hardware) to run it on.
     43 `+outputs.default+` tells Liminix that we want the default image output
     44 for flashing to the device: for the Qemu "hardware" it's an alias for
     45 `+outputs.vmbuild+`, which creates a directory containing a root
     46 filesystem image and a kernel.
     47 
     48 [TIP]
     49 ====
     50 The first time you run this it may take several hours, because it builds
     51 all of the dependencies including a full MIPS gcc and library toolchain.
     52 Once those intermediate build products are in the nix store, subsequent
     53 builds will be much faster - practically instant, if nothing has
     54 changed.
     55 ====
     56 
     57 Now you can try it:
     58 
     59 [source,console]
     60 ----
     61 ./result/run.sh
     62 ----
     63 
     64 This starts the Qemu emulator with a bunch of useful options, to run the
     65 Liminix configuration you just built. It connects the emulated device's
     66 serial console and the
     67 https://www.qemu.org/docs/master/system/monitor.html[QEMU monitor] to
     68 stdin/stdout.
     69 
     70 You should now see Linux boot messages and after a few seconds be
     71 presented with a root shell prompt. You can run commands to look at the
     72 filesystem, see what processes are running, view log messages (in
     73 :file:/run/log/current), etc. To kill the emulator, press ^P (Control P)
     74 then c to enter the "QEMU Monitor", then type `+quit+` at the `+(qemu)+`
     75 prompt.
     76 
     77 To see that it's running network services we need to connect to its
     78 emulated network. Start the machine again, if you had stopped it, and
     79 open up a second terminal on your build machine. We're going to run
     80 another virtual machine attached to the virtual network, which will
     81 request an IP address from our Liminix system and give you a shell you
     82 can run ssh from.
     83 
     84 We use https://www.system-rescue.org/[System Rescue] in tty mode (no
     85 graphical output) for this example, but if you have some other favourite
     86 Linux Live CD ISO - or, for that matter, any other OS image that QEMU
     87 can boot - adjust the command to suit.
     88 
     89 Download the System Rescue ISO:
     90 
     91 [source,console]
     92 ----
     93 curl https://fastly-cdn.system-rescue.org/releases/10.01/systemrescue-10.01-amd64.iso -O
     94 ----
     95 
     96 and run it
     97 
     98 [source,console]
     99 ----
    100 nix-shell -p qemu --run " \
    101 qemu-system-x86_64 \
    102 -echr 16 \
    103 -m 1024 \
    104 -cdrom systemrescue-10.01-amd64.iso \
    105 -netdev socket,mcast=230.0.0.1:1235,localaddr=127.0.0.1,id=lan \
    106 -device virtio-net,disable-legacy=on,disable-modern=off,netdev=lan,mac=ba:ad:3d:ea:21:01 \
    107 -display none -serial mon:stdio"
    108 ----
    109 
    110 System Rescue displays a boot menu at which you should select the
    111 "serial console" option, then after a few moments it boots to a root
    112 prompt. You can now try things out:
    113 
    114 * run `+ip a+` and see that it's been allocated an IP address in the
    115 range 10.3.0.0/16.
    116 * run `+ping 10.3.0.1+` to see that the Liminix VM responds
    117 * run `+ssh root@10.3.0.1+` to try logging into it.
    118 
    119 Congratulations! You have installed your first Liminix system - albeit
    120 it has no practical use and it's not even real. The next step is to try
    121 running it on hardware.
    122 
    123 === Installing on hardware
    124 
    125 For the next example, we're going to install onto an actual hardware
    126 device. These steps have been tested using a GL.iNet GL-MT300A, which
    127 has been chosen for the purpose because it's cheap and easy to unbrick
    128 if necessary.
    129 
    130 [WARNING]
    131 ====
    132 There is always a risk of rendering your device unbootable by flashing
    133 it with an image that doesn't work. The GL-MT300A has a builtin
    134 "debrick" procedure in the boot monitor and is also comparatively simple
    135 to attach serial cables to (soldering not required), so it is lower-risk
    136 than some devices. Using some other Liminix-supported MIPS hardware
    137 device also _ought_ to work here, but you accept the slightly greater
    138 bricking risk if it doesn't.
    139 
    140 See <<_supported_hardware>> for device support status.
    141 ====
    142 
    143 You may want to read and inwardly digest the section on <<serial>>
    144 when you start working with Liminix on real hardware. You
    145 won't _need_ serial access for this example, assuming it works, but it
    146 allows you to see the boot monitor and kernel messages, and to login
    147 directly to the device if for some reason it doesn't bring its network
    148 up.
    149 
    150 Now we can build Liminix. Although we could use the same example
    151 configuration as we did for Qemu, you might not want to plug a DHCP
    152 server into your working LAN because it will compete with the real DHCP
    153 service. So we're going to use a different configuration with a DHCP
    154 client: this is `+examples/hello-from-mt300.nix+`
    155 
    156 It's instructive to compare the two configurations:
    157 
    158 [source,console]
    159 ----
    160 diff -u examples/hello-from-qemu.nix examples/hello-from-mt300.nix
    161 ----
    162 
    163 You'll see a new `+boot.tftp+` stanza which you can ignore,
    164 `+services.dns+` has been removed, and the static IP address allocation
    165 has been replaced by a `+dhcp.client+` service.
    166 
    167 [source,console]
    168 ----
    169 nix-build -I liminix-config=./examples/hello-from-mt300.nix \
    170  --arg device "import ./devices/gl-mt300a" -A outputs.default
    171 ----
    172 
    173 [TIP]
    174 ====
    175 The first time you run this it may take several hours. Again? Yes, even
    176 if you ran the previous example. Qemu is set up as a big-endian system
    177 whereas the MediaTek SoC on this device is little-endian - so it
    178 requires building all of the dependencies including an entirely
    179 different MIPS gcc and library toolchain to the other one.
    180 ====
    181 
    182 This time in `+result/+` you will see a bunch of files. Most of them you
    183 can ignore for the moment, but `+result/firmware.bin+` is the firmware
    184 image you can flash.
    185 
    186 ==== Flashing
    187 
    188 Again, there are a number of different ways you could do this: using
    189 TFTP with a serial cable, through the stock firmware's web UI, or using
    190 the https://docs.gl-inet.com/router/en/3/tutorials/debrick/[vendor's
    191 "debrick" process]. The last of these options has a lot to recommend it
    192 for a first attempt:
    193 
    194 * it works no matter what firmware is currently installed
    195 * it doesn't require plugging a router into the same network as your
    196 build system and potentially messing up your actual upstream
    197 * no need to open the device and add cables
    198 
    199 You can read detailed instructions on the vendor site, but the short
    200 version is:
    201 
    202 [arabic]
    203 . turn the device off
    204 . connect it by ethernet cable to a computer
    205 . configure the computer to have static ip address 192.168.1.10
    206 . while holding down the Reset button, turn the device on
    207 . after about five seconds you can release the Reset button
    208 . visit http://192.168.1.1/ using a web browser on the connected
    209 computer
    210 . click on "Browse" and choose `+result/firmware.bin+`
    211 . click on "Update firmware"
    212 . wait a minute or so while it updates.
    213 
    214 There's no feedback from the web interface when the flashing is
    215 finished, but what should happen is that the router reboots and starts
    216 running Liminix. Now you need to figure out what address it got from
    217 DHCP - e.g. by checking the DHCP server logs, or maybe by pinging
    218 `+hello.lan+` or something. Once you've found it on the network you can
    219 ping it and ssh to it just like you did the Qemu example, but this time
    220 for real.
    221 
    222 [WARNING]
    223 ====
    224 Do not leave the default root password in place on any device exposed to
    225 the internet! Although it has no writable storage and no default route,
    226 a motivated attacker with some imagination could probably still do
    227 something awful using it.
    228 ====
    229 
    230 Congratulations Part II! You have installed your first Liminix system on
    231 actual hardware - albeit that it _still_ has no practical use.
    232 
    233 Exercise for the reader: change the default password by editing
    234 `+examples/hello-from-mt300.nix+`, and then create and upload a new
    235 image that has it set to something less hopeless.
    236 
    237 === Routing
    238 
    239 The third example `+examples/demo.nix+` is a fully-functional home "WiFi
    240 router" - although you will have to edit it a bit before it will
    241 actually work for you. Copy `+examples/demo.nix+` to `+my-router.nix+`
    242 (or other name of your choice) and open it in your favourite text
    243 editor. Everywhere that the text `+EDIT+` appears is either a place you
    244 probably want to change or a place you almost certainly need to change.
    245 
    246 There's a lot going on in this configuration:
    247 
    248 * it provides a wireless access point using the `+hostapd+` service: in
    249 this stanza you can change the ssid, the channel, the passphrase etc.
    250 * the wireless lan and wired lan are bridged together with the
    251 `+bridge+` service, so that your wired and wireless clients appear to be
    252 on the same network.
    253 
    254 [TIP]
    255 ====
    256 If you were using a hardware device that provides both 2.4GHz and 5GHz
    257 wifi, you'd probably find that it has two wireless devices (often called
    258 wlan0 and wlan1). In Liminix we handle this by running two `+hostapd+`
    259 services, and adding both of them to the network bridge along with the
    260 wired lan. (You can see an example in `+examples/rotuer.nix+`)
    261 ====
    262 
    263 * we use the combination DNS and DHCP daemon provided by the `+dnsmasq+`
    264 service, which you can configure
    265 * the upstream network is "PPP over Ethernet", provided by the `+pppoe+`
    266 service. Assuming that your ISP uses this standard, they will have
    267 provided you with a PPP username and password (sometimes this will be
    268 listed as "PAP" or "CHAP") which you can edit into the configuration
    269 * this example supports the
    270 newfootnote:[https://datatracker.ietf.org/doc/html/rfc1883[RFC1883
    271 Internet Protocol&#44; Version 6] was published in 1995, so only "new"
    272 when Bill Clinton was US President] Internet Protocol v6 as well as
    273 traditional IPv4. Configuring IPv6 seems to vary from one ISP to the
    274 next: this example expects them to be providing IP address allocation
    275 and "prefix delegation" using DHCP6.
    276 
    277 Build it using the same method as the previous example
    278 
    279 [source,console]
    280 ----
    281 nix-build -I liminix-config=./my-router.nix \
    282  --arg device "import ./devices/gl-mt300a" -A outputs.default
    283 ----
    284 
    285 and then you can flash it to the device.
    286 
    287 ==== Bonus: in-place updates
    288 
    289 This configuration uses a writable filesystem (see the line
    290 `+rootfsType = "jffs2"+`), which means that once you've flashed it for
    291 the first time, you can make further updates over SSH onto the running
    292 router. To try this, make a small change (I'd suggest changing the
    293 hostname) and then run
    294 
    295 [source,console]
    296 ----
    297 nix-build  -I liminix-config=./my-router.nix \
    298   --arg device "import ./devices/gl-ar750" \
    299   -A outputs.systemConfiguration && \
    300 result/install.sh root@address-of-the-device 
    301 ----
    302 
    303 (This requires the device to be network-accessible from your build
    304 machine, which for a test/demo system might involve a second network
    305 device in your build system - USB ethernet adapters are cheap - or a bit
    306 of messing around unplugging cables.)
    307 
    308 For more information about in-place-updates, see the manual section
    309 `+Rebuilding the system+`.
    310 
    311 === Final thoughts
    312 
    313 * These are demonstration configs for pedagogical purposes. If you'd
    314 like to see some more realistic uses of Liminix,
    315 `+examples/rotuer,arhcive,extneder.nix+` are based on some actual real
    316 hosts in my home network.
    317 * The technique used here for flashing was chosen mostly because it
    318 doesn't need much infrastructure/tooling, but it is a bit of a faff
    319 (requires physical access, vendor specific). There are slicker ways to
    320 do it that need a bit more setup - we'll talk about that later as well.
    321 
    322 *Footnotes*