keter: Web application deployment manager, focusing on Haskell web frameworks

This is a package candidate release! Here you can preview how this package release will appear once published to the main package index (which can be accomplished via the 'maintain' link below). Please note that once a package has been published to the main package index it cannot be undone! Please consult the package uploading documentation for more information.

[maintain] [Publish]

Hackage documentation generation is not reliable. For up to date documentation, please see:

[Skip to Readme]


Versions 0.1,, 0.2.0,,,, 0.3.0,, 0.3.1, 0.3.2, 0.3.3, 0.3.4,,, 0.3.5,,,,, 0.3.6,, 0.4.0, 1.0.1,,, 1.1.0,, 1.2.0, 1.2.1, 1.3.0, 1.3.1, 1.3.2, 1.3.3, 1.3.4, 1.3.5,,,, 1.3.6, 1.3.7,, 1.3.8, 1.3.9,,, 1.3.10,, 1.4.0,, 1.4.1,, 1.4.3,,, 1.5, 1.6, 1.6, 1.7, 1.8, 1.8.1, 1.8.2, 1.8.3, 1.8.4, 1.9, 2.0, 2.0.1
Change log
Dependencies aeson, array, async, attoparsec (>=0.10), base (>=4 && <5), blaze-builder (>=0.3 && <0.5), bytestring, case-insensitive, conduit (>=1.1), conduit-extra (>=1.1), containers, data-default, directory, filepath, fsnotify (>=0.3), ghc-prim, http-client, http-conduit (>=2.1), http-reverse-proxy (>=0.4.2 && <0.7), http-types, indexed-traversable, keter, lifted-base, mtl, network, optparse-applicative, process (>=1.4.3 && <1.7), random, regex-tdfa (>=1.1), stm (>=2.4), system-filepath, tar (>=0.4), template-haskell, text, time, tls (>=1.4), tls-session-manager, transformers, unix (>=2.5), unix-compat (>=0.3 && <0.6), unordered-containers, vector, wai (>=3.2.2), wai-app-static (>=3.1 && <3.2), wai-extra (>=3.0.3 && <3.2), warp, warp-tls (>=3.0.3 && <3.4.0), yaml (>=0.8.4 && <0.12), zlib [details]
License MIT
Author Michael Snoyman
Category Web, Yesod
Home page
Source repo head: git clone
Uploaded by Jappie at 2021-11-09T16:08:27Z



Automatic Flags

Use system-filepath


Use -f <flag> to enable a flag, or -f -<flag> to disable that flag. More info


Maintainer's Corner

For package maintainers and hackage trustees

Readme for keter-1.6

[back to package description]

Githbu actions build status

Deployment system for web applications, originally intended for hosting Yesod applications. Keter does the following actions for your application:

Keter provides many more advanced features and extension points. It allows configuration of static hosts, redirect rules, management of PostgreSQL databases, and more. It supports a simple bundle format for applications which allows for easy management of your web apps.

[1]: The health check happens trough checking if a port is opened. If your app doesn't open a port after 30 seconds it's presumed not healthy and gets a term signal.

Quick Start

To get Keter up-and-running quickly for development purposes, on an Ubuntu system (not on your production server), run:

wget -O - | bash

(Note: This assumes you already have keter installed via cabal.) (Note: you may need to run the above command twice, if the shell exits after apt-get but before running the rest of its instructions.) This will download and build Keter from source and get it running with a default configuration. By default Keter will be set up to support HTTPS and will require you to provide a key and certificate in /opt/keter/etc. You can disable HTTPS in /opt/keter/etc/keter-config.yaml by commenting the certificate and key lines.

This approach is not recommended for a production system. We do not recommend installing a full GHC toolchain on a production server, nor running such ad-hoc scripts. This is intended to provide a quick way to play with Keter, especially for temporary virtual machines. For a production system, we recommend building the keter binary on a separate system, and tracking it via a package manager or similar strategy.

Bundling your app for Keter

  1. Modify your web app to check for the PORT environment variable, and have it listen for incoming HTTP requests on that port. Keter automatically assigns arbitrary ports to each web app it manages. When building an app based on the Yesod Scaffold, it may be necessary to change the port variable in config/settings.yaml from YESOD_PORT to PORT for compatibility with Keter.

  2. Create a file config/keter.yaml. The minimal file just has two settings:

    exec: ../path/to/executable

    See the bundles section below for more available settings.

  3. Create a gzipped tarball with the config/keter.yaml file, your executable, and any other static resources you would like available to your application. This file should be given a .keter file extension, e.g. myapp.keter.

  4. Copy the .keter file to /opt/keter/incoming. Keter will monitor this directory for file updates, and automatically redeploy new versions of your bundle.

Examples are available in the incoming directory.


Building keter for Debian, Ubuntu and derivatives

Eventually, I hope to provide a PPA for this (please contact me if you would like to assist with this). For now, the following steps should be sufficient:

First, install PostgreSQL:

sudo apt-get install postgresql

Second, build the keter binary and place it at /opt/keter/bin. To do so, you'll need to install the Haskell Platform, and can then build with cabal. This would look something like:

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

Third, create a Keter config file. You can view a sample at

Optionally, you may wish to change the owner on the /opt/keter/incoming folder to your user account, so that you can deploy without sudoing.

sudo mkdir -p /opt/keter/incoming
sudo chown $USER /opt/keter/incoming

