Skip to content
WebShield Docs

The app updates itself after a push to a private repository

Deploy a Node.js, Python, Go or Docker app from GitHub Actions, GitLab CI, Gitea or Forgejo — without opening repository access and without a server of your own.

Deploying from a private repository usually means giving the platform access to it. Here it is not needed: the code is already on the CI runner, and the job sends it to us as an archive.

The solution is a CI job that runs webshield apps deploy on every push to main with a token that can deploy one project and nothing else.

What you get: every push to main is built and rolled out; a failed build turns the CI job red while the previous version keeps serving. You need: an app created with us and a repository on GitHub, GitLab, Gitea or Forgejo. Time: 10 minutes.

In the control panel: Services → Apps → project → Token for CI → Issue token. Copy it right away: it is shown in full only once.

The token can only deploy apps of this project and read their status and log. Variables, domains, other projects and the rest of the account are out of its reach. You can revoke it in the same place.

Name it WS_TOKEN so the CLI picks it up without extra flags.

  • GitHub, Gitea, Forgejo: Settings → Secrets → Actions → New secret.
  • GitLab: Settings → CI/CD → Variables, with Masked and Protected checked.

webshield.toml at the repository root:

[app]
project = "shop"
name = "web"

Exclude whatever the build does not need (node_modules, build output, test data) with .gitignore or .webshieldignore: a smaller archive deploys faster. The limit is 100 MB.

GitHub Actions, Gitea, Forgejo:

# .github/workflows/deploy.yml (Gitea and Forgejo: .gitea/workflows/ or .forgejo/workflows/)
name: Deploy app
on:
push:
branches: [main]
# Several pushes in a row — the last one wins.
concurrency:
group: deploy-app
cancel-in-progress: true
jobs:
deploy:
runs-on: ubuntu-latest
env:
WS_TOKEN: ${{ secrets.WS_TOKEN }}
steps:
- uses: actions/checkout@v5
- name: Install the CLI
run: curl -fsSL https://raw.githubusercontent.com/webshieldpro/webshield-cli/main/install.sh | sh
- name: Deploy
run: ~/.local/bin/webshield apps deploy

GitLab CI:

.gitlab-ci.yml
deploy:
image: debian:stable-slim
rules:
- if: $CI_COMMIT_BRANCH == "main"
interruptible: true
script:
- apt-get update -qq && apt-get install -yqq curl ca-certificates
- curl -fsSL https://raw.githubusercontent.com/webshieldpro/webshield-cli/main/install.sh | sh
- ~/.local/bin/webshield apps deploy

There is no need to build in CI: the build happens on our side, by Dockerfile or by the project’s stack.

Push. The job log shows status: building, status: deploying and deployment #N is live. Open the app address — it serves the new version.

Symptom Cause and fix
app … not found The names in webshield.toml differ from the panel, or the token belongs to another project.
403 on deploy The token was revoked or is not a CI token. Issue a new one and update the secret.
the archive is larger than 100 MB Dependencies or build output got into the archive — add them to .gitignore or .webshieldignore.
The job fails with a build log The app build failed: the log is in the job output and in the panel (Build log). The previous version keeps serving.
Another deployment of this service is in progress The previous deployment is still running. The concurrency block above removes this race.