• Stars
    star
    259
  • Rank 157,669 (Top 4 %)
  • Language
    Haskell
  • License
    MIT License
  • Created over 12 years ago
  • Updated 4 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Web app deployment manager

Githbu actions build status

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

  • Binds to the main port (usually port 80) and reverse proxies requests to your application based on virtual hostnames.
  • Provides SSL support if requested.
  • Automatically launches applications, monitors processes, and relaunches any processes which die.
  • Provides graceful redeployment support, by launching a second copy of your application, performing a health check[1], and then switching reverse proxying to the new process.

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 - https://raw.githubusercontent.com/snoyberg/keter/master/setup-keter.sh | 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
    host: mydomainname.example.com

    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.

Setup

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 https://github.com/snoyberg/keter/blob/master/etc/keter-config.yaml.

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 https://github.com/snoyberg/keter/blob/master/etc/keter-config.yaml.

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
[Unit]
Description=Keter
After=network.service

[Service]
Type=simple
ExecStart=/opt/keter/bin/keter /opt/keter/etc/keter-config.yaml

[Install]
WantedBy=multi-user.target

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

Additionally, you may want to enable logging to stderr by disabling rotate-logs in config/keter.yaml, since systemd will automatically capture and manage stderr output for you:

rotate-logs: false

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]
respawn

# 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

NixOS

Keter is integrated within nixos:

https://search.nixos.org/options?channel=22.11&show=services.keter.keterPackage&from=0&size=50&sort=relevance&type=packages&query=keter

There is an example that integrates yesod into keter with NixOS here: https://github.com/jappeace/yesod-keter-nix

Bundles

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 https://github.com/snoyberg/keter/blob/master/incoming/foo1_0/config/keter.yaml.

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

exec: ../com.example.app
args:
    - Hello
    - World
    - 1
host: www.example.com
extra-hosts:
    - "*.example.com"
    - foo.bar.example.com
static-hosts:
    - host: static.example.com
      root: ../static
redirects:
    - from: example.com
      to: www.example.com

Due to YAML parsing, wildcard hostnames will need to be quoted as above. Wildcard hostnames are not recursive, so foo.bar.example.com must be explicitly added as an extra hostname in the above example, or alternatively, *.*.example.com would cover all host names two levels deep. It would not cover host names only one level deep, such as qux.example.com. 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.*.example.com.

Full RFC2818 compliance is not present - f*.example.com 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.

Deploying

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:

  • Add the following lines to your config/keter.yaml file:
plugins:
  postgres: true
  • Keter can be configured to connect to a remote postgres server using the following syntax:
plugins:
  postgres: 
     - 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.)

  • Modify your application to get its database connection settings from the following environment variables:

    • PGHOST
    • PGPORT
    • PGUSER
    • PGPASS
    • PGDATABASE
  • The Yesod scaffold site is already equipped to read these environment variables when they are set.

Known issues

  • There are reports of Keter not working behind an nginx reverse proxy. From the reports, this appears to be a limitation in nginx's implementation, not a problem with Keter. Keter works fine behind other reverse proxies, including Apache and Amazon ELB.

    One possible workaround is to add the following lines to your nginx configuration:

    proxy_set_header Connection "";
    proxy_http_version 1.1;
    

    This has not yet been confirmed to work in production. If you use this, please report either its success or failure back to me.

    Additionally, to make sure that nginx does not reset the Host header (which keter uses to choose the right target), you will need to add:

    proxy_set_header Host $host;
    
  • Keter does not handle password-protected SSL key files well. When provided with such a key file, unlike Apache and Nginx, Keter will not pause to ask for the password. Instead, your https connections will merely stall.

    To get around this, you need to create a copy of the key without password and deploy this new key:

    openssl rsa -in original.key -out new.key
    

    (Back up the original key first, just in case.)

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: ..
listeners:
  - host: "*4" # Listen on all IPv4 hosts
    port: 80
  - host: 127.0.0.1
    key: key.pem
    certificate: certificate1.pem
  - host: 127.0.0.2
    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:

stanzas:
    - type: webapp
      exec: ../yourproject
      ssl:
        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

      ssl:
        [..]
        chain-certificates:
          - /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.

FAQ

  • Keter spawns multiple failing process when run with sudo start keter.
    • This may be due to Keter being unable to find the SSL certificate and key. Try to run sudo /opt/keter/bin/keter /opt/keter/etc/keter-config.yaml. If it fails with keter: etc/certificate.pem: openBinaryFile: does not exist or something like it, you may need to provide valid SSL certificates and keys or disable HTTPS, by commenting the key and certificate lines from /opt/keter/etc/keter-config.yaml.

