13

How to host a Monorepo on Coolify

Monorepos have become increasingly popular for managing complex projects with multiple applications or services. Recently, I was working on a project that required two applications to share some components and utilities. Normally, hosting would have been a no-brainer while a using a service like Vercel but that was not an option here. I had to use a custom server and I chose to use Coolify, a self-hosted PaaS solution that simplifies deployment and management of applications, to manage that server.

Prerequisites:

  • A Coolify instance set up and running
  • A monorepo with multiple applications (we'll use a example with a web and dashboard app).
  • Basic knowledge of Docker and Docker Compose

Step 1: Structuring Your Monorepo Ensure your monorepo is structured properly. Here's an example structure:


monorepo/
├── web/
│ ├── src
│ ├── package.json
│ ├── nginx.conf
│ └── Dockerfile
├── dashboard/
│ ├── src/
│ ├── package.json
│ ├── nginx.conf
│ └── Dockerfile
├── packages/
│ └── shared-components/
├── web-docker-compose.yml
├── dashboard-docker-compose.yml
├── web-nginx.conf
├── dashboard-nginx.conf
├── pnpm-workspace.yaml
└── turbo.json

You can decide to have the applications inside an apps directory or any other structure that suits you. The packages directory is where you can put shared components or utilities that are used by both applications. In my case, the web and dashboard applications are two React + Vite applications.

Step 2: Creating Dockerfiles Create a Dockerfile for each application in your monorepo. Here's an example for the web app:

 
FROM node:20.11.1-alpine3.19 AS build
 
RUN npm install -g pnpm turbo
 
WORKDIR /app
 
# Copy root files
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml turbo.json ./
 
# Copy app and packages
COPY web ./web
COPY packages ./packages
 
RUN pnpm install --frozen-lockfile
 
# Build the app
RUN turbo run build --filter=web...
 
# Production stage
FROM nginx:alpine
 
# Copy built assets from build stage
COPY --from=build /app/web/dist /usr/share/nginx/html
 
# Copy a custom nginx.conf for the app itself
COPY web/nginx.conf /etc/nginx/conf.d/default.conf
 
EXPOSE 80
 
CMD ["nginx", "-g", "daemon off;"]
 

You can reconfigure this for the other app.

Step 3: Setting Up Nginx

Here we need to set up Nginx to serve the applications as Single Page Applications. Create a nginx.conf file inside the web and dashboard directories. Here's an example for the web app:

 
server {
    listen 80;
    root /usr/share/nginx/html;
    index index.html;
 
    location / {
        try_files $uri $uri/ /index.html;
    }
}
 

Do the same for the dashboard app.

Step 4: Setting Up Docker Compose

In the root of your monorepo, create a vedor-docker-compose.yml and a dashboard-docker-compose.yml files to orchestrate the applications. For me, the separation was important so I could easily scale the applications independently. Here's an example for the web-docker-compose.yml:

version: "3"
services:
  web:
    build:
      context: .
      dockerfile: web/Dockerfile
    ports:
      - "3001:80"
    volumes:
      - turbo-cache:/app/.turbo
 
  web-nginx:
    image: nginx:alpine
    ports:
      - "8081:80"
      - "8444:443"
    volumes:
      -  # add the path to the nginx configuration file in coolify
      - ./ssl:/etc/nginx/ssl:ro
    depends_on:
      - web
 
volumes:
  turbo-cache:

Do the same for the dashboard app.

Step 5: Set up Nginx in the root directory of your monorepo

Here we need to configure Nginx for reverse proxying to the applications. This step is also performed for each application. Create a web-nginx.conf and a dashboard-nginx.conf file in the root of your monorepo. Here's an example for the web app:

 
server {
    listen 80;
    server_name # add the domain name for the app in coolify;
 
    ssl_certificate # add the path to the ssl certificate in coolify;
    ssl_certificate_key # add the path to the ssl certificate key in coolify;
 
    location / {
        proxy_pass # add the domain name for the app in coolify;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}
 

Do the same for the dashboard app.

Step 6: Deploying to Coolify

Now that everything is set up, you can deploy your monorepo to Coolify. Here's how:

  1. Push your monorepo to a Git repository.
  2. Create a new project in Coolify.
  3. Add a new application to the project.
  4. Set up the application with the following settings:
    • Repository URL: URL to your Git repository
    • Branch: Branch to deploy
    • For the Build Pack, select Docker Compose
    • Under the Build, add the appropriate Docker Compose path under Docker Compose Location for the application you are deploying.
    • Environment Variables: Add any environment variables needed for your application
  5. Deploy the application.

That's it! Your monorepo should now be deployed to Coolify and accessible via the domain name you set up in Coolify and Nginx config files.

From this, you can optimize your deployment by setting up some bash scripts to automate the deployment process. You can also set up a CI/CD pipeline to automatically deploy your monorepo to Coolify whenever you push changes to your Git repository.

I hope this guide helps you deploy your monorepo to Coolify. If you have any questions or need further assistance, feel free to reach out to me. Happy coding!