Halloween DealsAmazon USHalloween week deals: useful picks before month-endAmazon US: current deals, useful picks and tech finds.Check DealsClean PCRecommendedOne scan can reveal what keeps slowing WindowsLook for cleanup and repair opportunities.Run ScanHalloween DealsAmazon USOctober picks are moving - compare before checkoutAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
World desk13 min

How to Set Up GitLab CI/CD to Deploy to a Linux VPS

Learn the complete GitLab CI/CD to Linux VPS workflow: dedicated SSH keys, protected variables, runner choices, rsync transfers, idempotent server scripts, deployment serialization, security controls, and rollback procedures.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The dependable pattern is GitLab repository → CI runner → tests and build → protected deploy job → SSH to a dedicated VPS user → an idempotent deployment script. The runner can copy a build with rsync and then invoke a script over SSH. This keeps build work in CI, limits server privileges, records deployments in GitLab, and makes failed releases and rollbacks diagnosable.

This guide shows how to build that arrangement without tying it to a particular VPS provider, Linux distribution, web server, or application framework.

As an Amazon Associate I earn from qualifying purchases.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

What the finished deployment looks like

A push to the default branch starts a pipeline. The test job verifies the change, the build job produces a known artifact, and a production job runs only after both succeed. That job uses a dedicated runner, loads an SSH private key from protected GitLab CI/CD variables, verifies the VPS host key, transfers the artifact, and calls a server-side script. The script installs or unpacks the exact release, performs any required migration, restarts or reloads the service, checks health, and returns a non-zero status when something fails.

GitLab’s environment entry records the deployment as production. A resource_group named production serializes jobs so two production deployments do not run at once. Branch and variable protection then determine who can reach the deployment credentials.

#1 Best Overall
Sale
TOZO A1 Wireless Earbuds Bluetooth 5.3 Light Weight in Ear Headphones | IPX5 Waterproof,2 Mics for AI Calls,Immersive Premium Sound Bass Headset with Charging Case,32 EQ via App Black
  • [Ultra-Lightweight Ear Buds Designed for Small Ears] Each earbud weighs only 3.7g and features a compact, ergonomic in-ear design made especially for small ears. Secure, low-profile, and comfortable for workouts, all-day wear or overnight sleeping.The ultra-slim profile sits flush in your ear with no hard edges poking or rubbing, so you can even sleep on your side without discomfort.
  • [Immersive Stereo Sound with TOZO OrigX Technology] TOZO OrigX tuning delivers clear vocals, balanced mids, and natural stereo sound for music, podcasts, and videos.
  • [Long Battery Life for Daily Use] Get up to 7 hours of playtime on a single charge, with up to 32 hours total using the charging case—ideal for workdays, commuting, and extended listening sessions.
  • [Bluetooth 5.3 & Stable Connection] Bluetooth 5.3 provides fast pairing, stable wireless performance, and reduced dropouts as you move around home or office.
  • [Deep Bass with Clear Vocals] High-performance drivers produce punchy bass while keeping vocals clean and detailed for everyday listening.

Prerequisites and decisions

  • A GitLab project containing a working .gitlab-ci.yml.
  • An SSH-reachable Linux VPS. Port 22 is conventional; use the configured alternative when the server listens elsewhere.
  • A non-root deploy user with only the permissions required by the deployment script.
  • A registered GitLab Runner. Docker and shell executors are common choices; runner tags identify the runner intended for this job.
  • A deployment directory on the VPS and a repeatable server-side script.
  • A defined release model: copy files into one directory (in-place) or keep versioned release directories for quick rollback.
  • A health-check method, such as an HTTP endpoint, a systemd service check, or an application-specific command.

Decide whether production should deploy automatically after a successful default-branch pipeline or require a human promotion. Automatic deployment is convenient for low-risk applications; a manual job or protected branch is safer when migrations, customer data, or scheduled maintenance are involved.

Prepare the VPS safely

Create a dedicated account

Create a user such as deployer rather than allowing CI to log in as root. Give that account ownership of the release directory or narrowly scoped permissions through a reviewed administrator-owned script. Keep operating-system administration, firewall changes, package installation, and service-unit edits outside the normal CI path unless there is a specific, audited reason to automate them.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The deploy account needs to read the uploaded artifact and execute the deployment entry point. If the service runs under another account, use a narrowly scoped sudoers rule for the exact restart or reload command instead of unrestricted sudo. Test the command as the deploy user before connecting GitLab.

Create the deployment layout