Debugging

There is a debug port option available in the global keter config:

cli-port = 1234

This allows you to attach netcat to that port, and introspect which processes are running within keter:

nc localhost 1234

Then type --help for options, currently it can only list the apps, but this approach is easily extensible if you need additional debug information.

This option is disabled by default, but can be useful to figure out what keter is doing.

Contributing

If you are interested in contributing, see https://github.com/snoyberg/keter/blob/master/incoming/README.md 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 [email protected].

More Repositories

1

conduit

A streaming data library
Haskell
898
star
2

http-client

An HTTP client engine, intended as a base layer for more user-friendly packages.
Haskell
277
star
3

yaml

Support for serialising Haskell to and from Yaml.
Haskell
160
star
4

mono-traversable

Type classes for mapping, folding, and traversing monomorphic containers
Haskell
155
star
5

classy-prelude

A typeclass-based Prelude.
108
star
6

file-embed

Use Template Haskell to embed file contents directly.
Haskell
87
star
7

xml

Various XML utility packages for Haskell
Haskell
69
star
8

markdown

Convert Markdown to HTML, with XSS protection
Haskell
68
star
9

packdeps

Web app to track lagging package dependencies.
Haskell
61
star
10

basic-prelude

An enhanced core prelude, meant for building up more complete preludes on top of.
Haskell
49
star
11

http-conduit

Superseded by: https://github.com/snoyberg/http-client
Haskell
48
star
12

file-server-demo

Single-file example of a Haskell file server
Haskell
44
star
13

mime-mail

Compose MIME email messages.
Haskell
41
star
14

why-you-should-use-stm

Haskell
38
star
15

yesod-js

Higher-level interaction between Yesod and Javascript
Haskell
36
star
16

trio

Crazy experiment, ignore unless you know better
Haskell
35
star
17

routetype-rs

Strongly typed routes for Rust
Rust
34
star
18

monad-logger

A class of monads which can log messages
Haskell
32
star
19

yesoddocs

Yesod Web Framework documentation site
Haskell
30
star
20

githash

Compile git revision info into Haskell projects
Haskell
30
star
21

http-enumerator

HTTP client package with enumerator interface and HTTPS support.
Haskell
27
star
22

posa-chapter

Chapter for Performance of Open Source Applications
26
star
23

snoyman.com-content

HTML
25
star
24

tonic-example

Minimal example of using Tonic for client/server gRPC
Rust
25
star
25

yackage

Personal Hackage replacement for testing new packages.
Haskell
21
star
26

warp-letsencrypt

Integration of the Warp webserver with Let's Encrypt
Haskell
19
star
27

sortasecret

Rust
18
star
28

cookie

HTTP cookie parsing and rendering
Haskell
17
star
29

safe-prelude

A Haskell prelude optimized for safety
Haskell
16
star
30

zerem

Haskell streaming library optimized for low CPU and GC overhead
Haskell
16
star
31

haskup

Wrap up Haskell tools
Haskell
15
star
32

haskell-web-rosetta

Examples of implementing the same task in different frameworks in Haskell
Haskell
15
star
33

bwbackup

Create encrypted backups of your Bitwarden vault
Rust
14
star
34

vegito

Some standalone stream fusion experiments
Haskell
14
star
35

pid1-rust-poc

Rust
13
star
36

mega-sdist

Handles uploading to Hackage from mega repos
Haskell
12
star
37

kids-haskell-ide

Miniature Haskell interactive environment for my kids to play around with
Haskell
12
star
38

validation-rs

A Result-like type that can collect multiple Errs
Rust
12
star
39

servius

Warp web server with template rendering
Haskell
11
star
40

data-object-yaml

Serialize data to and from Yaml files
Haskell
11
star
41

yesod-fay

Utilities for using the Fay Haskell-to-JS compiler with Yesod.
Haskell
10
star
42

foundation

An alternate Prelude for promote modern best practices.
Haskell
10
star
43

pantry

Haskell
9
star
44

magical-guide-haskell

WIP guide to learning programming with Haskell, targeted at children
HTML
9
star
45

yesodwiki

Haskell
9
star
46

tar-conduit

Conduit based tar extraction mechanism
Haskell
8
star
47

snoyman.com

HTML
8
star
48

