Deploy with GitLab CI and restart a service
This example builds a Node.js project, uploads the build over password-authenticated SFTP, and restarts one Zaroz Cloud service through the API. The SFTP password transfers files; a separate fine-grained API token controls only the restart.
The calls used are POST /service-instances/{id}/restart and GET /service-instances/{id}/resources from the API reference. To deploy a container image instead of uploading files, see Deploy from CI/CD.
What you need
From the service's page in the console, collect the SFTP host, port, username, password, and destination path.
Create a dedicated API token with these two grants, both scoped to the exact service being deployed (its service instance id, as in the console URL). See API tokens for how to scope a token:
services.read— lets the job wait for the server to come back.services.power— lets the job restart the server.
Do not give a deployment token terminal, billing, database, or account-wide access.
Add protected CI/CD variables
In GitLab, open Settings → CI/CD → Variables and add:
| Variable | Type | Recommended flags |
|---|---|---|
ZAROZ_API_TOKEN | Variable | Masked, protected |
ZAROZ_SERVICE_ID | Variable | Protected |
ZAROZ_SFTP_HOST | Variable | Protected |
ZAROZ_SFTP_PORT | Variable | Protected |
ZAROZ_SFTP_USER | Variable | Protected |
ZAROZ_SFTP_PATH | Variable | Protected |
ZAROZ_SFTP_PASSWORD | Variable | Masked, protected |
ZAROZ_SFTP_KNOWN_HOSTS | File | Protected |
Generate ZAROZ_SFTP_KNOWN_HOSTS from a trusted computer and verify the displayed host fingerprint before storing it. Do not use StrictHostKeyChecking=no in a deployment pipeline.
Protect the deployment environment
Protected variables are only available to protected branches or tags. Configure GitLab's production environment protection so an untrusted merge request cannot exfiltrate either credential.
Add .gitlab-ci.yml
This example expects npm run build to produce a dist/ directory. Change the build command and local directory for your project.
Code
Why the job restarts in place and then waits
restart bounces the server without passing through a stopped state that your script would have to observe, so there is no stop-then-start race. The restart takes time to finish, so the job reads the primary resource's status until it is running, and gives GitLab a useful failure reason if it becomes failed or crash_looping instead.
For software that supports graceful reloads, prefer its own reload mechanism. A stop/start cycle interrupts active players or users.
Adapt the upload
The SFTP batch above overwrites matching files but does not delete remote files that disappeared from dist/. If your release must be an exact mirror, deploy into a versioned directory and atomically switch releases from your application's own startup script.
Never upload secrets from the repository. Keep runtime secrets in the Zaroz dashboard or protected CI/CD variables.
Troubleshooting
The API returns 403
Confirm both token grants are scoped to the same UUID in ZAROZ_SERVICE_ID. The owning user must also still be allowed to control that service.
SFTP reports a host-key error
Update ZAROZ_SFTP_KNOWN_HOSTS only after verifying the new fingerprint through a trusted channel. Do not disable verification.
The upload works but the restart does not
Check that services.power was selected, not only services.read, and that the token has not expired.
The server does not return to running within about a minute
Let the job fail rather than repeatedly restarting it. Inspect the service in the console (and its logs) and retry the deployment once the cause is fixed.