A simple layout might contain /srv/myapp/releases, /srv/myapp/current, and /srv/myapp/deploy.sh. The transfer step can upload to a temporary directory or to a release directory named with the commit SHA. The script validates the contents, switches current to the new release, restarts the service, and leaves older releases available for rollback.

For a small static site, an in-place directory can be sufficient. Versioned releases are preferable when a restart can fail, when a migration must be reversed, or when you need to restore the previous commit without rebuilding it.

Install the server-side prerequisites

Install the runtime, process manager, web server, and any database client required by the application. The deployment script should check that required commands exist and stop before changing the live release if they do not. Keep application configuration and secrets on the VPS or in a separately controlled secret store; do not commit production secrets to the repository or copy them into an artifact.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #2
Sale
Smart Watch for Men Women Compatible with iPhone Samsung Android Phone 1.69 inch Full Touch Screen IP68 Waterproof Bluetooh Fitness Tracker Heart Rate/Sleep Monitor (Black)
  • 【IP68 Waterproof Multifunctinal Smart Watch】Torjalph fitness activity tracker smart watch is IP68 waterproof technology ,you can wear it when swimming,handwashing,it's rain-proof which means that you perform multiple exercise modes outside without worrying about sweat or rain corroding your fitness smart watch,and this watch equipped with a 230 mAh large capacity battery magnetic charging ,and this sports activity tracker watch can be used 5-7 days If fully charged.
  • 【Larger 1.83'' Full Screen Watch & Multi-dial Selection】1.83 inch full HD color touch screen smart watch for men / women provides excellent 240*284 resolution image quality ,This Bluetooth smart watch offers a better touch experience and remarkable immersion and ,more than 200 watch faces for you to choose from App"Da Fit ", you can change the dial style according to your mood to wear keeping the world on your wrist
  • 【Accurate Activity Tracker Smart Watch 】sports watch activity tracker uses sweat and dust resistant breathable silicone strap, our Fitness Tracker Smart Watch for Android iOS Phones supports 12 sports modes,walking,running,bicycle,swimming,badminton,basketball,football,rope skipping. This bluetooth calls smart watch for men women is lightweight and stylish, bringing more convenient and relaxing sports experience while also providing more protection.
  • 【Your 24 Hour Personal Daily Health Monitor】Fitness watch for women men full touch screen IP67 waterproof bluetooth smartwatch for Android iOS Phones with heart rate blood pressure monitor multifunction Andriod smart watch with steps counter sleep monitor sports fitness watch, monitoring blood oxygen saturation allows you to understand your physical condition in real time to track fitness progress ,to know your health status in time.
  • 【More Functions Bluetooth Call Smart Watch】This fitness activity smart watch full screen for iPhone and Android phones includes a bunch of new features including:The bluetooth smart watch can hang up the phone, receive and display WhatsAPP /Text /Facebook /Twitter /Messenger reminder.Support sedentary reminder, alarm clock, stopwatch, timer,weather information,music control, remote camera control compatible with Android 5.0 and above or iOS 9.0 and above smartphones.

Set up a dedicated SSH key

Generate a key pair for automation

Generate a new key pair solely for this deployment account. Do not reuse a personal key. GitLab’s SSH guidance advises storing private keys securely, avoiding personal keys for automated jobs, and rotating automation keys regularly to reduce the risk of unauthorized access.

Run key generation on an administrator-controlled workstation or another trusted system, using a modern key type supported by the server. Protect the private-key file while it is being handled. The public key, not the private key, is what belongs on the VPS.

Authorize the public key on the VPS

  1. Log in to the VPS through an existing administrative path.
  2. Create ~deployer/.ssh with mode 700.
  3. Append the public key to ~deployer/.ssh/authorized_keys.
  4. Set the file mode to 600 and make sure the directory and file are owned by deployer.
  5. From a trusted machine, test ssh as the deploy user and confirm that the expected account, home directory, and permissions are used.

Store private infrastructure values in GitLab

In the project, open Settings → CI/CD → Variables and add these values:

Variable Type and protection Purpose
SSH_PRIVATE_KEY File variable; protected; scoped to the production environment The private key used by the deploy job
VPS_HOST Protected variable DNS name or address of the VPS
VPS_USER Protected variable The non-root deployment account
VPS_PORT Protected variable SSH port; use 22 when unchanged
DEPLOY_PATH Protected variable Application directory on the VPS
VPS_KNOWN_HOSTS Protected, masked where GitLab permits The verified host-key line or lines for the VPS

