So here's a little sum up how I do it:
Create dockerfile
ARG nodeversion=21-bullseye
# build stage using standard node container
FROM docker.io/node:$nodeversion AS builder
WORKDIR /app
# copy & install dependencies
COPY package.json yarn.lock .yarnrc.yml ./
COPY .yarn/ .yarn
RUN yarn install
# copy source code & build
COPY . .
ENV NODE_ENV=production
RUN yarn build --standalone
# use cloudron base image for running the app
FROM docker.io/cloudron/base:4.0.0@sha256:31b195ed0662bdb06a6e8a5ddbedb6f191ce92e8bee04c03fb02dd4e9d0286df
WORKDIR /app
ENV NODE_ENV=production
# copy built files
COPY --from=builder ./app/.output ./.output/
# start script for execution of the app, make sure its executable
COPY --from=builder ./app/start.sh ./
RUN chmod +x /app/start.sh
# set the port and host and expose the port
ENV HOST 0.0.0.0
ENV PORT 8000
EXPOSE 8000
# start the app using start script
CMD [ "/app/start.sh"]
Create start.sh
#!/bin/bash
set -eu
# set any environment variables here, e.g. database connection details
# run the server
node .output/server/index.mjs
Create CloudronManifest.json
Nothing special here, follow documentation from Cloudron, set app details, add addons, set exposed port, etc.
Create CI/CD pipeline
This depends a bit on your runner setup, I'm using a custom gitlab runner package on Cloudron I build for myself + the cloudron build service app. This has some quirks but works for me. Its a docker in docker runner but without access to the docker.sock its not possible to run docker commands itself (or at least didn't figure out how). Normally you'd need access to the docker.sock which is not possible with app packages and a security risk.
Nevertheless here's a sample of my .gitlab-ci.yml
stages:
- stage
deploy_stage:
stage: stage
image: node:19
environment:
name: STAGE
variables:
BUILD_SERVICE: 'https://builderbot.serverdomain.de'
FQ_IMAGE_NAME: 'docker.serverdomain.de/imagepath'
TAG: pre
only:
- main
script:
- npm install -g cloudron
- cloudron build --tag $TAG --set-build-service $BUILD_SERVICE --set-repository $FQ_IMAGE_NAME --build-service-token $CI_BUILD_SERVICE_TOKEN
- cloudron update --server my.serverdomain.de --token $CI_CLOUDRON_TOKEN --app appsubdomain.serverdomain.de --image docker.serverdomain.de/imagepath:$TAG
#- cloudron install --server my.serverdomain.de --token $CI_CLOUDRON_TOKEN --location appsubdomain.serverdomain.de --image docker.serverdomain.de/imagepath:$TAG
For first run you need to use install cli cmd and afterwards update. Hence I always keep it commented out in the pipeline in case I need to reinstall the app from scratch. A combined command for this would be brilliant *hint *hint @girish 😉
Apart from that there's a little more to it in terms of one time setup which I ommited:
Setup private docker registry in Cloudron (alternative use a public registry)
Register the gitlab runner in gitlab
Setup secrets in gitlab, e.g. Cloudron access tokens
might be more I've forgotten, as always once setup things get blurry in memory 🙂