CI/CD for VM deployments is the process of turning a code change into a repeatable build, test, release, verification, and rollback workflow for one or more virtual machines.
The useful boundary is simple:
commit
→ CI checks
→ build versioned artifact/image
→ approve release
→ deploy to VM
→ restart/reload safely
→ verify health
→ keep rollback target
Raff Technologies VMs can be automated through normal Linux tooling, APIs, cloud-init, and infrastructure-as-code workflows. The CI/CD system should treat the VM as a controlled deployment target, not as a terminal that someone manually edits after every merge.
CI and CD solve different parts of VM delivery
Continuous integration (CI) validates the change before production.
Typical CI steps include:
- checkout;
- dependency installation;
- linting;
- unit/integration tests;
- security or dependency checks;
- build/package;
- artifact publication.
Continuous delivery/deployment (CD) moves a validated release toward a target environment.
Typical CD steps include:
- environment approval;
- secret retrieval;
- deployment;
- service restart/reload;
- migrations;
- health checks;
- rollback on failure.
A team can have CI without automated production deployment. That is often a sensible intermediate stage.
Build once, deploy the same artifact
The safest pipeline creates a versioned artifact once and promotes that exact artifact.
Examples:
- tar/zip release bundle;
- compiled binary;
- Docker image;
- framework build output.
Avoid rebuilding production independently after tests passed elsewhere. A second build can produce a different dependency graph or output.
A release identifier should map back to a commit SHA, tag, or immutable image digest.
Choose the deployment transport deliberately
Common VM deployment methods include:
| Method | Good fit | Main concern |
|---|
| SSH + rsync/scp | Small teams and simple artifacts | Credential scope and imperative scripts |
| SSH + remote release script | Repeatable VM release directories | Script quality and rollback handling |
| Pull from artifact/object storage | Larger artifacts | Access control and artifact retention |
| Pull container image | Container workloads | Registry and image lifecycle |
| Config-management/IaC workflow | Larger fleets | More operational tooling |
SSH is not inherently wrong. A narrowly scoped, audited deployment credential can be appropriate for a small VM fleet.
The pipeline should not use a developer's personal SSH key.
Separate deployment credentials from runtime secrets
CI/CD needs credentials to reach the target environment, but those credentials should be scoped to deployment.
Examples:
- deploy-only SSH key;
- short-lived cloud credentials;
- environment-scoped CI secret;
- registry read token.
Runtime secrets such as database passwords or application API keys should not automatically become visible to every CI job.
Use environment-specific protection and approval controls for production credentials.
Use deployment environments and approvals
A practical workflow often separates:
development → staging → production
Production can require:
- branch/tag rules;
- manual approval;
- protected environment;
- limited secret access;
- restricted deployment actor.
This reduces the chance that every successful CI run automatically becomes a production release.
For environment architecture, see Staging vs Production vs Development Environments.
Keep VM state predictable
A pipeline should know where the application lives and how releases are activated.
One common layout:
/opt/app/releases/<release-id>/
/opt/app/current -> /opt/app/releases/<release-id>/
The deploy job:
- uploads/extracts the new release;
- installs only required production dependencies if necessary;
- validates configuration;
- switches the active release;
- restarts or reloads the service;
- checks health;
- retains previous releases for rollback.
This is easier to recover than overwriting one directory in place.
Service restarts should be controlled
The release step should use the production supervisor:
systemctl restart or reload for systemd services;
- PM2 reload/restart for Node.js where PM2 is used;
- Docker Compose update/recreate for Compose workloads.
Do not deploy by killing arbitrary PIDs or starting a new process in an interactive shell.
The Application Deployment on a Linux VM guide owns the broader runtime architecture.
Database migrations need their own failure plan
Database migrations are one of the hardest parts of automated deployment.
A useful rule is to prefer backward-compatible changes when possible.
For example:
- add a new nullable column;
- deploy code that can use old/new state;
- backfill;
- switch reads/writes;
- remove old schema in a later release.
That is safer than a deployment that makes the previous application version immediately incompatible with the database.
A pipeline should not automatically run destructive migrations without a recovery plan.
Verify health after deployment
A successful SSH command is not a successful deployment.
The pipeline should verify:
- process/service state;
- local readiness endpoint;
- public HTTPS endpoint;
- expected version where possible;
- basic critical-path request.
If health fails, stop promotion and roll back or leave the previous release active.
Rollback should be faster than debugging
Production incidents are not the right time to design rollback.
For artifact-based deployments, keep at least one previous known-good release.
For containers, keep the previous image digest/tag.
Rollback should ideally be:
select previous release
→ switch active version
→ restart
→ verify
Database changes may make rollback more complicated, which is why migration compatibility matters.
Blue-green and rolling deployments are later-stage options
A single VM deployment usually has a short restart/reload window unless the runtime supports graceful reload.
As availability requirements increase, teams may use:
- blue-green deployment;
- rolling deployment across multiple VMs;
- canary releases;
- app-platform deployment primitives.
These require extra capacity and traffic-routing control.
Use Blue-Green vs Rolling Deployments for that decision rather than implementing complexity before the workload needs it.
GitHub-hosted vs self-hosted runners
Where CI runs is a separate decision from where the application runs.
A GitHub-hosted runner is simpler operationally. A self-hosted runner can provide custom software, network access, caching, or resource control but becomes infrastructure that the team must patch, isolate, monitor, and scale.
Use GitHub Actions Self-Hosted Runners vs GitHub-Hosted for that decision.
Do not place an untrusted public-repository workflow on a privileged self-hosted runner that can reach production secrets or networks.
CI/CD pipeline security checklist
For production VM deployment:
- use least-privilege deploy credentials;
- separate production secrets from general CI secrets;
- protect deployment environments;
- pin or review third-party actions/tools;
- restrict who can modify deployment workflows;
- avoid printing secrets;
- keep build artifacts immutable/versioned;
- log deployment identity and release ID;
- rotate deployment credentials;
- limit network access where practical.
What to automate first
A small team does not need to automate everything at once.
A useful progression is:
Stage 1
- tests on push;
- manual production deployment using a documented script.
Stage 2
- build/version artifact in CI;
- protected manual deployment job.
Stage 3
- automated staging deploy;
- production approval;
- health verification;
- one-command rollback.
Stage 4
- multi-VM rolling/blue-green release if availability requirements justify it.
This sequence adds safety before sophistication.
A VM pipeline is valuable when the team wants OS/runtime control.
An app platform may be simpler when you primarily want:
- Git-connected builds;
- environment-variable management;
- managed release lifecycle;
- automatic runtime restart;
- platform-level deployment history;
- less server administration.
Use Cloud VM vs App Platform to compare the responsibility models.
Frequently asked questions
What is CI/CD for a VPS?
It is an automated or semi-automated workflow that tests, builds, releases, verifies, and rolls back application versions deployed to a virtual private server or cloud VM.
Can GitHub Actions deploy directly to a VPS?
Yes. A common approach uses a protected deployment job with a scoped SSH credential, versioned artifact, remote release script, health check, and rollback path.
Should I run a self-hosted CI runner on the production VM?
Usually not. It increases the blast radius because workflow execution and production runtime share the same trust boundary. Separate runners or hosted runners are easier to isolate.
Should production deploy automatically after every merge?
Not necessarily. Small teams often benefit from automatic CI plus a protected production approval until the release process and test coverage are mature.
How do I roll back a VM deployment?
Keep the previous artifact or image, switch the active release back, restart the service, and verify health. Database compatibility must be considered separately.
Do I need Kubernetes for CI/CD?
No. CI/CD works with a single VM, multiple VMs, containers, Kubernetes, and app platforms. The deployment target changes the release mechanics, not the need for repeatable delivery.
Sources