A file variable gives the job a path to a temporary file rather than placing the key text directly in the YAML. Mark production values as protected so they are available only to protected branches or tags, and scope them to the production environment when the project uses multiple environments. Keep host names and deployment paths out of the repository when they disclose production infrastructure.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Verify the host key

Host-key verification prevents a job from silently connecting to an impostor. Obtain the VPS host key through a trusted administrative channel, review its fingerprint, and store the resulting known-hosts line in VPS_KNOWN_HOSTS or provision it on a dedicated runner. Do not use a blanket option that accepts every unknown host key in production. If the server is rebuilt and its host key legitimately changes, pause deployments, verify the new fingerprint, update the protected value, and document the change.

Choose and harden the runner

Docker executor

The Docker executor gives each job an isolated container and is a common default for build and deployment tooling. Ensure the image contains, or can install, an OpenSSH client and rsync. Pin a suitable image or verify package installation so a base-image change does not unexpectedly remove required commands.

Rank #3
New Bee Guitar Cable 10ft Electric Instrument Bass AMP Cord
  • [Low Noise High Fidelity] New bee guitar cord with 22AWG oxygen-free-copper center conductors provides enhanced signal transfer, the PVC insulation material and the high-density stranded copper double shield provide noise rejection for quiet operation
  • [Ideal for Choice] New bee 1/4 straight and right angle metal connectors, ensures a secure connection in any instrument, pedal, or amp jack. L shape great fro on stage guitar stands
  • [Wide Compatible] Suitable for mixer, power amplifier, microphone, effector, decoder, equalizer, electoronic organ, electric guitar, electric bass and other electronic equipments. Widely used in the installation of smart home, karaoke speaker, professional stage audio, etc
  • [Easy Disassemble] Making incidental repairs quick and easy! Very nice, flexible cable
  • [Dont Hesite to Order] 24 hours customer services and professional technology team are standing by

Shell executor

The shell executor is useful when the runner host already has the exact toolchain. Its trade-off is a larger blast radius: job commands execute directly on that host, and a compromised project job can affect files, credentials, or processes available to the runner account. Dedicate such a runner to trusted projects and keep its operating system patched.

SSH executor

The SSH executor runs jobs on a remote machine by runner design. That is different from using SSH inside an ordinary deployment job to reach the production VPS. Choose the executor deliberately so the machine that builds code is not accidentally the machine that hosts production.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Tags and privilege boundaries

Jobs with tags run only on runners carrying all those tags. Give the production job a dedicated tag, such as production-deploy, and apply that tag only to the intended runner. GitLab warns that privileged self-managed runners can expose their host to privilege escalation. Avoid privileged mode and host PID namespace sharing unless a narrowly justified and controlled requirement exists. Isolate production runners from unrelated projects and treat them as part of the production trust boundary.

Build the pipeline

Use separate test, build, and deploy stages. The deploy job should have no path to run when tests or the build fail. The following provider-neutral example assumes the build creates a dist/ directory and the VPS contains an executable deploy.sh.

stages: [test, build, deploy]

test:
  stage: test
  script:
    - ./ci/test.sh

build:
  stage: build
  script:
    - ./ci/build.sh
  artifacts:
    paths: [dist/]

deploy_production:
  stage: deploy
  tags:
    - production-deploy
  environment:
    name: production
  resource_group: production
  rules:
    - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
  before_script:
    - command -v ssh-agent >/dev/null || (apt-get update -y && apt-get install -y openssh-client rsync)
    - eval "$(ssh-agent -s)"
    - chmod 400 "$SSH_PRIVATE_KEY"
    - ssh-add "$SSH_PRIVATE_KEY"
    - mkdir -p ~/.ssh && chmod 700 ~/.ssh
    - printf '%sn' "$VPS_KNOWN_HOSTS" > ~/.ssh/known_hosts
  script:
    - rsync -az --delete -e "ssh -p ${VPS_PORT:-22}" dist/ "$VPS_USER@$VPS_HOST:$DEPLOY_PATH/dist/"
    - ssh -p "${VPS_PORT:-22}" "$VPS_USER@$VPS_HOST" "$DEPLOY_PATH/deploy.sh"

The exact package-manager command depends on the runner image. If the image is not Debian-based, install OpenSSH and rsync using its native package manager or choose an image that already contains them. The chmod and ssh-add steps ensure that the private key is not readable by other processes in the job container.

Control when production can run

