Deployment

Deploying with IHP Cloud

The fastest way to share your app with the internet is by using IHP Cloud. We recommend following this approach as it’s the most simple to get started with.

Account Setup

IHP Cloud is currently still in beta. To register a new account you need an invite from an existing user or you can join the waiting list at ihpcloud.com.

Creating the Project

Once you’re logged in to IHP Cloud, follow the instructions to create a project for your application.

Private Git Repos: When you connect a private git repository make sure to provide a SSH git clone url. IHP Cloud will provide you with a SSH public key. You need to add this deploy key to your repository.

On GitHub you can do this by opening the repository settings and clicking on Deploy keys.

First Deployment

After the project setup is finished, click on + Deploy Now to start your first deployment.

When your CSS or JS looks broken, take a look at the next section CSS & JS Bundling.

CSS & JS Bundling

In production all your CSS and JS is bundled into a single file.

By default the Web.View.Layout is configured to serve these prod.css and prod.js files.

Take a short look at Web/View/Layout.hs. You can see that depending on whether the app is running in development or production mode it includes your CSS files or the prod.css / prod.js file.

stylesheets = do
    when (isDevelopment FrameworkConfig.environment) [hsx|
        <link rel="stylesheet" href="/vendor/bootstrap.min.css"/>
        <link rel="stylesheet" href="/vendor/flatpickr.min.css"/>
        <link rel="stylesheet" href="/app.css"/>
    |]
    when (isProduction FrameworkConfig.environment) [hsx|
        <link rel="stylesheet" href="/prod.css"/>
    |]

scripts = do
    when (isDevelopment FrameworkConfig.environment) [hsx|
        <script id="livereload-script" src="/livereload.js"></script>
        <script src="/vendor/jquery-3.2.1.slim.min.js"></script>
        <script src="/vendor/timeago.js"></script>
        <script src="/vendor/popper.min.js"></script>
        <script src="/vendor/bootstrap.min.js"></script>
        <script src="/vendor/flatpickr.js"></script>
        <script src="/helpers.js"></script>
        <script src="/vendor/morphdom-umd.min.js"></script>
    |]
    when (isProduction FrameworkConfig.environment) [hsx|
        <script src="/prod.js"></script>
    |]

These bundles are generated by using make:

make static/prod.js
make static/prod.css

The bundling process is only concatenating the files (along the lines of cat a.css b.css c.css > static/prod.css). Currently there is no minification or transpiling applied.

Configuring the CSS & JS Bundling

The files that are bundled together to get our prod.css and prod.js are configured in your projects Makefile. Inside your projects Makefile you will have these statements:

CSS_FILES += ${IHP}/static/vendor/bootstrap.min.css
CSS_FILES += ${IHP}/static/vendor/flatpickr.min.css

JS_FILES += ${IHP}/static/vendor/jquery-3.2.1.slim.min.js
JS_FILES += ${IHP}/static/vendor/timeago.js
JS_FILES += ${IHP}/static/vendor/popper.min.js
JS_FILES += ${IHP}/static/vendor/bootstrap.min.js
JS_FILES += ${IHP}/static/vendor/flatpickr.js
JS_FILES += ${IHP}/static/helpers.js
JS_FILES += ${IHP}/static/vendor/morphdom-umd.min.js
JS_FILES += ${IHP}/static/vendor/turbolinks.js
JS_FILES += ${IHP}/static/vendor/turbolinksInstantClick.js
JS_FILES += ${IHP}/static/vendor/turbolinksMorphdom.js

You need to add your app specific CSS and JS files here as well. E.g. if you have a app.css, a layout.css and a app.js add them by appending this:

CSS_FILES += static/app.css
CSS_FILES += static/layout.css
JS_FILES += static/app.js

Run make static/prod.js static/prod.css to test that the bundle generation works locally. To force a rebuild, either delete the files and run make again, or run make -B static/prod.js static/prod.css.

You can also remove the JS and CSS files that are provided by IHP (like ${IHP}/static/vendor/bootstrap.min.css) if you don’t need them. E.g. if you don’t use bootstrap for your CSS, just remove the CSS_FILES and JS_FILES statements for bootstrap.

DB Migrations

Currently IHP has no standard way of doing migrations. Therefore currently you need to manually migrate your IHP Cloud database after deploying.

Open the project in IHP Cloud, click Settings, then click Database. There you can find the database credentials for the postgres DB that is running for your application. Connect to your database and manually apply the migrations.

Changing the domain

Open the project in IHP Cloud, click Settings and click Domain. You can set a ***.ihpapp.com domain in here.

Using your own domain instead of .ihpapp.com

Using your own domain with IHP Cloud is only available for IHP Cloud Pro users. To use your own domain point a CNAME record to ihpapp.com.

After that go to Settings, click Domain and enter your domain name. When you change your domain to a custom domain we are automatically getting a SSL certificate from LetsEncrypt for you so please make sure to set the CNAME record a few minutes before changing the domain inside your project.

Deploying manually

You can build and deploy your IHP app yourself.

Make sure that the infrastructure you pick to buid your IHP app has enough memory. Otherwise the build might fail because GHC is very memory hungry. You can also set up a swap file to work around this.

Install nix on your server

Nix is needed to build your application. Install it the usual way:

curl -L https://nixos.org/nix/install | sh

We recommend to use the digitally induced cachix binary cache to avoid rebuilding the IHP dependencies and IHP itself:

cachix use digitallyinduced

In case you’re on NixOS, you can skip this.

Copy your project folder to your server

Copy your application source code to the build server. If you’re using git to clone it onto your server, we recommend you use SSH agent forwarding.

Configuration

Make required modifications to your Config/Config.hs:

  1. Switch environment = Development to environment = Production
  2. Set appHostname = "YOUR_HOSTNAME"
  3. Configure any custom settings

(This includes ´make -B .envrc´ to download and build any extra Haskell packages, such as the mmark package in the tutorial)

appHostname is used to build your baseUrl when this is not set manually. baseUrl equals http://{appHostname}:{port} or http://{appHostname} if port is 80. You can overwrite baseUrl by setting it in Config/Config.hs

When you deploy with IHP Cloud your Config.hs is set automatically on project creation. IHP Cloud sets your baseUrl to https://{appHostname} because every deployed app is served with SSL enabled.

To configure your database connection: Set the env var DATABASE_URL to your postgres connection url. Set the env var PORT to the port the app will listen on.

The database needs the UUID-extension which is enabled by running create extension if not exists "uuid-ossp";

Building

Inside your project directory start a nix-shell for the following steps.

We can use make to build the application binary. The default IHP Makefile provides two target: build/bin/RunUnoptimizedProdServer and build/bin/RunOptimizedProdServer.

The first target runs with -O0. It’s useful when you’re setting up the deployment workflow for the first time. Otherwise you will always need to spend lots of time waiting for GHC to optimize your haskell code.

Both make targets will generate a binary at build/bin/RunUnoptimizedProdServer or build/bin/RunOptimizedProdServer and will create a symlink at build/bin/RunProdServer targeting to the binary.

Run make static/prod.css static/prod.js to build the asset bundles.

Starting the app

Now you should be able to start your app by running build/bin/RunProdServer.

More Resources

Check out this blog post on how to deploy IHP to EC2.