Mar 18,
2017

Lighttpd and Ephemeral Logs

Recently I've found out that lighttpd doesn't start and bails out with an error if it can't find its log file.

The backstory is that my home NAS uses an Intel Z-U130 USB SSD as the system disk1 and unfortunately it's tragically slow, especially writing data. According to Intel documentation the write speed is rated at 24 GiB/s, I've never bothered to measure it but it feels way slower.

Anyway, to offset the subjective slow write speed and somewhat extend the lifespan of the device, I decided to mount /tmp and /var/log to the RAM file-system.

First of all, I'm not suggesting to indiscriminately mount log files on tmpfs, the reader should evaluate the pros and the cons of such arrangement starting from considering RAM usage and clearly the ephemeral nature of log files stored on tmpfs.

Another thing that I'm not suggesting is avoiding to save the contents of /var/log during shutdown.

In my case I don't bother, so it's not a surprise that at boot time the log directory is empty and lighttpd fails to start. The fix is trivial tho, before launching the daemon the required path needs to be created.

Enough Ramblings

A simple way to do it is using systemd and a sensible way to do it is appending the required actions in a local configuration file instead of modifying the service file directly. In this way changes are preserved when installing new versions of the package.

This is accomplished by creating a directory with the same name of the service, in this specific case /etc/systemd/system/lighttpd.service.d and storing inside a file ending with the .conf suffix with the required instructions.

For example local.conf will do:

[Service]
# When mounting log on tmpfs, creating the lighttpd log path 
ExecStartPre=/bin/sh -c 'mkdir -p /var/log/lighttpd && chown www-data:adm /var/log/lighttpd'

As a side note, on Debian the canonical way to configure the use of tmpfs is using the /etc/defaults/tmpfs file but it looks like it's missing an option for logs. I reverted to use the mount options in the /etc/fstab file.

# log on tmpfs
tmpfs    /var/log        tmpfs defaults,mode=0755 0 0
tmpfs    /var/log/apt    tmpfs defaults,mode=0755 0 0

To the astute reader it would be clear that this post is not about how to use lighttpd with log mounted as tmpfs but more as a example to a proper way to do it with systemd, as I can probably find half a dozen different ways to do it.

Challenge Accepted

A friend, after reading a draft of this post, invited me to enumerate at least 6 different ways to do it.

OK, let's see:

  • editing rc.local

  • putting a script in /etc/init.d

  • using a shell helper/trampoline script

  • exploiting cron (gnu cron has a @reboot directive)

  • using overlayfs 2

  • modifying the source

Mic drop.

Picking up the mic from the floor: apparently, the proper way to fix it with systemd3 is to create a file in /etc/tmpfiles.d directory with the necessary parameters. In this case this is the content of my lighttpd-log.conf file:

D /var/log/lighttpd/ 0755 www-data adm

The details are explained on the freedesktop.org site.

Mic drop again.


  1. should we stop calling them disks? ↩︎

  2. Debian Jessie's default kernel is without overlayfs support ↩︎

  3. something similar happened with ConsoleKit when mounting /var/log on tmpfs ↩︎

 
 

Mar 02,
2017

Wi-Fi and Neighbors

Some time ago I started to have a feeling that the time required to move files using Wi-Fi between my NAS and PCs has increased. About this, I noticed that the reported wireless link speed of my systems was 145 Mbit/s but I was reasonably sure that in the past that value was 300 Mbit/s.

My access point is a relatively old TP-Link model that runs a somewhat recent version of OpenWRT that I compiled and flashed, so yes, to the aficionado reader this may resemble my typical tinkering scenario, only this time I didn't touched the thing for a year or more.

According to the OpenWRT's Atheros chip-set documentation, for 802.11n the /etc/config/wireless configuration file looks correct:

config wifi-device 'radio0'
option type 'mac80211'
option hwmode '11g'
option path 'pci0000:00/0000:00:00.0/0000:01:00.0'
option channel 'auto'
option htmode 'HT40'
option txpower '15'
option country 'IT'

So 802.11n is basically 802.11g plus HT 1 mode with 40 MHz channel width, but strangely all the NICs in my home were connecting using only a width of 20 MHz.

Good Neighborhoods

Until yesterday I was unaware that there is a part of the 802.11 protocol that it's called "20/40 coexistence" or "good neighbor policy", so in few words, when a different AC is found, to avoid contemption of the Wi-Fi media, the channel's width is kept at 20 instead of 40 MHz.

I suppose, in the past few months, one or more of my neighbors has added or changed a Wi-Fi router and now my AC is correctly occupying less bandwidth.