The example limits deployment to the default branch. A protected branch or protected tag can add an approval boundary. For a manual promotion, add when: manual to the deploy job and require an authorized person to start it. If production and staging use different hosts, define separate environments and scope each environment’s variables to the matching job.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #4
BSIMB 15.6" Digital Family Calendar & Chore Chart, No Subscription Fees
  • Digital Family Calendar: BSIMB digital calendar wall touch screen puts an end to your chaotic life. Designed for busy families, the digital calendar keeps you organised and in step with your family. Assign different colours and tasks to each family member to make family scheduling easier and more intuitive.
  • Easy Setup and Auto-Sync: Plug in, connect to WLAN and auto-syn your electric calendar in minutes. Digital wall calendar compatible with Google calendar, iCloud calendar, Outlook calendar, Cozi calendar and Yahoo calendar. Add events directly on the device or through the ecalendar app. Electronic calendar stays current whether you're at work or traveling—no manual updates needed.
  • All-In-One Home Assistant: Smart calendar builds habits and encourage independence with personalised chores. Display daily meal plan to reduce the daily ‘What's for dinner?’ stress. To-do lists keep track of everything you want. Turning chores into valuable achievements with stars and rewards, making life easier and more enjoyable.
  • Manage Anytime Anywhere: BSIMB electronic calendar for family stay connected with the powerful ecalendar app. Access and manage your digital wall calendar anytime, anywhere with free features like stars & rewards, photo screensaver, chore charts, meals plans, to-do lists etc. Electronic planner paid features like Magic Import tailor advanced tools for users with special needs.
  • Stay in Touch with Loved Ones: Share photos or videos from your phone to electronic wall calendar with app, instantly update your life moment, and keep in touch with your family, especially those who are far away; you can also surprise your smart calendar digital wall by sending him a wish card; it's also great for keeping tech-illiterate elders in touch with the youngsters.

Use artifacts as the hand-off

The build job’s artifact is the hand-off between stages. It represents the tested output rather than asking the production server to fetch arbitrary source code. Set an expiration appropriate to your rollback policy; if an artifact must remain available for an extended rollback window, retain it through your GitLab settings or keep a copy in a controlled artifact store.

Write an idempotent VPS deployment script

The script on the VPS is the policy boundary. Keep it reviewed and administrator-owned, while allowing the deploy user to invoke it through the narrowest permissions practical. It should be safe to run twice with the same artifact and should leave the service either on the new release or on the previous known-good release.

  1. Enable strict shell error handling and log the commit or release identifier being deployed.
  2. Check that the expected artifact directory exists and contains required files.
  3. Validate configuration without exposing secret values in logs.
  4. Copy or unpack into a temporary release directory, not directly over the live files.
  5. Install dependencies using a lockfile or other exact version declaration.
  6. Run database migrations in a controlled order when the application requires them. Make migrations backward-compatible with the currently running version when a service restart is not instantaneous.
  7. Run application-level validation, such as a configuration check or a local health command.
  8. Switch the service to the new release, then restart or reload it using the permitted command.
  9. Perform a health check and return status zero only when it succeeds.
  10. Retain a defined number of older release directories and remove temporary files only after the health check passes.

A failure must produce a non-zero exit status so GitLab marks the deployment failed. Do not hide errors with unconditional success commands. Keep logs useful but redact tokens, database passwords, and private keys.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Transfer methods and release strategies

Decision Option Advantages Trade-offs
How files reach the VPS Runner pushes with rsync Simple, fast incremental transfer; the job controls exactly what is copied The VPS must accept SSH from the runner and the runner needs the private key
How files reach the VPS Server pulls a GitLab artifact Can reduce direct file transfer from the runner and fit a pull-based network design The VPS needs artifact credentials and outbound access; token scope and expiry require careful management
Release layout In-place replacement Few moving parts and low disk usage Partial copies can leave a mixed release; rollback is harder
Release layout Versioned directories with a current link Atomic switch and quick rollback to a retained release Uses more disk and requires cleanup and service-path discipline
Promotion Automatic on default branch Fast feedback and low operational overhead A merged change reaches production without a human checkpoint
Promotion Manual or protected promotion Useful for risky migrations and scheduled releases Someone must approve and start the job

There is no universally superior row. Select the combination that matches your failure impact, network rules, and rollback requirements, then encode it in the script and environment policy rather than relying on operator memory.

Prevent overlapping and outdated deployments

