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.
1. Issue a token for CI
Section titled “1. Issue a token for CI”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.
2. Store the token as a repository secret
Section titled “2. Store the token as a repository secret”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.
3. Describe the app next to the code
Section titled “3. Describe the app next to the code”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.
4. Add the deploy job
Section titled “4. Add the deploy job”GitHub Actions, Gitea, Forgejo:
# .github/workflows/deploy.yml (Gitea and Forgejo: .gitea/workflows/ or .forgejo/workflows/)name: Deploy appon: 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 deployGitLab CI:
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 deployThere 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.
Troubleshooting
Section titled “Troubleshooting”| 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. |
What’s next
Section titled “What’s next”- Apps — variables, domain, log, rollback.
- Command-line client — every CLI command.
- API tokens — general tokens with the Apps area.