I wanted to confirm it was really the case, and yes, using the OpenWRT's noscan option and a throughput test with iperf3 confirmed it's the presence of nearby ACs that reduces my wireless link speed.

Unfortunately the noscan is not a reasonable option2 as I can force the larger channel size but I still can't avoid contemption3 with the other ACs, so it looks like I need to move to the 5 GHz band and, with the occasion upgrade to 802.11.ac, with all the considerations that this imply.


  1. High Throughput ↩︎

  2. pun wasn't intended ↩︎

  3. unless I wrap the walls with tinfoil, Wi-fi blocking paint or special wallpaper ↩︎

 
 

Feb 10,
2017

Re-Design Reprise: Theme Tweaks

I've made an effort to reduce the size of the static assets of my theme to speed up the page loading on mobile platforms; my target was a normal G2 connection, so 300 ms of latency and 250 Kb/s of downstream bandwidth.

The elephant in the room was the JQuery library required by Bootstrap, in my case was used only for the collapsible navigation bar, so it was the first thing I tried to tackle. I looked to compile only the required module, but the gain was minimal. Next I tried automatic tools for dead code elimination and "three shaking" but they didn't produced a gain either. Fortunately before I started to write a solution by my own, I've found an actively developed library created to replaced JQuery as a drop in replacement, so with the bootstrap.native library it passed from 120 KByte uncompressed to less than 3.5 KByte uncompressed.1

I slightly modified the Javascript to not be completely broken on IE8, still some glitches remain, and arranged the theme to not be completely unusable if Javascript is disabled.

Jinja templates

I used the occasion to fix an ugly bit that was present in the previous iteration. The current wisdom is to put all the Javascript functions at the end of a page to speed up the rendering, but with my theme, when an images gallery was added to an article, a Javascript function necessary to initialize the gallery unfortunately ended in the middle of the index page, as I couldn't find a way with Jinja to pass a value from a child template to a parent template if the value was defined inside an include.

I was stuck forever with this and I suspect a bug as it's supposed to work according to Jinja's documentation. I ended up using a workaround abusing the global context:

{% set _ = gallery_required.append(gallery_name) %}

It's not a clean approach and it risks to not work in a future version, but I couldn't find a better solution. When I have some time I need to isolate a test case and report it upstream.

Unfortunately the current stable version (2.9) fixed a bug that enforce the scoping of variables modified inside code blocks and it broke the rendering of my archives.html page. Considering the design's decisions, I'm starting to doubt that Jinja is flexible enough for a static site generator.

Anyway I rearranged the archives code without values passed using variables and now should be fixed for the foreseeable future:

{% for year, articles in dates| groupby('date.year')| reverse %}
    {{ year }}
    {% for article in articles %}
        {{ article.date.strftime("%d %B") }} - {{ article.title }}
    {% endfor %}
{% endfor %}

Playing with Fonts

I've experimented with WebFonts in the theme, i.e. if the primary font choice wasn't installed in the system, a webfont was used as a secondary choice2. I've verified that Firefox doesn't show glitches but testing it with Chrome there was an ugly FOIT when loading the index page, so for the platforms that don't have Georgia installed I'm sorry, you have to use your system version of a serif font.

Critical

Another thing that I've played with is what is called "critical CSS".

There is a Google developer page where it's suggested to inline in the page's header tag only the portion of CSS necessary to style the elements displayed on the view-port3, defer the loading of the full CSS file as one of the last operations and finally inject it in the page when the file is downloaded.

I've implemented the thing, but considering that the full CSS when minified it's only about 20 KByte, I've toyed with the idea to put all my CSS inline.

Things That Need Fixing

There's still a thing that's broken: Bootstrap doesn't do anything special with the abbr HTML tag4, so on devices with touchscreen, abbreviations don't work. It's in the to do list.

Conclusions

The final tuning was to enable HTTP/2, gzip compression and cache expiration for the static assets and moving the page encoding from the HTML to the web server headers.

I haven't extensively bench-marked the page loading, but throttling the network parameters to simulate a regular 2G connection, the process of loading and displaying an index page with a cold cache is completed in less than two seconds, the painting of the view-port above the fold happens after less than 700 ms. On a desktop it's near a half second, not bad considering that the server I'm using is now in the East of North America.


  1. plus nearly other 3.5 KB of polyfill functions for older browsers ↩︎

  2. I like the Old-Style Figures ↩︎

  3. they call it the "above the fold" ↩︎

  4. Bootstrap issue 5373 ↩︎