codename-karka

Grand refactoring of a whole bunch of stuff at once
Haskell
8
star
49

photosorter

Just a local webapp, pay it no mind
Haskell
8
star
50

failure

A simple type class for success/failure computations.
Haskell
7
star
51

docker-testing

Executables for testing Docker edge cases with PID1 and processes
Haskell
7
star
52

attempt

Concrete data type for handling extensible exceptions as failures.
Haskell
7
star
53

cabal-nirvana

Avoid Cabal dependency hell by constraining to known good versions.
Haskell
7
star
54

rummikub-solver

Simple Rust application for solving Rummikub boards
Rust
7
star
55

purescript-halogen-onetimepad

Work with one time pads from a web page, mostly to teach me PureScript/Halogen
PureScript
7
star
56

web-routes-quasi

Define data types and parse/build functions for web-routes via a quasi-quoted DSL
Haskell
7
star
57

haskell-inside-out

Code to go with my talk at FLIP
Haskell
7
star
58

yesodcms

Haskell
6
star
59

haskell-impatient-poker-players

Haskell for impatient poker players
Haskell
6
star
60

map-class

Typeclass for map-like structures
Haskell
6
star
61

yesodbook

Yesod Web Framework book
Haskell
6
star
62

bloggy

Simple blog based on Yesod Web Framework
Haskell
6
star
63

intro-functional-programming

FP Haskell Center project providing an introduction to functional programming.
Haskell
5
star
64

haskell-hackathon

Repository for the LambdaConf Haskell Hackathon 2018
5
star
65

convertible

Typeclasses and instances for converting between types
Haskell
5
star
66

stack-coc

Unofficial, work in progress: Stack Code of Conduct
5
star
67

orangeroster

Address book site based on Yesod
Haskell
5
star
68

yesod-gitrepo

Host content provided by a Git repo
Haskell
5
star
69

ascii

Type-safe, bytestring-based ASCII values.
Haskell
5
star
70

yesod-alternative

Some proof-of-concept code for alternative approaches to the standard Yesod approach.
5
star
71

snoyberg.github.io-old

CSS
4
star
72

todolist

Sample of a simple CRUD application with Yesod and Backbone.js
4
star
73

data-object

Represent hierachichal structures, called objects in JSON.
Haskell
4
star
74

foreach

First class stream fusion
Haskell
4
star
75

zlib-bindings

THIS LIBRARY IS DEPRECATED: Please use streaming-commons instead
4
star
76

neither

A better either.
Haskell
4
star
77

rust-streaming-utf8

Rust
4
star
78

rio

Reader+IO monad plus utilities
Haskell
4
star
79

data-object-json

Serialize JSON data to/from Haskell using the data-object library.
Haskell
4
star
80

json2yaml

Utility to convert a file from JSON to YAML format.
Haskell
3
star
81

snoyberg-buy-rs

Small helper app for adding purchases to my ledger file, written in Rust
Rust
3
star
82

snoyman-webapps

A repo for a single-image deployment of multiple applications
Haskell
3
star
83

blank-canvas

A trivial Haskell API into HTML5
Haskell
3
star
84

static-bytes

Pack bytes into Word64 to avoid extra pointer indirection
Haskell
3
star
85

rush-crash-course-tokio-exercise-2

Rust
3
star
86

soda

Simple encryption tool for passing secrets
Rust
3
star
87

hack-frontend-monadcgi

Allows programs written against MonadCGI to run with any hack handler.
Haskell
3
star
88

lambda-engine

Haskell
3
star
89

snoy-extra

Various Haskell utilities that don't necessarily deserve to be published
Haskell
3
star
90

trojan

Don't try this at home kids
Haskell
3
star
91

bouncy-rs

Dumb demo, bouncy ball
Rust
2
star
92

luach

Web app to remind of annual events on both the Gregorian and Hebrew calendars.
Haskell
2
star
93

delete-largest

Haskell
2
star
94

yesod-web-service-tutorial

An FP Haskell Center project tutorial
Haskell
2
star
95

hebrew-time

Hebrew dates and prayer times.
Haskell
2
star
96

rust-streams-bench

Rust
2
star
97

totallylegitimatestudies

Haskell
2
star
98

whosawthatcoming

A Yesod-based site for logging prediction
Haskell
2
star
99

control-monad-attempt

Monad transformer for the attempt monad using transformers library.
Haskell
2
star
100

do-not-use-stack

fuck stack
Haskell
2
star