Thursday, July 2, 2020

How to generate and read QR code on Linux

QR code, short for Quick Response code, was initially created to improve on bar codes used in inventory management. Nowadays, QR codes are ubiquitous, on posters, billboards, web pages, etc. This post will illustrate how to generate and read QR codes using the Linux command line interface (CLI).

The programs you will need to generate and read QR codes are qrencode and zbarimg respectively. (If you want to work with a GUI tool, there is QtQR.) To install the 2 programs on Debian:

$ sudo apt install qrencode zbar-tools 


A QR code is a matrix of square dots (or 'modules' in QRspeak). QR codes have as many as 40 versions of increasing data capacity. Version 1's dimension is 21 × 21 modules, and each higher version adds 4 modules per side ending with version 40 with 177 × 177 modules.

The exact maximum data capacity of a version depends on several factors, including the type of characters stored, e.g., numeric vs alphanumeric, and the level of error correction desired. At Medium error correcting capability, version 1 can store up to 20 alphanumeric characters; version 40, 3,391.

Fortunately, as we'll see next, the qrencode utility specifies good defaults, and hides much of the gory details from you.

QR code generation

In its simplest form, qrencode takes the input string to be encoded and outputs the PNG graphic to a file. The following command encodes the URL for this website.

$ qrencode -o webURL.png  ''

You can specify different parameters to fine-tune the QR code. Use the -l parameter to change the error correction level from the default L for Lowest to M for Medium, Q for Quite High, or H for Highest. In addition, you can explicitly specify the version to use, the size of the module and the margin, etc. The following example generates a version two QR code for the same website at the Highest error correcting level.

$ qrencode -o webURL.png -l H -v 2 ''

Besides the URL, marketers typically encode information such as phone numbers and email addresses.

$ qrencode  -o webPhone.png  '(604)555-1234'
$ qrencode  -o webEmail.png ''

Many QR code scanners will automatically open the associated app upon scanning a QR code of a special format, e.g., a browser for URLs, email client for email addresses, and phone app for telephone numbers.

QR code scanning

The Linux program zbarimg decodes the QR code stored in a file. To invoke, simply provide the input filename which contains the QR code.

$ zbarimg webURL.png
scanned 1 barcode symbols from 1 images in 0 seconds

If you specify the -d parameter, zbarimg will display the QR code in addition to the decoded information.

The default camera app of recent Android or iOS phones can also function as QR code scanner. To scan, run the camera app and point it towards the QR code.

Tuesday, June 23, 2020

Adding Google Analytics tracking code to a WordPress website

My previous post revealed how to piggyback a new WordPress website on an existing WordPress instance using what is known in WordPress-speak as multisite. In this post, I'll walk through how to embed the Google Analytics tracking code, aka the Global Site Tag, in the new website.

Website administrators want to know who, when, how, and what users do on their websites. Google Analytics can provide that information if the proper tracking code is found on the web pages.

There is more than 1 way to insert the tracking code, including using the Google Tag Manager or the WordPress plugin MonsterInsights. This post details a manual method of directly embedding the tracking code in a WordPress theme, assuming that you have already set up a Google Analytics account for the target website. In addition, I assume that you have created and activated a child theme for your website. If you are hosting multiple websites within the same WordPress instance, I assume you have a separate child theme for each site.

  1. Login to Google Analytics, and select the account corresponding to the target website.
  2. Click Admin on the LHS menu bar.
  3. Click Tracking Info and then Tracking Code in the middle column.
  4. Copy the Global Site Tag script to be pasted next in the WordPress theme.
  5. SSH into web host, and copy the header.php file from the parent theme to the children theme.
  6. $ cp /var/www/  /var/www/
  7. Paste the tracking code script.
    The script should be inserted in the header.php file in your child theme directory, say /var/www/, just before the call to wp_head() at the end of the header specification.
  8. Navigate back to Tracking Info/Tracking Code on Google Analytics and click Send Test Traffic.
    A new session of your website pops up in the browser.
  9. Navigate to Reports section on the LHS menu bar, click Realtime, then Overview.
    You should see the just opened session being counted in the number of active users on site.

Related webpages

Sunday, June 14, 2020

How to migrate single site WordPress to multisite

The scenario

I had an existing WordPress website, say, that was hosted on a DigitalOcean VPS running LEMP(Linux, NGINX, MySQL, PHP). The website supported HTTPS using a TLS certificate issued by Let's Encrypt.

I wanted to start a new WordPress website, say Barring a miracle, would initially have minimal traffic.

I decided that the new site would run on a virtual host on the same VPS, using WordPress's multisite feature.

