Blog

  • How I set up my self-hosted Matrix instance

    Matrix is a modern, decentralized, federated real-time communication protocol and open standard. It has a thriving ecosystem of servers, clients, and applications. Synapse is the reference server and Element is the reference client for the web, desktop and mobile platforms.

    Matrix protocol logo

    This is something that I have been interested in using and self-hosting for a few years now. I have had an account on the main matrix.org instance for a while now and wanted to switch to a self-hosted instance.

    Since I have been using docker, docker-compose, and Ansible to deploy and run a wide range of self-hosted applications for my personal use, the spantaleev/matrix-docker-ansible-deploy was my choice for setting up my instance. I chose to use Synapse over Dendrite, the second-generation server because though it is lightweight, it is not feature-complete. All the other third-party implementations have a lot of catching up to do as well, at the time of writing this post.

    I learned a bit of Terraform in my previous job, but never had a chance to learn it properly or build something from scratch using it. So armed with my little knowledge of Terraform, I created a small Terraform project to automate setting up a new Matrix instance. It provisions the DNS records needed for Matrix on Namecheap — my domain registrar and DNS host, provisions an appropriately sized Hetzner cloud instance with a floating IP address, and runs the deployment playbook in the matrix-docker-ansible-deploy repository with the provided Ansible variables file. I used the hcloud and the namecheap Terraform providers to do this.

    With this, I was able to provision and set up my Matrix instance in under 10 minutes by just running

    $ terraform plan -out=matrix-plan
    $ terraform apply "matrix-plan"

    I have released the source code for this project here on GitLab under the GNU Affero General Public License v3.0 (AGPLv3) or later. Since this project contains the matrix-docker-ansible-deploy repository as a git submodule, running git submodule update --init should automatically pull in a known good commit of that repository to use for the deployment. The README file has the instructions for using the project to set Matrix instances from scratch.

    I hope it is useful for those who are looking to set up a new Matrix instance.

  • Move windows between displays using shortcuts in KDE Plasma

    I have a dual-display setup for my desktop and I usually set up custom keyboard shortcuts in KDE Plasma to allow moving windows between the displays easily. However, the KWin shortcuts section of the Plasma System Settings app has multiple shortcuts named in a confusingly similar way.

    So I am writing this post to just document what I did to get my custom Ctrl +Alt + <left/right> arrow shortcut working.

    Set up custom shortcuts for the Window to Previous Screen and the Window to Next Screen entries to get this working. As mentioned above, I use Ctrl + Alt + <left arrow> for the former and Ctrl + Alt + <right arrow> for the latter.

    Screenshot showing the shortcut entries to change.

  • Updating a docker-based Wireguard server when connected to it remotely via the same VPN

    I have a WireGuard server running on a Raspberry Pi 4B at my home, exposed to the internet via a static IP address and port forwarding. I set it up using the Linuxserver.io WireGuard docker container, which is straightforward to use and manage.

    As I am in a different city now, I had been postponing the updates to the docker container since it is risky to do so remotely. Any issue in the upgrade process could lock me out of my home network till I am physically present in my home.

    As I hate deferring updates, I decided to apply the update remotely. To prepare for that, I logged into the Raspberry Pi via the WireGuard VPN and set up a remote forwarding SSH tunnel on a server of mine hosted in the cloud, using a command like,

    $ ssh -R 2222:127.0.0.1:22 username@remote.server.address -N

    This command forwards the 2222 port on the remote server to 127.0.0.1:22 on the Raspberry Pi, thereby allowing access to it from the remote server. The -N flag prevents the execution of any remote command (like say, starting the user’s shell) and is useful for just forwarding ports.

    Then I logged in directly to that server and logged in to the Raspberry Pi using the forwarded port on that server. Now I could destroy and re-create the WireGuard container without the fear of being locked out since I was connected to the device using SSH and not the WireGuard VPN itself. So, I ran the following command.

    $ ssh -p2222 -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o CheckHostIP=no username@127.0.0.1

    The UserKnownHostsfile=/dev/null option prevents the saving of the remote host’s SSH key in the ~/.ssh/known_hosts file, the StrictHostKeyChecking=no option prevents the checking of the remote host key, and the CheckHostIP=no option prevents the checking of the remote host’s IP address. These options disable a lot of important security measures that SSH provides by default ⚠️. But since we are connecting to a known host through a forwarded host, and don’t want to save any local data about it, these options are fine to use.

    This command my remote SSH session, and I was worried that I had missed something important and was locked out. So, I disconnected the SSH session using the escape sequence (<enter>~.) and reconnected to my cloud server and then to the Raspberry Pi. It worked and I heaved a sigh of relief and was glad to have pulled this off without any issues. I verified that updated WireGuard container was running without any issues and that I was able to connect to the VPN. 😌

  • Bye Tiny Tiny RSS, hello FreshRSS!

    Update (April 2021): I switched back to Tiny Tiny RSS after fixing the abandoned LinuxServer.io Tiny Tiny RSS docker codebase to work with the latest Tiny Tiny RSS changes in my fork.

    I have been using feed readers to consume RSS feeds for more than a decade now, starting with Liferea and then moving on to the web-based Google Reader (RIP) and NewsBlur. I used the free tier of NewsBlur for a long time and even contributed some bug fixes to it. The Android app was available on F-Droid and worked pretty well. However, as a self-hosting enthusiast, I wanted to self-host NewsBlur, and it was very difficult to do so. So I started searching for alternatives again.

    I found Tiny Tiny RSS and fell in love with it as it was full of useful features and very easy to self-host. The project’s author can often be a very difficult person to deal with and is very opinionated. Fortunately, I had to ask for support on the official forums just a few times in the many years that I used Tiny Tiny RSS.

    The TTRSS-Reader app on F-Droid proved to be a very good companion Android app, followed by a fork of the official version. When I moved all my self-hosted applications to a docker-compose based setup a couple of years ago, the LinuxServer.io tt-rss container image was very easy to set up and migrate to. Then the project stopped maintaining the container because the upstream author didn’t like them packaging his software and asked them to stop doing so. 🙁

    The source for the container image was available on GitHub and I continued to use it to build and update the tt-rss container that I self-hosted. However, a month or so ago, there were some breaking changes to the configuration method used by Tiny Tiny RSS and my builds stopped working. Then I started checking if I could use the officially supported docker-based installation method documented here. However, that installation method required Tiny Tiny RSS to be run as a sub-folder under a top-level domain and not as a sub-domain like I wanted.

    So I attempted to build my own Tiny Tiny RSS container and while doing so, realized that it is not worth doing so. I decided against spending any more time trying to get Tiny Tiny RSS to work as it was clearly not intended to be used in the way that I wanted to (according to the author). I started looking for alternatives again and liked FreshRSS. To be honest, it didn’t feel as polished and mature as Tiny Tiny RSS or NewsBlur, but was close enough.

    I used the LinuxServer.io FreshRSS container to set up my instance and migrated all my feeds from Tiny Tiny RSS to it. As the web interface felt a bit clunky to me, I started using it via the client apps – NewsFlash on my desktop and Readrops from F-Droid on my phone and the experience has been okay.

    Before I chose FreshRSS, I checked and investigated the current status of NewsBlur and if the self-hosting scenario had improved. The project has a docker-based deployment method now in the dashboard3 branch, but it looks like it might take a while for it to have first-class support. And the project has and uses a lot of bells and whistles which are not needed for a small instance or a single-user setup. I briefly considered subscribing to the premium plan on the official NewsBlur site, but didn’t do so out of subscription fatigue and also because I already pay for infrastructure which can be used for self-hosting many services.

  • The birthday greeting card masterpiece

    Today is my wife’s birthday and after hearing that her nephew had made her a greeting card, my 32-months-old daughter decided that she had to do something to top that.

    So she took her scribbling notepad, took all her crayons and scribbled all the colors she had one by one singing “Happy birthday to you amma!” for each color and gifted the result as her greeting card immediately after.

    😘

  • Fixing the rough edges of my Plasma setup

    I use KDE Plasma on my Arch desktop and I’ve had some issues with getting my dual-monitor, mixed DPI setup to work properly as mentioned in my previous post.

    I nuked and paved my existing installation a few weeks ago and set up Arch afresh on the same computer on a new SSD. On the previous install, I had set up the root filesystem on a hard drive with LVM and the system startup was very slow – ~45 seconds to reach SDDM, an additional ~30 seconds to drop to a usable desktop, and then ~5 seconds to run my xrandr script.

    The boot time and the time taken to reach a usable desktop was significantly lesser with the SSD – ~8 seconds to start SDDM, ~5 seconds to the desktop, ~3 seconds to run the xrandr script. So I was happy.

    As exciting as that was, I still had many rough edges and paper cuts, most of them persisting across multiple re-installations. Thanks to the posts by various posts by fellow Plasma users, I was able to solve them 🙂

    SDDM

    Monitor layout

    When SDDM started, it always did with my monitor layout and DPI configured wrong. My secondary 1080p monitor is placed to the left of my primary 4K monitor and SDDM always placed the former to the right of the latter.

    Thanks to this useful post, I was able to create a custom Xsetup script by adding the xrandr command from my previous post and configuring SDDM to run it when starting the display server.

    # /etc/sddm.conf
    [XDisplay]
    DisplayCommand=/usr/share/sddm/scripts/Xsetup

    Theme

    I don’t like the default theme used by SDDM, maui. Since Arch is a DIY distro, it doesn’t automatically set up the default Plasma theme, breeze, like many other distros do when Plasma is installed.

    Previously, I was using the Chili login theme to make the SDDM greeter look nice. I was unsure why and how, the Manjaro installation on my laptop, had a nice Plasma theme for SDDM. But I didn’t spend any time investigating at all till now.

    I checked the Arch wiki page on SDDM theming to check if there are nice themes listed there that I could use and found that it is possible to configure the SDDM theme using the Plasma System Settings application after installing the sddm-kcm package. I found the default Breeze theme which I liked very much and set it as the theme. But that didn’t work. So I went ahead and configured it manually in sddm.conf and voilà, it worked! 😀

    # /etc/sddm.conf
    [XDisplay]
    DisplayCommand=/usr/share/sddm/scripts/Xsetup
    
    [Theme]
    Current=breeze

    Desktop scaling

    I was pleasantly surprised to see that Plasma automatically scaled my 4K monitor without having to configure scaling manually via the Display settings application. Everything in the secondary monitor looked large as expected and I had to run my xrandr command from the previous post, with some changes to restart Plasma shell for making the wallpaper fit the scaled display, manually every time due to something in the Plasma startup process resetting the screen configuration irrespective of when my xrandr auto-start script ran.

    Thanks to this post on Reddit by a fellow Plasma user, I found that the kscreen2 service was the culprit and disabling it ensured that the display configuration set up by the SDDM Xsetup script persisted and as a result, I didn’t have to manually run my xrandr script 😀 😌

    There could be some side-effects caused by disabling the kscreen2 service, but I haven’t run into any till now 🙂

    Emoji picker

    The built-in emoji picker, introduced in Plasma 5.18, is very convenient and something that Plasma was sorely missing before. However, in spite of installing an appropriate emoji font, the emoji picker had a lot of missing emoji with blank squares and the color/gender variants of some emoji looked broken with those showing up as two separate symbols (one for the emoji and the other for the color/gender variant) overlapping each other.

    Thanks to this Reddit post, I was able to solve the issue by creating a custom fontconfig configuration file, ~/.config/fontconfig/fonts.conf, with the configuration below and by forcefully rebuilding the font info cache files by running fc-cache -f.

    <?xml version='1.0'?>
    <!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>
    <fontconfig>
    	<match target="font">
    		<edit mode="assign" name="rgba">
    		<const>rgb</const>
    		</edit>
    	</match>
    	<match target="font">
    		<edit mode="assign" name="hinting">
    		<bool>true</bool>
    		</edit>
    	</match>
    	<match target="font">
    		<edit mode="assign" name="hintstyle">
    		<const>hintfull</const>
    		</edit>
    	</match>
    	<match target="font">
    		<edit mode="assign" name="antialias">
    		<bool>true</bool>
    		</edit>
    	</match>
    	<match target="font">
    		<edit mode="assign" name="lcdfilter">
    		<const>lcddefault</const>
    		</edit>
    	</match>
    	<match target="font">
    		<edit name="autohint" mode="assign">
    		<bool>false</bool>
    		</edit>
    	</match>
    	<match target="pattern"> 
    		<edit name="family" mode="prepend"> 
    		<string>Noto Color Emoji</string> 
    		</edit> 
    	</match> 
    </fontconfig>

    It looks nice after the fix 👌🏼

  • How to get a dual monitor setup with mixed DPI working on Xorg

    Last year, I purchased a new 4K monitor to use as my primary display in addition to my existing 1080p monitor. Like with most 4K monitors, this one required scaling to display text and interface elements in a readable size. While the dual monitor setup worked okay out of the box on Windows 10, it didn’t on my Arch install running an up-to-date KDE Plasma.

    1.5x scaling in the Display settings on Plasma made everything look okay on the primary 4K monitor but look large and ugly on the 1080p monitor. I was aware that Wayland supports mixed DPI environments very well but I was stuck on Xorg due to having an Nvidia GPU and Plasma’s support for EGLStreams still being a work in progress.

    I read multiple recommendations on the internet to scale (mentioned correctly in a few places as “upscaling”) the 1080p display using xrandr to compensate for the scaling done by the desktop environment so that everything looks okay on both displays. What confused me a long time is that “scaling” meant different things when it came to xrandr and the desktop environment. Scaling in the desktop environment translated to zooming in the desktop by 1.5x (“downscaling”) to make everything look larger and (up)scaling the display using xrandr meant zooming out the Xorg display for the monitor 1.5x to make everything look smaller.

    A lot of different xrandr commands were given as examples. However, all of those were for setups different from mine and used a lot of parameters and flags without a general explanation of what they do and how to adapt them for other scenarios. This was very important for someone like me who isn’t familiar with the terminology. So for a while, I had to resort using just konsole on the secondary 1080p monitor with the font size reduced to make it look okay and the interface elements still looking large and ugly.

    Eventually, I found out the solution that I needed – scale the desktop environment 1.5x which reduced the effective resolution of the 4K (3840×2160) monitor to 1440p (2560×1440) and that of the 1080p (1920×1080) monitor by 1.5x to 720p (1280×720). That made everything on the 4K monitor look properly sized and large on the 1080p monitor. To fix that, I had to use xrandr to upscale the 1080p display by 1.5x (2880×1620) to compensate for the desktop environment’s 1.5x scaling. With that, everything looked good on both monitors. Below is the xrandr command that I used.

    xrandr --fbmm 6720x3780 --output DP-0 --pos 2880x0 --mode 3840x2160 --scale 1x1 --primary --output HDMI-0 --pos 0x0 --mode 1920x1080 --scale 1.5x1.5

    The fbmm flag sets the reported physical size of the X screen as a whole. In this case it is (3840+2880)x(2160+1620), which is the sum of the resolutions of both monitors after running the xrandr command. The --pos flag is used to position the monitors in the 6720x3780 display. Since the 1080p monitor is present to the left of the primary 4K monitor, its position is at 0x0. The starting position of the 4K monitor is 2880x0, where 2880 is the horizontal resolution of the 1080p monitor, so that it is positioned right after the latter ends.

    This still caused an issue on the 1080p monitor where the Plasma desktop screen was reduced in size by 1.5x and was not filling the whole display. This also meant that the wallpaper was not filling the whole display. The unfilled area in that display was black in color. (Update May 2020: this can be fixed by restarting the Plasma Shell) To work around this issue, I used black color as the wallpaper for that screen and removed all the elements on that desktop. Till very recently, I continued using black color as the wallpaper and when I found that this was fixed in a recent Plasma update (not sure when and which version), I was able to use a proper wallpaper on the 1080p monitor as well.

    While this solved the major problem with mixed DPIs, the GUI toolkits (Qt 5, GTK 3) and some applications like Firefox needed some additional scaling tweaks to get them looking okay. For this I used the excellent documentation on HiDPI in the Arch wiki which covered almost everything. Steam and VirtualBox were a couple of notable exceptions that didn’t work okay. The former didn’t support fractional scaling and only worked with 2x scaling which makes everything noticeably larger. The latter was broken and had a lot of issues with the menus appearing in the wrong places and the guest VMs unable to use a proper resolution. Fixing this issue required setting QT_SCREEN_SCALE_FACTORS to 1.0.

  • Balloon, joy in small things

    Balloon, joy in small things

    Today, we took our 20-month-old daughter to a toy store for the the first time. She was excited to be there and was eagerly looking at everything. While she pointed to a few things that caught her eye and said that she wanted it, she didn’t cry or protest when we ignored her requests.

    A free balloon given to her in that shop was all that she needed to have an unerasable grin 😃 on her face for the next few hours and ignore everything else!

  • Getting encryption to work on Redmi Note 4 with LineageOS 15.1 and newer

    I have been using LineageOS on my Redmi Note 4 phone from the day I bought it. Till yesterday, I was running LineageOS 15.1 on it with encryption enabled. Since I wanted to try out the new Pie release, I tried installing the Resurrection Remix 7.0 ROM based on the Android Pie release. After setting everything up and restoring all the apps and data using Titanium Backup, I tried encrypting the device. However the encryption process failed and caused the phone to do a quick restart.

    Since this was totally unexpected, I checked the error messages using the adb logcat command. The error message was

    E Cryptfs : Bad magic for real block device /dev/block/bootdevice/by-name/userdata
    E Cryptfs : Not a valid ext4 superblock
    Orig filesystem overlaps crypto footer region.  Cannot encrypt in place.

    This was strange because the userdata partition that is mounted at /data was formatted normally using the ext4 filesystem. Searching the internet lead me to this Reddit post which gave some useful pointers about the issue.

    I tried to resize the userdata partition by formatting it from the bootloader and voilà the encryption succeeded on the next boot after a clean install. So I started restoring the apps and data from the backup and when it was about to complete, I got an error notification which said internal storage running out, some system functions may not work.

    I was surprised by this since my phone had 64 GB of internal storage and there is no way for all of it to get used up. I also wondered if it was due to the encryption of the new apps and data (like what Bitlocker does on Windows by showing the disk to be 100% full while it is doing the initial encryption). (After resolving this issue later, I found this to be this reported issue). I started to suspect that something is broken with the installed ROM. I wanted to flash the stock MIUI ROM to check the partition size but it was difficult to find a working download link for the official fastboot ROM files because of issues (intentional?) with the Xiaomi site as usual.

    After flashing the stock ROM via the fastboot interface and then flashing TWRP and then the ROM, GApps and Magisk, I booted into the OS to find the internal storage size detected correctly. However, when I tried to encrypt the phone it failed again with the initial error.

    Suspecting some issue with the ROM, I installed LineageOS 15.1 because the encryption was working fine on it. But unfortunately, even with LineageOS 15.1, the encryption was failing with the same error. Since I had already spent too much time trying to fix this, I gave up for the time being and went to sleep.

    This morning, I researched this issue further and found this post, which revealed this to be an issue with TWRP 3.2+ not formatting the /data partition properly and the solution was to use a 3.1 version to format the userdata partition and then use the latest TWRP to flash Oreo ROMs or newer because of the compatibility requirements. Luckily for me, it worked perfectly and now my phone can run the Pie-based ROM with data encrypted.

    One important lesson I learned from this experience is to be conservative when flashing/switching ROMs because I often end up spending a lot of time to get everything working as expected and also have to suffer phone downtime. Another thing I reminded myself (again!) to do is to periodically download and keep backups of the stock fastboot ROMs because of how unreliable the official site can be.

  • 2018: A roller coaster ride

    2018 is almost over and it was an unbelievable year! It took me through a myriad of situations, experiences and emotions and I can barely believe that I was able to get through.

    My daughter was born in the beginning of the year and it was an amazing experience being a parent for the first time, in spite of being clueless about bringing a baby up. Holding the tiny bundle of joy in my hands for the first time and the days gone by seeing her grow up very fast, have all been surreal.

    Just a week after the birth, while I was on paternity leave, I was laid off along with hundreds of others in a workforce reduction and the division I was working for, was wiped out from Bangalore without a trace. It came out of the blue and though there were attempts by the local management to re-hire and re-purpose at least some of those affected, it was too little too late. It was an unbelievable shock and it took everyone affected, a long time to recover.

    I had injured my shoulder while playing badminton towards the end of 2017 and was advised a surgery to fix it. I had planned to get it done during my paternity leave and was in tatters due to the layoff.

    I applied for some jobs via referrals of friends and acquaintances and got a couple of job offers. But there were some issues to consider before I could accept any of them – daily commute to office being one of the major factors. I received a job opportunity from my previous company to work for a different team and given my circumstances, I chose to accept it and joined in a new role soon after.

    I was a part of a new team with everyone else in the team including my manager working in remote locations, with a couple of interns/new joinees expected to join me a few months later. The work was in a totally different domain and I was never able to mingle with the folks and the work environment didn’t feel the same.

    I took a fortnight off and had my shoulder surgery which was a minor procedure. It was a very traumatic experience because of the poor care provided at the hospital in spite of me repeatedly warning them about it. I was advised to do physiotherapy for 2 months to regain full movement of my right shoulder and that didn’t go well after a while – the hospital was too far from my home and the hospital refused to provide on-site physiotherapy after a while. Later, the hospital had some issues at the management level and almost all the doctors including the one I was consulting, quit the hospital and moved to a different hospital which was even farther. 🤷‍♂️

    I read the monthly ‘Ask HN: Who’s hiring?’ posts on Hacker News regularly and came across a job posting for an interesting remote job as a senior open source developer. Just out of curiosity, I applied for it and though I never expected to get a response, I got one in a fortnight’s time. I had an interview with the company’s CEO and I was given a job offer soon after.

    The next couple of weeks when I had to think about the job offer and make a decision were tough. Though I was laid off and re-hired immediately after, I was in a very comfortable and familiar job with a lot of employment benefits. On the other hand, I would have to work on an hourly basis as a self-employed contractor in the new job and without any employment benefits like paid leave, medical/life insurance etc. But it would allow me to permanently work from home, spend time with my daughter and also avoid the headache of daily commute in the mad Bangalore traffic.

    I bought a used car (a silver grey Hyundai i20, 2009 model) to gain more driving experience after my driving classes in the previous year and also to be able to drive my family when required. I had vowed to never buy a car since, imho, I would be inconveniencing myself and everyone else on the road given the Bangalore. But the incessant pressure from my wife made me cave in.

    During this time, a close relative who was ill for the past few months passed away. He was a fatherly figure to me and I was very close to him right from my childhood, having been brought up in a joint family he was a part of. It was an unbearable loss that shook the whole family and I was no exception.

    All the chaos in the first half of the year till that point made me decide to continue with the status quo and continue in my current job. But a last-minute call with my colleague, friend and a mentor changed my mind and I ended up writing my resignation letter instead of an email rejecting the job offer.

    I joined the new job in the second half of the year. Though the work and pay were very good, there was a two-month trial period which made me very nervous till I successfully completed it.

    My wife went back to work after her maternity leave and though there was support from my in-laws to take care of our daughter, it was always going to be temporary given their preferences and way of life. Given, my parents continued to keep away from us, thanks to my father still being mad about my marriage (even the sight of my daughter didn’t change that), we had to take whatever help was offered under any condition.

    I took my wife, daughter and a cousin on a long drive towards the end of the year in my car and it was an amazing (but tiring) experience and helped me get more comfortable with my car (My wife is still fighting with it 😜) I also bought myself a new laptop, but haven’t set it up fully for work yet.

    This month, we did our daughter’s first hair shaving and ear piercing ceremony and it was heartbreaking to see her cry continuously and be very cranky for many days after the ceremony, thanks to her fever and a bout of common cold.

    Next year is going to be very challenging as she grows up. She is already very active and naughty and things are only going to get worse 😉 My wife’s office is not willing to support her to take care of our daughter any more and with my in-laws planning to go back some time in the middle of the next year, it is just going to be the three of us and one heck of a journey. 🤞🏼

    Here’s to an awesome 2019!