CI/CD Pipelines for Tor Hidden Services: Automated Anonymous Deployment
Continuous integration and deployment pipelines for Tor hidden services must operate entirely within the .onion ecosystem to maintain anonymity. A pipeline that sends code to a clearnet CI service (GitHub Actions, CircleCI, Travis CI) before deploying to a .onion server exposes the developer's code and identity to clearnet infrastructure that may log, scan, and retain it. A fully .onion-native CI/CD pipeline: code lives in a .onion Gitea or Forgejo repository, CI jobs run on .onion-accessible runners, deployment targets the production .onion server via SSH over Tor, and notifications go through Tor-routed channels. This guide covers building this complete pipeline with Woodpecker CI (a lightweight, Forgejo-native CI system), Gitea Actions (compatible with GitHub Actions syntax), and deployment via SSH over Tor.
Need this done for your project?
We implement, you ship. Async, documented, done in days.
A fully anonymous CI/CD pipeline consists of: (1) Source code repository: Gitea or Forgejo running as a .onion hidden service. Developers push via SSH over Tor (ProxyCommand nc -x 127.0.0.1:9050 in ~/.ssh/config). (2) CI system: Woodpecker CI or Gitea Actions, both running as hidden services on the same or separate .onion servers. Webhooks from Gitea/Forgejo trigger CI jobs over .onion-to-.onion HTTP. (3) CI runners: agents that execute the CI jobs, running in Docker containers on a .onion-accessible server. Runners pull job definitions from the CI server via Tor. (4) Deployment target: the production .onion server, accessed via SSH over Tor from the CI runner. SSH keys for deployment stored in the CI server's secret management system. (5) Notifications: job completion notifications via Tor-routed webhook to a .onion messaging system (XMPP, Matrix) or directly via Tor to a Telegram bot API.
Woodpecker CI on .onion Setup
Woodpecker CI is a lightweight, pipeline-defined CI system (similar to Drone CI) that integrates natively with Gitea/Forgejo. Deploy Woodpecker CI server: create a Gitea OAuth2 application for Woodpecker authentication, run woodpecker-server Docker container with WOODPECKER_HOST=http://your-onion.onion, WOODPECKER_GITEA=true, WOODPECKER_GITEA_URL=http://your-gitea-onion.onion, WOODPECKER_GITEA_CLIENT/SECRET from the OAuth2 app. Create a .onion hidden service for Woodpecker's web UI and API (port 8000). Expose this via Tor HiddenServicePort 80 127.0.0.1:8000. Configure Woodpecker agent (runner): WOODPECKER_SERVER=http://your-woodpecker-onion.onion, WOODPECKER_AGENT_SECRET=shared-secret. The agent connects to the Woodpecker server through Tor. For the agent to route its outbound connections through Tor: set https_proxy and http_proxy environment variables to socks5://127.0.0.1:9050 in the Docker Compose for the agent.
Pipeline Definition and Automated Testing
Woodpecker uses .woodpecker.yml in the repository root to define pipelines (similar to GitHub Actions YAML). Example pipeline for a Node.js .onion service: steps: test: image: node:18-alpine, commands: [npm ci, npm test], pull: true, environment: [https_proxy=socks5://127.0.0.1:9050]. The proxy environment variable ensures any npm install or test network calls route through Tor. For Python services: use python:3.11-slim image with pip install -r requirements.txt and pytest. For security scanning: include a SAST step with Semgrep or Bandit as a pipeline step before deployment. Test isolation: each pipeline step runs in a fresh Docker container - no state persists between steps unless mounted via volumes. For .onion services that need to test Tor connectivity itself, mount the host's Tor socket (/var/run/tor/control.authcookie) into the test container.
Automated Deployment via SSH over Tor
The deployment step SSHes to the production .onion server over Tor. Configuration: store the production server's SSH private key as a Woodpecker secret (DEPLOY_SSH_KEY). In the pipeline deployment step: add an SSH config file with ProxyCommand nc -x 127.0.0.1:9050 %h %p for .onion hosts, write the private key from the secret to a temp file, run ssh -i /tmp/deploy_key deployuser@yourprod.onion deploy-script.sh. The Woodpecker agent's network is proxied through Tor (via environment variable), so the SSH connection to the production .onion server routes through Tor. Deployment script on the production server: git pull origin main, docker-compose up -d --build (or systemctl restart service). After successful deployment, the pipeline can verify the deployment by curling the production .onion service's health check endpoint via Tor.
Secret Management in .onion CI/CD
CI/CD pipelines require secrets: SSH keys for deployment, API keys for services, database credentials for tests. Woodpecker's built-in secret management encrypts secrets at rest in its database and injects them as environment variables during pipeline execution. Secrets are never visible in pipeline logs. For external secret management: HashiCorp Vault can be deployed as a .onion hidden service and queried from pipeline steps via Tor. Configure Vault's API accessible at vault.onion:8200 and retrieve secrets in pipeline steps via curl through Tor. For the highest security: secrets that are only needed once per deployment (one-time tokens, TOTP codes) should be generated per deployment rather than stored. Rotate long-lived secrets (SSH keys, API tokens) quarterly and update in Woodpecker's secret store. Monitor secret usage: Woodpecker logs which secrets are accessed per pipeline run.