WordPress multisite

Hosting multiple websites/domains on the same VPS can be a double-edged sword. Suffice to say, the advantage is economy of scale, and the disadvantage, putting all one's eggs in one basket.

The multisite model in WordPress can be summarized as '1 instance, 1 database'. The multiple websites share the same WordPress DocumentRoot directory (/var/www/example1) and the same WordPress mySQL database.

Within the single database, site-specific information is stored in tables identified by the blog IDs. For instance, the wp_posts table for retains the same name in multisite. However, the corresponding table for is named wp_2_posts (the 2 in the name refers to the official blog ID).

Multisite introduces a new level of complexity in administration. Seeing multisite in action is the best way to know what you are getting into before actually migrating your production website.

Trialing the migration

Setting up a separate VPS with the same configuration as the production system is the best option for conducting a trial migration. Notwithstanding, I opted for a poor man's platform to test the migration, my home workstation.

I won't be able to completely replicate at home the production environment. Most notably, no HTTPS for the home machine because there won't be TLS certificates.

To reflect the change from HTTPS to HTTP, I modify 2 WordPress administrative options, siteurl and home. Run the following SQL commands under mySQL:

update wp_options set option_value='' where option_name = 'siteurl';
update wp_options set option_value='' where option_name = 'home';

Note that instead of reusing the same names for and, I renamed them to say and respectively. In addition, I configure local DNS on my home workstation to map and to localhost's IP address. The reason is that I can access both the production and the trial websites at the same time. Add the following lines to the /etc/hosts file:

The rest of this post will detail the steps to convert WordPress from hosting a single site to hosting multiple sites.

