Jakob Gillich Personal blog

Smaller Moment.js

Moment.js is a great JavaScript library that makes working with time a lot easier. I totally love it, but there is one problem: It is huge! That is because moment-with-langs.js includes all supported languages, and they support a lot of them!

Now the good news is that you can build a custom version of Moment.js with just the languages you need. To do this, you need Git, Node.js and Grunt - but you have these already, right?

Let’s start by fetching the repository and installing dependencies:

git clone https://github.com/moment/moment.git
cd moment
git checkout master
npm install

Now simply run the below command with a comma seperated list of all languages you need (German and French in this example) - all languages in the lang/ folder can be embedded.

grunt release --embed_languages=de,fr

Note that english is always included and there is not way to change that. When the command finishes, you’ll find your custom version at min/moment-with-customlangs.js.

The resulting file size is around 70 KB with a single language - much better than the default 270 KB.

My First FreeBSD Port

I’ve recently created a FreeBSD port for Ghost. Overall, it was a pretty frustrating experience. The biggest issue was that there’s just so few resources on the web about it.

Yes, the official documentation is pretty good. But on the other hand, it actually answered very few of my questions. One example: Ports contain a plist file that lists all files that belong to it. There is documentation about it and it also has a section about dynamic plists. It tells you when you can use a dynamic plist, but it’s missing any instructions on how you actually implement one.

Since FreeBSD is not as popular as Linux, there are a lot less forum/blog posts and mailing list entries. You really can’t blame FreeBSD for that, but it makes finding solutions a lot harder. That’s also one of the reasons why I’m writing this.

But there is one thing that has helped me a lot: Reading other ports. You will gain a lot from that as most ports are written by experienced contributors. And if you struggle too much, there are a lot of helpful people hanging around on the forums and mailing lists.


There were a few challenges I had to face. Once I even fixed a issue by switching to a fresh jail and abandoning the old. So please - if you are a newbie, use a jail so you don’t mess up your production system!

Extract to Subdirectory

The Ghost source code is a zip file that contains no sub folder. Doesn’t sound like a big deal, right? Actually, it is. If the source code extracts directly into ${WRKDIR}, it is pretty hard moving it into ${STAGEDIR} without specifying every single file because the latter directory is inside the former.

But this can be solved by using a custom do-extract:

    ${MKDIR} ${WRKSRC}
    ${LOCALBASE}/bin/unzip -d ${WRKSRC} ${DISTDIR}/${DISTFILES}

Set correct permissions

After extracting the files, they were set to 100. Not very useful, but using @mode 755 in the plist fixed it. You can also use @owner somebody and @group somegroup if you want to.

Dynamic plist

Implementing a dynamic plist wasn’t that hard. You simply need to specify PLIST= ${WRKDIR}/plist and then generate this file in the pre-install target like this:

cd ${WRKSRC}; ${FIND} . -type f | cut -c2- \
    | ${SED} 's|^|www/ghost|' \
    | ${SORT} -r >> ${PLIST}
${ECHO_CMD} "@comment directories" >> ${PLIST}
cd ${WRKSRC}; ${FIND} . -type d | cut -c2- \
    | ${SED} 's|^|@dirrm www/ghost|' \
    | ${SORT} -r >> ${PLIST}

This uses find to get a list of files, corrects the path and appends them to the plist. That’s all you have to do.

Learn from me

You can find the full code of my port in the Ghost-Config repository. Feel free to check it out, study it and send me your improvements.

Automated Backups on FreeBSD

I recently had to think about a backup strategy. The FreeBSD manual has an entry describing the method I used to use in the past:

19.10.6. Do Nothing

“Do nothing” is not a computer program, but it is the most widely used backup strategy. There are no initial costs. There is no backup schedule to follow. Just say no. If something happens to your data, grin and bear it!

If your time and data is worth little to nothing, then “Do nothing” is the most suitable backup program for the computer. But beware, FreeBSD is a useful tool and over time it can be used to create a valuable collection of files.

To mount my backup space at Hetzner automatically, I used Samba and this fstab entry:

//u12345@your-backup.de/backup /mnt/backup smbfs rw,late,-N,-I188.40.5.173

There is a post on the FreeBSD forums about this that I can’t find anymore, but the missing space between the -I option and the IP address is not a typo!

The -N option tells Samba to not ask for a password so you need to add it to the /etc/nsmb.conf:


Both the hostname and the username must be in uppercase!

The recommended tools for doing backups are dump (creates backups) and restore (restores backups).

Dump can create full and incremental backups. Unlike rsync, it will only backup mountpoints (aka devices), not directories. If you need more flexibility, you should take a look at rsync instead.

To do incremental backups, dump uses so called dump levels. Here is the explanation from the manpage:

A level 0, full backup, guarantees the entire file system is copied (but see also the -h option below). A level number above 0, incremental backup, tells dump to copy all files new or modified since the last dump of any lower level. The default level is 0.

What this means is that dump stores a date when a backup finished and which dump level has been used and uses these to do further incremental backups. Here is how I do my automatic backups via cron:

