Deploying with Kamal
Running your own VPS is no mean feat when you consider how easy digital ocean or netlify make it deploy your website.
But it’s not as difficult as it used to be, there are some great open source tools to make it easier like coolify and kamal.
Coolify and Kamal take slightly different approaches, coolify is an app you install on your server, has a nice gui you can use to install from git or docker images.
Kamal on the other hand is a command line tool that you run and configure your deployment locally, it accesses your server and installs docker, builds your app into a docker image and deploys it to your server.
Sounds simple enough that your probably thinking I could just write a script to do that, but kamal also setups a proxy allowing you to run multiple apps on a server (new in kamal v2), gracefully pushes a new version of your app without downtime and configures certificates. It is very easy to configure and can be easily integrated into your CI/CD pipeline.
Kamal assumes you already have a dockerfile for your application and you will need a container registry as kamal will build your dockerfile locally, push it to your registry then on the server pull it from the registry. Kamal also requires root access and assumes you have an ssh token setup on the machine you are deploying from.
Kamal is a ruby gem and can be installed locally or via docker.
gem install kamal
Initialise
kamal init
this creates a few things
a config folder with a deploy.yml file that contains your deployment settings.
a .kamal folder with some samples for hooks that are scripts that can be run at certain stages of deployment like pre-deploy
if you need it
and a secrets file which is like a .env file and has a few ways of loading your secrets in.
The meat is in your deploy.yml file where you configre your deployement.
service: appname
# Name of the container image.
image: yourns/appname
# Deploy to these servers.
servers:
web:
- 12.34.56.78
proxy:
ssl: true
host: example.com
app_port: 8080
# Credentials for your image host.
registry:
# Specify the registry server, if you're not using Docker Hub
server: 1234456789kr.ecr.eu-west-1.amazonaws.com
username: AWS
# Always use an access token rather than real password (pulled from .kamal/secrets).
password:
- KAMAL_REGISTRY_PASSWORD
# Configure builder setup.
builder:
arch: amd64
env:
secret:
- NEXT_PUBLIC_SUPABASE_URL
The env var KAMAL_REGISTRY_PASSWORD
is pulled from the secrets file.
This is all that is needed.
Initially i ran into a few issues when using digital ocean container registry which can only contain one namespace or image tag, although after switching to use AWS ECR which is the same, so you will need one repo per app.
As you can see there is not a lot of configuration here, but it is also very configurable if you need to, even being able to an accessory
to push a database or other service.
Other things to consider when running your own VPS:
- create another user and login using that user rather than root
- setup and use an ssh key to login
- change the ssh port to block any bots
- disable password login
- setup a firewall