Skip to main content

Create the apps directory

When you first open the VPS terminal, create a folder to hold all your projects:

Clone all repositories

Install dependencies

For every project, install with the frozen lockfile so the VPS gets the exact versions that were tested:

Why pnpm install --frozen-lockfile matters

package.json usually allows version ranges like ^1.2.3 or ~1.2.3. That means pnpm install is allowed to pick a newer patch or minor version when one exists. For example:
  • Today, pnpm install might download 1.2.3.
  • If the author releases 1.2.9 tomorrow, pnpm install could download 1.2.9 instead.
If that new version has a bug or a breaking change, your deployed app is now different from what you tested. Sub-dependencies move too. package.json only lists your direct dependencies; the nested dependencies they pull in are recorded in pnpm-lock.yaml. A plain pnpm install can also update those transitive packages. pnpm install --frozen-lockfile uses pnpm-lock.yaml as a blueprint. It fails if the lockfile is out of date instead of silently upgrading packages, so the VPS gets the exact same dependency tree you tested.
Approve builds only for trusted packages. pnpm approve-builds lets dependencies run build scripts on your server. Native modules like sharp and puppeteer need this, but running arbitrary build scripts can be dangerous and may compromise the server.

Run CI/CD

Each project has its own CI/CD pipeline (GitHub Actions, GitLab CI, etc.) configured in the repo. Once cloned, the pipeline will automatically:
  • Install dependencies (pnpm install --frozen-lockfile)
  • Approve package build scripts (pnpm approve-builds)
  • Run builds (pnpm build)
  • Run migrations (Prisma for PostgreSQL projects)
  • Start the apps under PM2
Make sure environment files (.env) are set up in each project directory with the correct database, Redis, and API credentials before triggering the pipeline.
Verify all apps are running:
That’s it — the automation handles the rest.