0 4 * * 0 /sbin/dump -0uLa -f /mnt/backup/root0 /
0 4 * * 1 /sbin/dump -1uLa -f /mnt/backup/root1 /
0 4 * * 2 /sbin/dump -2uLa -f /mnt/backup/root2 /
0 4 * * 3 /sbin/dump -3uLa -f /mnt/backup/root3 /
0 4 * * 4 /sbin/dump -4uLa -f /mnt/backup/root4 /
0 4 * * 5 /sbin/dump -5uLa -f /mnt/backup/root5 /
0 4 * * 6 /sbin/dump -6uLa -f /mnt/backup/root6 /

Each day of a week at 4 a.m., this will execute dump.

  • On Sundays (day 0), it will do a full backup (dump level 0) of / and store it at /mnt/backup/root0.
  • On Mondays (day 1), it will do a incremental level 1 backup including all changes since dump level 0 and store it at /mnt/backup/root1.
  • On Tuesdays (day 1), it will do a incremental level 2 backup including all changes since dump level 1 and store it at /mnt/backup/root2.

So what you get is a full backup every sunday and backups including the daily changes every other day of the week.

About the options:

  • u: Tells dump to update the dumpfile at /etc/dumpdates automatically. Required for incremental backups to work.
  • L: Tells dump that it is working on a live file system so it will create a snapshot.
  • a: Do not ask any questions.
  • f: Target file.

For a complete explanation of these options, read the dump manpage.

Fix your JAVA_HOME

Trying to run one of JetBrain’s IDE’s (WebStorm in my case), you might get this error message:

ERROR: Cannot start WebStorm
No JDK found. Please validate either WEBIDE_JDK, JDK_HOME or JAVA_HOME environment variable points to valid JDK installation.

It is crazy how long it took me to find a solution for this. Most answers on the web are talking about Oracle’s proprietary Java; I wanted to run it using OpenJDK instead.

But thanks to this StackOverflow answer I was able to solve it. A pretty universal way to set $JAVA_HOME is this:

JAVA_HOME=$(readlink -f /usr/bin/java | sed "s:bin/java::")

On Fedora, $JAVA_HOME would now look like this:

$ echo $JAVA_HOME

But this path will change all the time.

ownCloud Client Configuration Folder

Every time ownCloud screws up, I have to delete the configuration files to reset it completely. The location where these files are stored isn’t really documented anywhere, so here is the path you have to rm:


Ghost on FreeBSD

Ghost has been released to the public today. Finally! I could not try it earlier because I wasn’t one of the Kickstarter backers. When I discovered the project, it was already way over their initial funding goal so I saw no reason to fund it.

If you never heard of it: It is a simple blogging software. Similar to Wordpress, but it looks better, has fewer features and it’s written in Node.js instead of PHP.

After trying it out locally, I installed it in a jail on my FreeNAS box. The installation is not completely straightforward, here is what you have to do:

1. Install the necessary dependencies

Here is a list of all dependencies that you need:

  • www/node
  • www/npm
  • databases/sqlite3

Install them from the ports collection or the package manager of your choice.

Ghost requires the node-sqlite3 package, and that one caused me some problems. To build and install it properly, we will need the node-gyp package from npm:

npm install node-gyp -g

2. Get Ghost and install more dependencies

Now we have to download and extract Ghost. Go to the download page and copy the latest download link, I will not keep the one below up to date.

fetch http://ghost.org/zip/ghost-0.3.2.zip
mkdir ghost
unzip -d ghost ghost-0.3.2.zip
cd ghost

This step is different from the official instructions. We have to explicitly pass the path of our sqlite3 installation to npm install (all third-party software is installed to /usr/local by default on FreeBSD).

npm install --production --sqlite=/usr/local

3. Adjust Configuration

We are almost done! Before running it, you have to create and open the config.js with your favorite text editor.

cp config.example.js config.js
ee config.js

Then find the production section and set these properties to whatever you want:

  • url
  • host
  • port

url is used for all frontend links, very useful if you run Ghost through a reverse proxy.

Now we are ready to run it using the npm start command from within the Ghost directory. If you plan to run it in production mode, execute setenv NODE_ENV production first.

4. Gain Control

Forever is a nice tool that keeps your node processes running, well, forever. It’s like the service command for Node.js. Thanks to npm, installation is easy:

npm install -g forever

To manage the process, I wrote a little service script. Put this at /usr/local/etc/rc.d/ghost and make it executeable:

Before the above script will work, you also have to do this:

  • Add the ghost user
  • Give the user write access to the database: chown -R ghost content/data/
  • Same for the logfile: chmod 777 /var/log/ghost
  • Install security/sudo

Now you have a service that integrates very well and in a secure way with the rest of the system:

  • Autostart on boot: Add ghost_enable="YES" to your /etc/rc.conf
  • Start manually: service ghost [one]start
  • Stop manually: service ghost [one]stop
  • Logs are stored at /var/log/ghost

I will probably create a port that will automate the whole process soon (just need to learn how to do it first). And please note that the one above is the first service script I ever wrote, it may break your system! If you know how to improve it, please leave a comment.

HTTPS Almost Everywhere

I have a free SSL certificate from StartSSL for all my domains. To force HTTPS everywhere in Apache’s httpd, I use the following virtual host:

<VirtualHost _default_:80>
  RewriteEngine On
  RewriteCond %{HTTPS} off
  RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}

Because it is _default_, we don’t need a server name and it is still possible to create regular HTTP hosts by adding another virtual host. And all parameters are of course preserved when redirecting.