Quick Deploy¶
Jenkins running from scratch in under 30 minutes.
Prerequisites¶
- Docker Desktop installed and running
- Git and GitHub CLI (
gh) installed - A GitHub account
- A domain managed by Cloudflare (or use a temporary tunnel for testing)
Step 1 — Clone this repo¶
Step 2 — Set up Cloudflare Tunnel¶
Jenkins needs a public URL for GitHub webhooks and OAuth callbacks. Do this before creating the GitHub Apps so you have the URL ready.
Full instructions: Cloudflare Tunnel
Output: a stable public URL (e.g. https://jenkins.yourdomain.com) and a tunnel token for .env.
Step 3 — Create GitHub Apps¶
Two separate GitHub Apps are required:
| App | Purpose | What you get |
|---|---|---|
| Jenkins CI App | Reads repos, posts build status, manages webhooks | App ID + private key .pem + webhook secret |
| Jenkins Login App | User login via GitHub account | Client ID + Client Secret |
Full instructions: GitHub Apps Setup
Step 4 — Configure .env¶
Open .env and fill in the required values. Every variable is documented with a comment explaining
its purpose, valid values, and when to change it. Minimum required set:
# Core — Jenkins credentials and public URL
JENKINS_ADMIN_PASSWORD=<strong-random-password>
JENKINS_URL=https://jenkins.yourdomain.com
# Cloudflare — tunnel token from Step 2
CLOUDFLARE_TUNNEL_TOKEN=<your-tunnel-token>
# GitHub identity
GITHUB_USERNAME=<your-github-username>
GITHUB_ADMIN_USERNAME=<your-github-username>
GITHUB_ORG=<your-github-org-or-username>
# Jenkins CI App from Step 3
GITHUB_APP_ID=<numeric-app-id>
GITHUB_WEBHOOK_SECRET=<random-secret-matching-app-settings>
# Jenkins Login App from Step 3
GITHUB_OAUTH_CLIENT_ID=<oauth-client-id>
GITHUB_OAUTH_CLIENT_SECRET=<oauth-client-secret>
Full variable reference: Configuration
Step 5 — Add the Jenkins CI App private key¶
Copy the .pem file downloaded during GitHub App creation into the repo root:
Never commit this file
github-app.pem is gitignored. Keep it that way. Anyone with this key can authenticate as
your Jenkins CI App against every repo it has access to.
Step 6 — Choose services and start the stack¶
Services are grouped by Docker Compose profile. Core (Jenkins + tunnel) always starts.
Add optional service groups via COMPOSE_PROFILES in .env:
| Profile | Services | When to use |
|---|---|---|
| (none — default) | Jenkins + Cloudflare tunnel | Minimal setup, CI only |
reporting |
+ Allure test reporting | Rich test result history and trend graphs |
full |
Everything | All platform features |
# Optional — set a profile before starting
echo "COMPOSE_PROFILES=reporting" >> .env
# Build the Jenkins image and start all configured services
docker compose up --build -d
First build
The first up --build takes a few minutes — Jenkins installs all plugins during image build.
Subsequent starts are fast.
Stream logs to confirm a clean startup:
Wait for Jenkins is fully up and running in the Jenkins container output.
If you enabled reporting, Allure is at:
Step 7 — Log in¶
Open http://localhost:8080 (or your public Cloudflare URL).
Log in with GitHub via the OAuth button. The account set as GITHUB_ADMIN_USERNAME is
pre-configured as admin via casc.yml.
Step 8 — Create the GitHub Organization Folder job¶
One-time manual step. Will be automated in a future phase via seed job — until then:
- New Item → name it
<your-github-username>→ select GitHub Organization - Credentials: select
jenkins-ci-app - Owner:
<your-github-username> - Behaviors: leave defaults (discovers branches and PRs)
- Fork PR trust — set Discover fork pull requests → Trust to match
JENKINS_FORK_PR_TRUSTin.env:
| Value | Who triggers CI on fork PRs | Trade-off |
|---|---|---|
nobody |
No one — all require manual approval | Maximum security |
contributors |
Authors with a previously merged PR | Chicken-and-egg for first PRs |
collaborators |
Explicitly added repo collaborators | Recommended |
organization |
All GitHub org members | Good for trusted teams |
everyone |
Anyone | Do not use — pipelines have credential access |
- Save — Jenkins scans your account and creates a job for every repo containing a
Jenkinsfile
From here, any new repo with a Jenkinsfile is picked up automatically. If the tunnel drops,
Jenkins rescans on the JENKINS_FOLDER_SCAN_INTERVAL schedule as a fallback. GitHub also retries
failed webhook deliveries for up to 3 days.
Step 9 — Verify¶
Push a commit to any repo with a Jenkinsfile. Within seconds:
- A build appears in Jenkins (via webhook)
- Build status is posted back to the GitHub commit or PR
Updating Jenkins¶
To apply config changes (plugins, casc.yml, Dockerfile):
Jenkins reloads JCasC automatically on restart. Build history is preserved in the jenkins_home volume.
Teardown¶
Stop the stack without losing data:
Full wipe — irreversible
docker compose down -v permanently destroys the jenkins_home, allure_results, and
allure_reports volumes. All build history and Allure trend data is gone.
Before running -v, configure publishArtifacts() with an external artifact backend
(S3, Azure Blob, etc.) to preserve Allure history. See Configuration.