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:
- Push your monorepo to a Git repository.
- Create a new project in Coolify.
- Add a new application to the project.
- 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
- 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!