Configuring system

  1. Configure DNS.

    Register with a domain name registry and add the appropriate DNS records.

  2. Obtain Let’s Encrypt TLS certificate for second domain.

    I assume certbot is already installed, certbot.timer enabled, and port 443 open.

    Although it is possible to bundle multiple domains, and in a single certificate, it is recommended that you create separate certificates for unique domain names.

    $ sudo certbot certonly --webroot -n --agree-tos -m -w /var/www/ -d 

    -m: the email address for the certificate contact.

    -w: the DocumentRoot for which is the same as

    -d: the domain.

  3. Install certificate.

    Link the private key and the certificate generated by Let’s Encrypt to their respective expected TLS locations.

    $ sudo ln -s /etc/letsencrypt/live/ /etc/ssl/private/key2.pem 
    $ sudo ln -s /etc/letsencrypt/live/ /etc/ssl/certs/cert2.pem

    Note that the names key2.pem and cert2.pem must be different from their counterparts for Make a note of their names as you will need them later.

  4. Configure website.

    Create /etc/nginx/sites-available/ by copying and making the necessary changes.

    My skeleton file looks like the following. The highlighted lines are relevant to the migration per se.

    server {
        listen 80;
        return 301 https://$host$request_uri;
    server { 
        listen 443 ssl; 
        ssl_certificate     /etc/ssl/certs/cert2.pem;
        ssl_certificate_key /etc/ssl/private/key2.pem;
        root /var/www/; 
        server_name *;
        index index.html index.php;
        location / {
            try_files $uri $uri/ /index.php?q=$uri&$args;
        location ~ \.php$ {
          fastcgi_pass unix:/var/run/php/; 
        location ~* /(?:uploads|files)/.*\.php$ {
          deny all;
        location = /robots.txt {
          allow all;
          log_not_found off;
          access_log off;
        add_header X-XSS-Protection "1; mode=block";
        add_header X-Content-Type-Options nosniff;
        add_header X-Robots-Tag none;
        add_header X-Download-Options noopen;
        add_header X-Permitted-Cross-Domain-Policies none;
        add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload";
        add_header Referrer-Policy no-referrer;
        add_header X-Frame-Options "SAMEORIGIN";
  5. Notes:

    • The location of the certificate (cert2.pem) and key (key2.pem) need to be specified.
    • The DocumentRoot location is the same as
    • The relevant server names are specified for this website(
    • PHP handling is listening to the same socket as (/var/run/php/
  6. Enable website.
    $ sudo ln -s /etc/nginx/sites-available/ /etc/nginx/sites-enabled/
  7. Reload NGINX.

    Test the syntax of the file changes before actually reloading the configuration files.

    $ sudo nginx -t
    $ sudo systemctl reload nginx

Configuring WordPress

  1. Install wp_cli.

    Although one can handcraft the necessary lines in the WordPress configuration file (/var/www/, I’d recommend using the command-line program [wp-cli]( To install, run this command sequence:

    $ curl -O
    $ chmod +x wp-cli.phar
    $ sudo mv wp-cli.phar /usr/local/bin/wp
  2. Convert to multisite.
    $ wp core multisite-convert --subdomains --path=/var/www/

    The above command can be run while the website is up because it only statically inserts the following lines into wp-config.php.

    define( 'WP_ALLOW_MULTISITE', true );
    define( 'MULTISITE', true );
    define( 'SUBDOMAIN_INSTALL', true );
    $base = '/';
    define( 'DOMAIN_CURRENT_SITE', '' );
    define( 'PATH_CURRENT_SITE', '/' );
    define( 'SITE_ID_CURRENT_SITE', 1 );
    define( 'BLOG_ID_CURRENT_SITE', 1 );
  3. Patch ‘blocked cookie’ bug.

    Unless the bug is patched, login to your new website ( is prevented. The error message from Firefox is ‘Cookies are blocked or not supported by your browser. You must enable cookies to use WordPress.’

    To patch, edit /var/www/, and insert the following define statement anywhere above the “That’s all” comment line.

    define('COOKIE_DOMAIN', false);
    /* That's all, stop editing! Happy publishing. */
  4. Restart the PHP-FPM and NGINX daemons.
    $ sudo systemctl restart php7.3-fpm
    $ sudo systemctl restart nginx

Creating new site

  1. Login to the original WordPress website using the URL(

    The ID to use to login is the same admin ID for In multisite, this admin ID is promoted to super-admin status, capable of administering all domains within the network.

  2. Click My Sites and select Network Admin and then Sites.
  3. Click Add New.
  4. Enter the required data, and click Add Site.
  5. The Site Address is where one is supposed to enter the URL except it expects a subdomain, such as example2 which it will then concatenate with the primary domain to become, not what I really wanted as in So for now, I simply play along by entering example2, and I will change it later. If you know a better way, please let me know in a comment.

    The Admin Email can be that of an existing user, say the super-admin, or a new user.

  6. Again, click My Sites and select Network Admin and then Sites.
  7. Hover over and click Edit.
  8. Enter the correct Site Address,, and click Save Changes.

Now, the new website is created and ready for you to edit. Browse to and login as the super-admin user.

Related webpages

Tuesday, May 26, 2020

Gromit-MPX: a nifty videoconference screen annotation tool

The rise of the COVID-19 pandemic propels videoconferencing to the stratosphere of user adoption. Almost overnight, the previously unknown app Zoom became a household technology name. Technology behemoths like Google and Microsoft scrambled to beef up their own videoconferencing products to match Zoom's success.

Zoom allows the meeting presenter to share their desktop with other participants. Google Meet and Skype also have that screen sharing feature. What Zoom offers, as of today, but not Google Meet or Skype, is the ability to annotate the shared screen in real time.

Undoubtedly, Google and Microsoft will eventually incorporate screen annotation in their respective products, but for the time being, gromit-mpx is a viable stopgap solution.

With gromit-mpx, presenters can annotate their desktop using free-hand drawing. It is true that Zoom as well as several third-party open-source annotation apps such as ardesia and pylote give presenters more bells and whistles, for instance, to draw geometrical shapes such as solid or dashed lines and to enter text. Yet the no-frills gromit-mpx is tailor-made for videoconferencing because of its non-obtrusive, hotkey-based mode of operation.

In contrast to Zoom and pylote, gromit-mpx does not have a toolbar, thus saving valuable screen space. In lieu of a toolbar, gromit-mpx functionalities can be activated using hotkeys(see the table below). The inconspicuous use of hotkeys is generally less obtrusive to the presentation than the clicking of the mouse on a protruding toolbar.

Hotkey combo Corresponding action
F9 Toggle drawing
Shift-F9 Clear screen
Ctrl-F9 Toggle visibility
Alt-F9 Quit app
Click Draw with red pen (default)
Shift-Click Blue pen
Ctrl-Click Yellow pen
Wheel-button click Green pen with arrow
Right click Eraser


To install gromit-mpx on Debian or Ubuntu, enter:

# apt install gromit-mpx


If a videoconference presenter has the most basic requirement for an annotation tool, for instance, to draw meeting participants' attention to an area of the screen, gromit-mpx fits the bill well. Its handy hotkeys make annotation more seamless and speedy than the clunky toolbar used by more feature-complete apps, even Zoom.

Thursday, May 14, 2020

Joplin vs Orgzly as note-taking to-do apps

This post evaluates 2 note-taking, to-do list managers: Joplin and org-mode/Orgzly. Both are free, open-source, cross-platform software.

As an avid emacs user, I have always used org-mode on my Linux desktop to take notes and compile my to-do lists. So much so, I held out as long as possible before I switched to another tool that could actually run on Android. Org-mode as an emacs tool did not support Android at the time. Painful as it was, I replaced org-mode with the cross-platform tool Joplin.

Joplin served me very well on both Linux and Android platforms…until I came across an Android app named Orgzly. Org-mode and Orgzly share the same plain text file format, and according to Orgzly documentation, 'files generated by Orgzly might differ in the amount of white space … Any other difference would be considered a serious bug.' File compatibility means that you can edit your tasks and notes using org-mode on Linux and Orgzly on Android.

One key difference between org-mode and Orgzly is how you edit the shared underlying files. Using org-mode, you edit the text files directly inside emacs the text editor. In contrast, you use Orgzly's GUI for editing.

Below, I compare Joplin and org-mode/Orgzly.


You can run Joplin in 3 ways:
  1. as a desktop app on Linux, Windows or macOS,
  2. as a mobile app on Android or iOS, and
  3. as a terminal program on Linux, FreeBSD, macOS or Windows.
I used both its Linux desktop version as well as the Android mobile version, and had no problem vouching for Joplin.

Orgzly runs on Android only (no iOS version yet). For non-mobile platforms, you will need to run org-mode within the emacs editor. Although it has been done before, converting to emacs just to use org-mode may be an overkill for most people.

On portability, Joplin has a definite advantage over org-mode/Orgzly.


Mobile versions of Joplin can be installed via the respective Google and Apple app stores. Installing it on a desktop (Linux, Windows, macOS) is just as convenient. Joplin is available to download from the standard repository of many Linux distributions including Debian. You can also download the AppImage version on Joplin's website.

Orgzly can be installed on Android using either Google Play or F-Droid, the repository for free and open-source Android apps. Org-mode, the desktop counterpart, is now part of emacs: installing emacs automatically installs org-mode.

It is a tie.

Data import/export

Unless you are using a note-taking to-do app for the first time, you will want to easily import any data from your existing app into the new app. Conversely, to prevent vendor lock-in to any 1 app, you want to be able to export data in a format that other apps can easily import. One such format is ENEX, the file format for Evernote, the app with arguably the largest installed user base.

Joplin can import ENEX files, but cannot export to the same. In recompense, you can import and export data in Markdown, PDF and JSON formats.

Orgzly currently only supports the import of org-mode files, and does not support any import or export of third-party file formats.

The clear winner is Joplin.


Both Joplin and Orgzly are minimalistic (even spartan in the case of Orgzly) but highly functional in their user interface design.

To their credit, both offer dark mode, i.e., the ability to set the background to dark.

Joplin has a slight edge over Orgzly in aesthetics.

Winner: Joplin.

Cloud storage

Both Joplin and Orgzly support data storage on popular cloud platforms. Cloud storage enables you to access your tasks and notes from multiple devices and platforms.

Some cloud platforms provide custom API that client apps such as Joplin and Orgzly can use to make connections. There is a cost to using API: the client app needs to write custom code for each cloud service.

The advent of the WebDAV protocol has created a level playing field for apps that need to exchange data over the Internet. Client apps only need to write the WebDAV interface once to support access to all WebDAV-compliant cloud services.

Joplin supports Dropbox and OneDrive via native API, and Nextcloud via the WebDAV protocol. Note that with OneDrive, upload files are restricted to a maximum size of 4 MB, which is relatively low if you are attaching large multimedia files.

Orgzly supports Dropbox through native API and Nextcloud and other cloud services through WebDAV.

A tie.


As discussed above, both apps can store data in the cloud. Data is regularly transmitted in the cloud to keep client apps synchronized.

Joplin data transmission is encrypted end-to-end; Orgzly, unencrypted.

With Joplin, your privacy is protected: not even Joplin developers or your cloud host such as Dropbox can access your encrypted data.

This may well be the killer feature that swings the pendulum all the way in favor of Joplin for most people.

Project viability

The 2 projects are very similar on this point – both stable and actively maintained by a team of one major developer. So, don't expect major new features every few months.

For mature applications like note-taking to-do list managers, that may actually be a benefit.

According to Google Play, both apps are downloaded roughly the same number of times(50,000+). Their numbers pale in comparison to the behemoth Evernote (100,000,000+). However, both projects have reached a critical mass in their respective user communities.

A tie.


Both Joplin and org-mode/Orgzly are more than capable to do the basic job. But Joplin is the eminently obvious overall winner … unless you are a hardcore emacs fan.