My personal website
Switch branches/tags
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Type Name Latest commit message Commit time
Failed to load latest commit information.



Lambdar is still in early development stage and missing some features.

This is the repository of my personal website, Lambdar. Lambdar is developed using Yesod, a web framework for Haskell.


  • Deadly simple blog app for me
  • Support multi-language articles
  • Support GitHub-Flavored Markdown to write articles
  • Support command-line management tools to publish articles


To develop Lambdar, you need to install GHC and Yesod on your machine. The following table shows which version of software you need.

Name Version Note
GHC 7.10.3 Haskell compiler

You can read a great book for Yesod on its website. The book helps you a lot while developing a web application. Yesod wiki is also a useful resource.

Setup on Mac OS X

To install GHC on Mac OS X, you can use Homebrew:

$ brew update
$ brew install ghc cabal-install

To install Yesod binaries, use Cabal:

$ # You may change the following line depending on your shell setup
$ echo 'export PATH=$HOME/.cabal/bin:$PATH' >> ~/.profile
$ cabal update
$ cabal install cabal-install
$ cabal install yesod-bin

Server Setup

Lambdar is deployed using Keter, a web application deployment manager. Currently, Lambdar is only tested on Ubuntu 14.04.2 LTS.

Setup on Ubuntu 14.04.2 LTS

To install Keter, follow the instructions on the repo:

$ sudo apt-get install haskell-platform
$ cabal update
$ cabal install keter
$ sudo mkdir -p /opt/keter/bin
$ sudo cp ~/.cabal/bin/keter /opt/keter/bin
$ sudo mkdir -p /opt/keter/incoming
$ sudo chown $USER /opt/keter/incoming

You also need to follow the Lambdar-specific setup:

$ # To ensure Sqlite database file is persistent through deployment
$ sudo mkdir -p /opt/keter/database
$ # Directory for scripts needed to manage production database
$ sudo mkdir -p /opt/keter/scripts
$ sudo chown $USER /opt/keter/scripts

Create a Keter config file /opt/keter/etc/keter-config.yaml (sample):

root: ..
    - host: "*4" # Listen on all IPv4 hosts

You may want to set up an Upstart job for keter:

# /etc/init/keter.conf
start on (net-device-up and local-filesystems and runlevel [2345])
stop on runlevel [016]

console none

exec /opt/keter/bin/keter /opt/keter/etc/keter-config.yaml

That's it. You can run Keter by:

$ sudo start keter

Compilation & Deployment

We don't want to compile a web app on server as mentioned in Yesod book. However, my development machine runs Mac OS X while the server machine runs Ubuntu. Lambdar uses Docker to avoid this problem by compiling in a Ubuntu-based container.

The first step is to create a Docker image:

$ cd /path/to/lambdar/repo
$ docker build -t builtinnya/lambdar .

Then, every time you want to deploy Lambdar, all you need to do is:

$ cd /path/to/lambdar/repo
$ ./deploy

NOTE: You need to set up Keter on server and SSH config for 'lambdar' host

Local SSH config ~/.ssh/config will be something like this:

Host lambdar
     User nya
     IdentityFile ~/.ssh/id_rsa
     Port 443


Articles are written in GitHub-Flavored Markdown and converted to HTML when registering to database. Lambdar provides command-line management tools to create, read, update, and delete articles, languages, and tags.

Management scripts (e.g. app/article.hs) are compiled into binaries (e.g. dist/build/article/article) and deployed to server. You have to invoke these binaries on server to access production database. This is what manage script takes care of.


To list all currently available languages:

$ ./manage lang list

To add a new language:

$ ./manage lang add SLUG NAME

SLUG becomes a part of URL. NAME is a displayed name.

To update a language's displayed name:

$ ./manage lang update SLUG NAME

To delete a language:

$ ./manage lang delete SLUG


To list all currently available tags:

$ ./manage tag list

To add a new tag:

$ ./manage tag add SLUG NAME [DESCRIPTION]

SLUG becomes a part of URL. NAME is a displayed name. DESCRIPTION is optional.

To update a tag's name and description:

$ ./manage tag update SLUG [--name NAME] [--description DESCRIPTION]

To delete a tag:

$ ./manage tag delete SLUG


To list all currently registered articles:

$ ./manage article list

To add a new article:

$ ./manage article add LANG SLUG TITLE SOURCEFILE

LANG is the language slug of the article. SLUG becomes a part of URL. TITLE is the title of the article. SOURCEFILE is relative path to a markdown file.

To update article's meta data:

$ ./manage article update LANG SLUG [--title TITLE]

To attach tags to an article:

$ ./manage article tag SLUG [--tags TAGS]

TAGS is a comma-separated list of tag slugs to be attached to the article.

To update article's content:

$ ./manage article content-update LANG SLUG [--sourcefile SOURCEFILE]


  • Automate database backup
  • Implement search
  • Implement RSS feed


Copyright © 2015-present Naoto Yokoyama

Distributed under the MIT license. See the LICENSE file for full details.