Deployments
Our SAAS platforms need to be deployed somewhere for internal and public access. This process guide provides the pointers for a developer working on a SAAS to create and maintain a working deployment.
Our existing SAAS platforms are usually deployed on Google Cloud, Digital Ocean or other bigger cloud platform. This guide is written for new projects or project transitioning to the new deployment target.
Self-hosting
Our new default since 2025 is self-hosted. Be cloud-agnostic and without vendor lock-in. By default we host using Coolify on the Hetzner Cloud, a German owned company. Hosting projects within EU and having an owner company within the EU is a good asset towards clients.
Coolify
You probably don’t need it, but just for reference, this file describes how our Coolify server and workers the host the actual projects are setup.
Deployments
A deployment should be kicked off through events in Gitlab. Most actions happen when pushing new code to a certain branch name as specified here.
Ideally, a project has these deployment targets:
- Review: code in a MR can be tried out on a throwaway/temporary environment, making it easy to play around.
- Staging: code in a branch is automatically deployed to staging giving a peek in the future where internal or sometimes also external users can verify workings before releasing code as a new production release.
- Production: code in this branch usually passed through Review and Staging earlier and is now ready to be used by production users of the service.
Prerequisites
Coolify requires a project to have a working Dockerfile
and runtime configurable environment variables.
Configuring a deployment environment
Project specific deployment information should be kept in the projects’ README.md
. Everything generic should be found
on this specific webpage.
Create a coolify project
- Obtain a login at our Coolify instance at Hetzner.
- Ensure you’re in the right team after logging in. You should start in team
Sandbox
that has a sandbox server connected to it so your first attempts at deploying something won’t break anything else. Once you’re confident you understand Coolify, ask an admin to add to your actual team. - Create a project
For a simple nextjs project like dc-website
, make a new project and add a
Private repository (with deploy key)
resource to it. (See gitlab integration)
Redirect www
If desired each project can be configured to redirect requests to the www subdomain. Make an A record for both the www and apex (root) domain. Configure both as the domain and set the redirection. If it doesn’t work you may need to reset the traefik labels and set the redirection again.
Production and staging environments
By default each project has a production environment. Create an additional environment called staging. This project will contain the staging and preview deployments. You can first create all the resources required for the project in the staging environment then clone them to the production one to save some time.
NOTE: Make sure to select an internal server for the staging environment. This ensures that everything hosted on it cannot be accessed outside of the office network.
For most projects you will need to add a domain and the environment variables. The preview deployments
also have to be enabled but only in the staging environment. The build is handled with nixpacks which
automatically determines how to built the project and will deploy it using docker.
If this works for the project then no further configuration is needed. Otherwise it is possible to
manually designated a Dockerfile
to be used.
More complex projects (Docker based)
For more complex projects a Dockerfile
is required for frontend and one for backend. If additional services are
used then these have to be defined in a docker-compose.yaml
file. The docker compose can be used to setup
a resource that contains the necessary services. If the services need to be accessed from the local
network they can be accessed with the following url convention: ‘$SERVICE_NAME-$SERVICE_ID’.
As an example: http://portal_backend-mgo4wgsoc0k0wco4k4oowc0s
. If the service needs to be accessed
outside of the network it can be assigned a domain name. Note that you may need to add a
non wildcard domain before wildcard domains will work.
docker-compose v.s. resource
Guidelines on when to use docker-compose
and when to create a manual resource:
- If you want to use the backup functionalities of coolify, use a resource to setup something like a DB.
- When using a
docker-compose
file, you need to append the uuid of the project. Otherwise the network will be disconnected from the rest of the project. More. - If you can do all of your config in docker-compose, then it might be a good solution, but you don’t want to put credentials in there, because the docker-compose is present in Git repos for everyone to see.
Databases
If your project requires a database like PostgreSQL (even the postgis extension is an option), you can create a
New Resource
within a Project and select PostgreSQL
. By default the PostgreSQL
database is on port 5432.
By default the database will have the version postgres:16-alpine
. Make sure you stay above this version and
do not go below this version.
When the database is created in Coolify, you have two options for connecting to it: using an internal URL or a public URL. The internal URL should be used when the service accessing the database is within the same resource as the database itself. If you need to access the database from outside that resource, you should use the public URL.
To enable the public URL, go to Coolify’s settings under General > Proxy,
and enable the option Make it publicly available
. Once this is selected,
a second URL will appear below the internal URL.
Creating a Database
By default, Coolify creates a database named postgres
. If you want to add a new database,
first deploy the database container.
Then open your terminal and create the database using the following command:
psql -h coolify-sandbox-internal.d-centralize.nl -p 5432 -U postgres -d postgres -c 'CREATE DATABASE db_name;'
In this command:
coolify-sandbox-internal.d-centralize.nl
is the server URL (in this example, from the sandbox group)5432
is the default PostgreSQL portpostgres
is both the default username and the name of the initial database
DNS
Topics to write about and configure:
Domains and DNS settings
What domain(s) are connected to a deployment and what DNS provider (our default is desec.io). Make sure you obtain credentials to set the domain records there and also make sure you describe in the README what (sub)domain settings are crucial for this deployment to work.
Starting deployments
Use the Coolify API in CI jobs to kickoff deployments.
See for example: KAT, deploy*
.