--- title: MMDVM D-STAR hotspot on Archlinux summary: I wrote down the installation of a forked DStarGateway with a slim dashboard based on Javascript on a Raspberry Pi 2. date: 2024-01-29T13:01:26+0100 #lastmod: categories: - amateur-radio tags: - archlinux - dstar - hotspot - linux - mmdvm - raspberry-pi # showBreadcrumbs: true # showDate: false # showReadingTime: false # showWordCount: false # showPagination: false # feed_exclude: true # site_exclude: true # some help # # highlighting with highlights # # use table, as inline creates a padding around # and it pushes the text more to the right side (end of screen) # # ~~~html {linenos=table,hl_lines="3-6"} # ~~~html {linenos=inline,hl_lines="1,3-6"} draft: true --- ## Installation of Archlinux I usually setup any Raspberry Pi without screen and keyboard but I make use of the [serial console](https://www.raspberrypi.com/documentation/computers/configuration.html#configuring-uarts). This procedure is taken from [archlinuxarm.org](https://archlinuxarm.org/platforms/armv7/broadcom/raspberry-pi-2) -- it is shown with more details there. ![Raspi 2 with wires connected to GPIO Pins GND, RXD and TXD](setup_console.jpg "I haven't changed a thing of the initial configuration") ### Preparations (microSD card) Partition the microSD card on your PC or laptop. ~~~console $ sudo fdisk /dev/sda ~~~ ~~~ Device Boot Start End Sectors Size Id Type /dev/sda1 2048 411647 409600 200M c W95 FAT32 (LBA) /dev/sda2 411648 15759359 15347712 7.3G 83 Linux ~~~ Format filesystems. ~~~console $ sudo mkfs.vfat /dev/sda1 $ sudo mkfs.ext4 /dev/sda2 ~~~ I am curerntly in `~/mnt`. ~~~console $ mkdir boot root $ sudo mount /dev/sda1 boot $ sudo mount /dev/sda2 root $ wget http://os.archlinuxarm.org/os/ArchLinuxARM-rpi-armv7-latest.tar.gz $ sudo bsdtar -xpf ArchLinuxARM-rpi-armv7-latest.tar.gz -C root $ sync $ sudo mv root/boot/* boot/ $ sudo umount boot root ~~~ So, place the microSD card in the Raspberry Pi and boot it up (with the serial console connected). ### First start There are the following two users pre-defined: | Username | Password | |------------| -----------| | _root_ | _root_ | | _alarm_ | _alarm_ | I prefer my username as _dominic_, so I changed it: ~~~console # usermod -l dominic -d /home/dominic -m alarm # groupmod -n dominic alarm ~~~ {{< alert circle-info >}} The user _alarm_ may come from **A**rch**L**inux **ARM**. {{< /alert >}} So the first real thing is upgrading the system. We start as this: ~~~console # pacman-key --init # pacman-key --populate archlinuxarm # pacman -Syu ~~~ Some general system administration tasks as time setup network setup etc... I'm using NetworkManager on the Raspi so I install it ~~~console # pacman -S networkmanager # nmcli device wifi connect {network-ssid} --ask ~~~ Now we may login via ssh. I had some problems with date and time, so a look at `systemd-timesyncd.service`, `timedatectl status`, `timedatectl show-timesync` and `timedatectl timesync-status` could be useful. At this time this is still not working and I think about running this within a timer: ~~~console $ sudo ntpdate {ntp-host} ~~~ Needs the package _npt_: ~~~console $ sudo pacman -S ntp ~~~ ## Installation of DStarGateway I prefer compiling as normal user so I login as _dominic_. We will need some packages. ~~~console $ sudo pacman -S --needed base-devel wget boost man-db gtest bind ~~~ I hope I got all that we need, if you run into errors, just install the missing ones :wink: ~~~console $ mkdir git && cd git $ git clone https://github.com/F4FXL/DStarGateway.git $ cd DStarGateway $ make ~~~ This ran for 38 minutes -- I will not forget to run `make -j4` the next time :face_with_rolling_eyes: You would now typically install the files but this is the part that made me stop for a while. ~~~console $ sudo make install ~~~ It will break, but at least it installs the binary files into `/usr/local/bin`. Whatever I was doing, it won't work automated. I'm not a developer, but to me this looks like as if `make -C` enters the directory before it runs the top-level Makefile so the `export ...` lines never get executed and the Makefiles in the sub-directories will never know about them, I have to manually install the `Data` folder contents (AMBE files, Hostfiles). Move to the `Data` directory and add the following line on top of the file: ~~~make export DATA_DIR=/usr/local/share/dstargateway.d ~~~ Then run `sudo make install` within the `Data` directory again and all should be fine. Also install the hostfiles (will need the program _wget_). ~~~console $ sudo make newhostfiles ~~~ Copy the systemd unit files to the right directory per hand: ~~~console $ sudo cp debian/* /usr/lib/systemd/system/ ~~~ {{< alert >}} Inspect them because you may edit some paths. {{< /alert >}} Also have a look at the configuration files in `/usr/local/etc/`. Enable the services, but I don't start them yet (except for a short test) because the hotspot will connect to the DSTAR reflector but we can't talk or hear anything. Once they are enabled, they will autostart at the next reboot. To enable the services: ~~~console $ sudo systemctl daemon-reload $ sudo systemctl enable dstargateway.service $ sudo systemctl enable dgwtimeserver.service ~~~ The second is only needed if you want time announcements. ## Installation of MMDVMHost Also this requires special packages: ~~~console $ sudo pacman -S libsamplerate ~~~ ~~~console $ git clone git@github.com:g4klx/MMDVMHost.git $ cd MMDVMHost $ make -j4 $ sudo make install-service ~~~ That would probably fail, but we can do it by hand. Setup the user _mmdvm_: ~~~console $ sudo useradd --user-group -M --system mmdvm --shell /bin/false $ sudo usermod --groups uucp --append mmdvm ~~~ So we run the command one more time: ~~~console $ sudo make install-service ~~~ Binaries are installed and the systemd unit files too. Modify the configuration file `/etc/MMDVM.ini`. Enable the service: ~~~console $ sudo systemctl daemon-reload $ sudo systemctl enable mmdvmhost.service ~~~ ## Setup the UART We can't start MMDVMHost right away (well, we can, but it will not work yet). We need to disable the serial console because we need the UART at the GPIO pins for our modem hardware. Disable the service, that accesses the serial console: ~~~console $ sudo systemctl disable serial-getty@ttyAMA0.service ~~~ Open `/boot/cmdline.txt` and remove `console=serial0,115200` from the line. Save and reboot. ## Configuration Make sure to check them before bringing up any service. ### DStarGateway I removed unused configuration parts, you can leave them in your config, but I want this code here as small as possible without loosing too much of information. ~~~ini [Gateway] type=hotspot callsign=OE7DRT address=0.0.0.0 icomAddress=172.16.0.20 icomPort=20000 hbAddress= hbPort=20010 latitude=0.0 longitude=0.0 description1= description2= url= language=english_us [ircddb_1] enabled=true hostname=ircv4.openquad.net username= password= [ircddb_2] enabled=false # [...] [ircddb_3] enabled=false # [...] [ircddb_4] enabled=false # [...] [Repeater_1] enabled=true band=E callsign=OE7DRT address= port=20011 type=hb reflector=REF096 A reflectorAtStartup= reflectorReconnect=5 frequency=432.7625 offset=-0.0 rangeKm=20 latitude=0.0 longitude=0.0 agl= description1= description2= url= band1= band2= band3= [Repeater_2] enabled=false # [...] [Repeater_3] enabled=false # [...] [Repeater_4] enabled=false # [...] [APRS] enabled=false hostname=rotate.aprs2.net port=14580 password=12345 positionSource= [GPSD] address= port= [Log] path=/var/log/dstargateway/ fileRoot= fileRotate= fileLevel= displayLevel= [Paths] data=/usr/local/share/dstargateway.d/ [DExtra] enabled=true maxDongles=5 [DPlus] enabled=true maxDongles=5 login= [DCS] enabled=true [XLX] enabled=true hostfileUrl=http://xlxapi.rlx.lu/api.php?do=GetXLXDMRMaster [DRats] enabled=false [Remote] enabled=false port=4242 password=CHANGE_ME [AccessControl] whiteList= blackList= restrictList= [Daemon] daemon=false pidfile=/var/run/dstargateway/dstargateway.pid user=dstar ~~~ You can set `band=B` or `band=C` in `[Repeater_1]`. I have `E` because I sometimes test a dual-hat hotspot which used to have `B` set and I've already setup `E` in my DSTAR terminal settings on [regist.dstargateway.org](https://regist.dstargateway.org/). ### MMDVMHost This would be a very long list, I removed things that I did not change from the example config file. I also changed some values to not have a duplicate of my hotspot running wild somewhere, so make sure you change all the options to match your own setup. ~~~ini [General] Callsign=CALLSIGN Id={DMR_ID} # or CCS or whatever this is called Timeout=180 Duplex=0 RFModeHang=10 NetModeHang=3 Display=None Daemon=1 [Info] RXFrequency=432762500 TXFrequency=432762500 Power=1 Latitude=0.0 Longitude=0.0 Height=0 Location=Home Description=DSTAR Hotspot URL=https://oe7drt.com [Log] DisplayLevel=0 FileLevel=2 FilePath=/var/log/mmdvm/ FileRoot=MMDVM FileRotate=1 [CW Id] Enable=0 Time=10 [DMR Id Lookup] File=DMRIds.dat Time=24 [NXDN Id Lookup] File=NXDN.csv Time=24 [Modem] Protocol=uart UARTPort=/dev/ttyAMA0 UARTSpeed=115200 TXInvert=1 RXInvert=0 PTTInvert=0 TXDelay=100 RXOffset=-75 TXOffset=-75 DMRDelay=0 RXLevel=50 TXLevel=50 RXDCOffset=0 TXDCOffset=0 RFLevel=100 RSSIMappingFile=RSSI.dat UseCOSAsLockout=0 Trace=0 Debug=0 [Transparent Data] Enable=0 # [...] [D-Star] Enable=1 Module=E SelfOnly=1 AckReply=1 AckTime=750 AckMessage=0 ErrorReply=1 RemoteGateway=0 WhiteList= [DMR] Enable=0 # [...] [System Fusion] Enable=0 # [...] [P25] Enable=0 # [...] [NXDN] Enable=0 # [...] [M17] Enable=0 # [...] [FM] Enable=0 # [...] [AX.25] Enable=0 # [...] [D-Star Network] Enable=1 LocalAddress=127.0.0.1 LocalPort=20011 GatewayAddress=127.0.0.1 GatewayPort=20010 Debug=0 [DMR Network] Enable=0 # [...] [System Fusion Network] Enable=0 # [...] [P25 Network] Enable=0 # [...] [NXDN Network] Enable=0 # [...] [M17 Network] Enable=0 # [...] [POCSAG Network] Enable=0 # [...] [FM Network] Enable=0 # [...] [AX.25 Network] Enable=0 # [...] ~~~ ### dgwtimeserver ~~~ini [TimeServer] callsign=OE7DRT address= format=voice language=english_us_2 interval=60 [Paths] data=/usr/local/share/dstargateway.d/ [Repeater_1] enabled=true band=E [Repeater_2] enabled=false band= [Repeater_3] enabled=false band= [Repeater_4] enabled=false band= [Log] path=/var/log/dstargateway/ fileRoot= fileRotate= fileLevel= displayLevel= [Daemon] daemon=false pidfile=/var/run/dstargateway/dstargateway.pid user=dstar ~~~ ## Install a dashboard I will install the [dashboard from John Hays (K7VE)](https://github.com/johnhays/dsgwdashboard) as my first look at it looked promising. But: I will not install this as it is in his instructions, because I don't like when these kind of applications (simple dashboards for example) have to be run as the _root_ user. I will therefore create a new user called _dashboard_ who will run the webserver later. We need a few packages for this: ~~~console $ sudo pacman -S nodejs npm ~~~ Create and impersonate our new user: ~~~console $ sudo useradd --user-group -m --system dashboard --shell /bin/bash $ sudo su - dashboard ~~~ Now we are the user _dashboard_ and we will install the dashboard: ~~~console $ git@github.com:johnhays/dsgwdashboard.git $ cd dsgwdashboard $ node -v $ npm install -save ~~~ We would now install some certificates to let the webserver be accessible via HTTPS, but I maintain a reverse-proxy at my home which will take care of all the https-connections. Therefore I modify the `index.js` file according to the following patch: ~~~patch diff --git a/index.js b/index.js index 0c71092..502933e 100644 --- a/index.js +++ b/index.js @@ -1,4 +1,4 @@ -const https = require("https"); +const http = require("http"); const fs = require("fs"); const ini = require("ini"); const lineReader = require('line-reader'); @@ -32,12 +32,8 @@ updatelinks(); let serverPort = inifile.config.port; -const server = https +const server = http .createServer( - { - key: fs.readFileSync("key.pem"), - cert: fs.readFileSync("cert.pem"), - }, app ) .listen(serverPort, ()=>{ ~~~ Modify the `dashboard.ini` file to change the port from 443 to 8443. Why? Because I want to run the webserver as non-root user[^1]! ~~~ini [config] dgwconfig=/usr/local/etc/dstargateway.cfg host=hotspot.oe7drt.net port=8443 ~~~ {{< alert circle-info >}} This might be confusing now, the **actual host** above does not listen to port 8443 because there is a reverse-proxy in-between (and actually a firewall/router too). {{< /alert >}} The actual path of this host and how it will be routed: {{< mermaid >}} %%{init: {"flowchart": {"htmlLabels": false}} }%% graph LR; A([Internet user]):::usr -- "`**HTTPS**`" -->B["`router/firewall _hotspot.oe7drt.net_`"]:::fw; B-- "`**HTTPS**`" -->C["`reverse-proxy _proxy.lan_`"]:::rev; C-- "`**HTTP**`" -->D["`hotspot dashboard _hotspot.lan_`"]:::dash; classDef usr stroke:#faa classDef fw stroke:#f55 classDef rev stroke:#9f9 classDef dash stroke:#0f0 {{< /mermaid >}} This configuration is now as slim as I could make, removing encryption on the dashboard made it even better in terms of performance and maintainability as I don't have to worry about the certificates on this host and no direct port-forwarding to this host has been made. I will now disable the shell for the _dashboard_ user because I won't need to login as the _dashboard_ user again. ~~~console $ sudo chsh -s /bin/false dashboard ~~~ [^1]: Ports below 1024 can only be used as the _root_ user. Those are socalled [privileged ports](https://www.w3.org/Daemon/User/Installation/PrivilegedPorts.html). To run the program as non-root user we need to set the port to something above 1024. ### Start the dashboard with systemd John already provides a systemd unit file, we need to copy this to the right directory. ~~~console $ sudo cp /home/dashboard/dsgwdashboard/util/dsgwdashboard.service /usr/lib/systemd/system/ ~~~ Edit the file, because John uses different paths than we do. ~~~systemd {hl_lines="7 9"} [Unit] Description=D-STAR Gateway Dashboard After=network.target,network-online.target Wants=network-online.target [Service] User=dashboard Type=simple WorkingDirectory=/home/dashboard/dsgwdashboard ExecStart=/usr/bin/node index.js Restart=on-failure RestartSec=5 StartLimitIntervalSec=60 StartLimitBurst=0 StandardOutput=syslog StandardError=syslog [Install] WantedBy=multi-user.target ~~~ Enable and start the dashboard: ~~~console $ sudo systemctl daemon-reload $ sudo systemctl enable --now dsgwdashboard.service ~~~ ## DSTAR Registration A DSTAR registration is needed if you want your transmission to to be heard on original ICOM repeaters. Otherwise your transmission will not be forwarded and you may be searching for errors... I registered in 2020 at but there is one important thing to add to the webui there: do not choose long passwords (like those from a password manager) because it will get cut off somewhere and it took me quite a while to realize that. {{< alert skull-crossbones >}} **I can't believe that there are still websites in 2024 that limit the lenght of a password!** {{< /alert >}} This can be an indication, that our passwords are saved in **cleartext**. {{< alert >}} This is one reason to not use the same password on different websites/services. {{< /alert >}} For your information: 12 characters work -- I couldn't bring me back up to test more. Many password-reset emails have been sent for this already so I couldn't be bothered to investigate even more into that.