Safe Stack in Dokku

Learn how to deploy SAFE Stack applications using Dokku. Explore alternatives to Azure and Heroku for full-stack F# deployment.

6 min read 1,075 words

Everyone knows about the SAFE Stack, if you don't please do check it out - it's a great way to do full-stack web development in F#, and may be the "coolest" thing about .NET these days.

If you go to the documentation, there are a couple of deployment options. It works like a charm, especially with Docker.

You can deploy the output Docker image to a public or private Docker registry, or create a private Azure registry and store it there. You can pull your image from the registry and load it into Azure Container Service. Boom!, your application is up and running. Not that difficult. The only thing I found annoying is that I need to deploy tags manually (for now?).

Yes, I can keep a latest tag as well and start continuous deployment, but for no reason I didn't like the latest tag; this just increases ambiguity for me.

But for most cases it works. You can always use a CI/CD solution for all this. It will surely make things easier as things are getting built on someone else's machine. But that would be overkill for small applications or experiments.

Let's go back a few years and discuss traditional Azure Websites. One good thing about Azure websites was and is Kudu. Your git push will trigger the build and deploy process. I was able to use Paket (an alternative to and wrapper around NuGet) instead of NuGet in my build processes. Quite versatile if you know what you are doing! But many times I end up spending time debugging Azure issues more than issues in my application.

Even further back, there was (and still is) another "easy deployment" solution called Heroku. Similar to working with Kudu, you would git push heroku master, and it would build and run the application. Additionally, Heroku manages a linked database and satisfies some caching needs for you! This felt much simpler to me than working with Azure trying to resolve these things. Heroku is still around, but due to pricing changes, I prefer other solutions...

But no worries; Dokku is here! You can start by deploying it to your favorite cloud provider, there are many options available. I will talk about Azure here. It is as simple as clicking a button literally. Be careful when you press Deploy to Azure - it by default selects a D series VM. It is good for production and may not fit your free plans, so better change it to an A or B series, which are good for testing. I am running an A2_V2 VM for testing my applications. Give the names and set up an SSH key which you already have on your machine. This way you can easily ssh to the Dokku machine. It is always good to assign a domain to your server. Make things easy to use and manage. Here is a wonderful video by Rob Conery on how to set up Dokku:

Now, back to the SAFE Stack.

If you read the documentation in Dokku, you will see that you will be required to use a build pack to run your application. But there is another way buried in those docs. If you have a dockerfile in your project and don't have a build pack, then it will utilize the dockerfile rather than the default option. Internally, Dokku runs Docker to manage and run different applications in isolated environments. So, instead of a build pack saying what to do, I am just giving a dockerfile to do that.

When you generate a SAFE Stack application (with the dotnet template) with the Docker option, it will set you up with the following Dockerfile:

FROM microsoft/dotnet:2.1-aspnetcore-runtime-alpine
COPY /deploy /
WORKDIR /Server
ENTRYPOINT [ "dotnet", "Server.dll" ]

A very simple Dockerfile - pull the ASP.NET Core runtime and run the server application. But it might not be enough for Dokku as we need to build the application on the server.

Here is a dockerfile that better fits Dokku's needs:

FROM vbfox/fable-build:stretch AS builder

WORKDIR /build

RUN dotnet tool install fake-cli -g
ENV PATH="${PATH}:/root/.dotnet/tools"

# Package lock files are copied independently and their respective package
# manager are executed after.
#
# This is voluntary as docker will cache images and only re-create them if
# the already-copied files have changed, by doing that as long as no package
# is installed or updated we keep the cached container and don't need to
# re-download.

# Initialize node_modules
COPY package.json yarn.lock ./
RUN yarn install

# Initialize paket packages
COPY paket.dependencies paket.lock ./
COPY .paket .paket
RUN mono .paket/paket.exe restore

# Copy everything else and run the build
COPY . ./
RUN rm -rf deploy
RUN fake run build.fsx --target Bundle



FROM microsoft/dotnet:2.1-aspnetcore-runtime-alpine
# here I am not putting everything in root, instead a directory app is created
WORKDIR /app
COPY --from=builder /build/deploy ./
# here I have to map it to the server directory
WORKDIR /app/Server
EXPOSE 8085
ENTRYPOINT [ "dotnet", "Server.dll" ]

ref: Continuous Deployment of SAFE apps on linux server

It is doing a few more things here... vbfox/fable-build:stretch installs Mono, Node, and .NET Core. So you can start building the application right away.

Install npm dependencies, install Paket dependencies, run a bundle command to build and bundle everything. After that, we do what we were initially doing: have a runtime and run the application. You can always customize everything; just add a specific file and Dokku will pick that up for you.

So, after your work is done, you can fire the command git push dokku master where Dokku is a remote repository pointed to dokku@mydokku.me:samplesafeapp. Don't forget that dokku username before your server, else things will fail. If you happen to get permission issues, it's likely due to SSH permissions... you just need to add your public SSH key to the Dokku server and the permissions issue should resolve. Your first build might take a bit of time, as it will download around 3.29 GB for you. :)

I can't say if this is the best option you have, but it's surely good if you like to have a git check-in-friendly server around. And Dokku does handle SSL, scaling, and no-downtime updates, which makes it a production-ready platform.

Give it a try, I am pretty sure you will like it.

Need help working with the SAFE Stack? I'm very much happy to help, and am also available for consulting. Drop a message, and I'll be more than happy to have a chat.

Frequently Asked Questions

What is Dokku and how does it compare to traditional deployment solutions?

Dokku is a lightweight deployment solution similar to Heroku and Azure Websites' Kudu, but more cost-effective and easier to manage. Like Heroku, you can deploy applications with a simple `git push` command, and it handles the build and deployment process automatically without the complexity and debugging issues often associated with Azure or the pricing concerns of Heroku.

How do I deploy a SAFE Stack application using Dokku?

First, deploy Dokku to your preferred cloud provider (like Azure using their one-click button), then configure an SSH key for access. Link a domain to your Dokku server, and you can deploy your SAFE Stack application by pushing to your Dokku remote repository, which automatically builds and runs your Docker container.

What VM specifications should I use for Dokku on Azure?

For testing and development, use A or B series VMs (such as A2_V2) which are cost-effective and suitable for small applications. Reserve D series VMs for production deployments, as they offer better performance but may not fit free tier plans.

Why is Dokku better than managing Docker images directly for small applications?

Dokku eliminates the need for manual Docker registry management and CI/CD pipeline setup, which would be overkill for small applications or experiments. It provides a simpler deployment workflow similar to Heroku while avoiding manual tag management and the complexity of traditional Azure deployment processes.

Share this article