Two pipelines can otherwise deploy in an unsafe order: an older commit may finish after a newer one and replace it. Set resource_group: production so only one production deployment job runs at a time. Configure workflow and job rules so obsolete branch pipelines do not compete with the protected default-branch pipeline, and use GitLab’s deployment-safety controls to prevent outdated jobs from replacing newer deployments.

Serialization does not decide which commit should win by itself. The job rules, cancellation policy, and release script must make that decision explicit. If a newer pipeline supersedes an older one, cancel or prevent the older deployment before it acquires the production resource. If a deployment has already started, let the script finish safely or provide a controlled abort path; do not kill it halfway through a database migration.

Production security checklist

  • Use a dedicated, non-root deploy account and a dedicated automation key.
  • Protect the production environment and all production variables; expose them only to protected branches or tags.
  • Scope variables to the production environment when the project has multiple environments.
  • Verify the VPS host key instead of accepting unknown hosts automatically.
  • Keep the private key in a file-type CI/CD variable, restrict its permissions in the job, and rotate it on a schedule and after any suspected exposure.
  • Use a runner tag dedicated to production and isolate that runner from unrelated projects.
  • Avoid privileged containers and host PID namespace sharing on self-managed runners unless the requirement is narrowly justified and controlled.
  • Do not print environment variables, private-key contents, or connection strings in job output.
  • Limit the deploy user’s filesystem and sudo permissions to the application and required service operation.
  • Retain deployment history, release identifiers, and service logs long enough to investigate failures.

Rollback planning

Rollback is a release operation, not an emergency copy-and-paste exercise. A versioned layout lets the script repoint current to the previous healthy release, restart or reload the service, and run the same health check. Keep the artifact or release directory for every version that your recovery policy promises to support. If a database migration is not backward-compatible, application rollback alone may be unsafe; design an explicit migration rollback or a forward-fix procedure before enabling automatic production deployment.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

After a rollback, record which commit is live and why the newer release failed. Fix the pipeline or application, run tests again, and deploy a new forward release rather than repeatedly toggling versions without understanding the failure.

Troubleshooting common failures

Permission denied (publickey)

  • Confirm that SSH_PRIVATE_KEY is a file variable and that the job runs on a protected branch or tag allowed to read it.
  • Check that the public key is in the intended deploy user’s authorized_keys, with correct ownership and modes.
  • Verify that VPS_USER, VPS_HOST, and VPS_PORT identify the same server tested manually.
  • Ensure the key format is supported by the runner’s OpenSSH client and that ssh-agent actually loaded it.

Host-key verification fails

The stored VPS_KNOWN_HOSTS value may be stale, incomplete, or for a different hostname. Compare the server’s fingerprint through a trusted channel, regenerate the known-hosts entry, and update the protected variable. Do not “fix” the job by disabling host-key checking.

rsync cannot write the destination

Check that DEPLOY_PATH exists or that the deploy script can create it, that the deploy user owns the upload location, and that disk space and inode availability are sufficient. Remember that --delete removes destination files absent from the artifact; use it only when the destination is dedicated to that release content.

The script runs but the service is unhealthy

Run the script manually as the deploy user with the same path and environment assumptions. Inspect service-manager status and logs, verify runtime and configuration files, and check that the health endpoint is reachable from the VPS. A failed health check should leave the previous release available and should return a non-zero exit status.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Two deployments still appear to run together

Confirm that every production job uses the exact same resource_group value and that there is not a second deploy job with different rules. Check whether a deployment is being started outside GitLab, such as by a separate scheduled task or administrator shell. Resource groups serialize matching GitLab jobs; they cannot control an unrelated process.

Verification before enabling production

  1. Run the complete pipeline against a staging VPS with a separate key and environment variables.
  2. Confirm that a failed test prevents the deploy job from becoming runnable.
  3. Confirm that the deploy job can connect only as the non-root account and only on the intended port.
  4. Change a harmless file, deploy it, and verify the expected commit identifier on the VPS.
  5. Intentionally fail the health check and verify that GitLab reports failure and the previous release remains recoverable.
  6. Start two pipelines close together and verify that the production resource group prevents unsafe overlap.
  7. Rotate the deployment key and host-key variable in a controlled maintenance window, then revoke the old public key.

Once these checks pass, GitLab CI/CD is acting as a controlled delivery mechanism rather than an unrestricted remote shell: tests gate the release, protected variables limit access, the runner is treated as production infrastructure, and the VPS script owns the final deployment and recovery behavior.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
Outdated Drivers Are Slowing You DownFree scan - exact matches
Windows Errors? Fix Them Before They SpreadFree repair scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.