Building keter for Redhat and derivatives (Centos, Fedora, etc)

First, install PostgreSQL:

sudo dnf install postgresql

Second, build the keter binary and place it at /opt/keter/bin. To do so, you'll need to install the Haskell Platform, and can then build with cabal. This would look something like:

sudo dnf install haskell-platform
cabal update
cabal install keter
sudo mkdir -p /opt/keter/bin
sudo cp ~/.cabal/bin/keter /opt/keter/bin

Third, create a Keter config file. You can view a sample at

Configuring startup

For versions of Ubuntu and derivatives 15.04 or greater and Redhat and derivatives (Centos, Fedora, etc) use systemd

# /etc/systemd/system/keter.service

ExecStart=/opt/keter/bin/keter /opt/keter/etc/keter-config.yaml


Finally, enable and start the unit (Note: You may need to disable SELinux):

sudo systemctl enable keter
sudo systemctl start keter

Verify that it's actually running with:

sudo systemctl status keter

Optionally, you may wish to change the owner on the /opt/keter/incoming folder to your user account, so that you can deploy without sudoing.

sudo mkdir -p /opt/keter/incoming
sudo chown $USER /opt/keter/incoming

For versions of Ubuntu and derivatives less than 15.04, configure an Upstart job.

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

# NB: keter writes logs to /opt/keter/log, but some exceptions occasionally
# escape to standard error. This ensures they show up in system logs.
console output

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

Finally, start the job for the first time:

sudo start keter


An application needs to be set up as a keter bundle. This is a GZIPed tarball with a .keter filename extension and which has one special file: config/keter.yaml. A sample file is available at

Keter also supports wildcard subdomains and exceptions, as in this example configuration:

exec: ../
    - Hello
    - World
    - 1
    - "*"
    - host:
      root: ../static
    - from:

Due to YAML parsing, wildcard hostnames will need to be quoted as above. Wildcard hostnames are not recursive, so must be explicitly added as an extra hostname in the above example, or alternatively, *.* would cover all host names two levels deep. It would not cover host names only one level deep, such as In this manner, wildcard hostnames correspond to the manner in which SSL certificates are handled per RFC2818. Wildcards may be used in only one level of a hostname, as in foo.*

Full RFC2818 compliance is not present - f* will not be handled as a wildcard with a prefix.

A sample Bash script for producing a Keter bundle is:

#!/bin/bash -ex

cabal build
strip dist/build/yesodweb/yesodweb
rm -rf static/tmp
tar czfv yesodweb.keter dist/build/yesodweb/yesodweb config static

For users of Yesod, The yesod executable provides a keter command for creating the bundle, and the scaffolded site provides a keter.yaml file.


In order to deploy, you simply copy the keter bundle to /opt/keter/incoming. To update an app, copy in the new version. The old process will only be terminated after the new process has started answering requests. To stop an application, delete the file from incoming.

PostgreSQL support

Keter ships by default with a PostgreSQL plugin, which will handle management of PostgreSQL databases for your application. To use this, make the following changes:

  postgres: true
     - server: remoteServerNameOrIP
       port: 1234

Different webapps can be configured to use different servers using the above syntax. It should be noted that keter will prioritize it's own postgres.yaml record for an app. So if moving an existing app from a local postgres server to a remote one (or switching remote servers), the postgres.yaml file will need to be updated manually.

Keter will connect to the remote servers using the postgres account. This setup assumes the remote server's pg_hba.conf file has been configured to allow connections from the keter-server IP using the trust method.

(Note: The plugins configuration option was added in v1.0 of the keter configuration syntax. If you are using v0.4 then use postgres: true. The remote-postgres server syntax was added in v1.4.2.)

Known issues

Stanza-based config files

Starting with Keter 1.0, there is an alternate format for application Keter config files, which allows much more flexibility in defining multiple functionality for a single bundle (e.g., more than one web app, multiple redirects, etc). This README will eventually be updated to reflect all various options. In the meanwhile, please see the following examples of how to use this file format:

Multiple SSL Certificates

Keter is able to serve different certificates for different hosts, allowing for the deployment of distinct domains using the same server. An example keter-config.yaml would look like::

root: ..
  - host: "*4" # Listen on all IPv4 hosts
    port: 80
  - host:
    key: key.pem
    certificate: certificate1.pem
  - host:
    key: key.pem
    certificate: certificate2.pem

An alternative way to make this possible is adding the following ssl: argument to the keter.yaml file in your Yesod app's config folder as follows:

    - type: webapp
      exec: ../yourproject
        key: /opt/keter/etc/cert/yourproject.key
        certificate: /opt/keter/etc/cert/yourproject.crt
        chain-certificates: []

If you don't have your certificates bundled in one .crt file, you should add the other certificates in the following order

          - /opt/keter/etc/middle.crt
          - /opt/keter/etc/root.crt

This way you can designate certificates per Yesod App while still having one SSL certificate in your main /opt/keter/etc/keter-config.yaml for your other Yesod apps to default to if they don't have this ssl: argument in their config/keter.yaml.

NOTE: If you get an error that a Bool was expected instead of an Object when adding the ssl: argument, then for this to work you might need to build Keter from Github, because at the time of writing the version of Keter on Hackage does not have this functionality. Just clone or download this repository and build it using stack.



If you are interested in contributing, see for a complete testing workflow. If you have any questions, you can open an issue in the issue tracker, ask on the #yesod freenode irc channel, or send an email to