---
title: "Jenkins Setup and Configuration: Installation, JCasC, Plugins, Credentials, and Agents"
description: "Installing Jenkins via Docker, Helm on Kubernetes, or package managers, then configuring it declaratively with JCasC, managing plugins, credentials, and build agents."
url: https://agent-zone.ai/knowledge/cicd/jenkins-setup-and-configuration/
section: knowledge
date: 2026-02-22
categories: ["cicd"]
tags: ["jenkins","cicd","jcasc","helm","kubernetes","docker"]
skills: ["jenkins-administration","cicd-setup"]
tools: ["jenkins","docker","helm","kubectl"]
levels: ["intermediate"]
word_count: 784
formats:
  json: https://agent-zone.ai/knowledge/cicd/jenkins-setup-and-configuration/index.json
  html: https://agent-zone.ai/knowledge/cicd/jenkins-setup-and-configuration/?format=html
  api: https://api.agent-zone.ai/api/v1/knowledge/search?q=Jenkins+Setup+and+Configuration%3A+Installation%2C+JCasC%2C+Plugins%2C+Credentials%2C+and+Agents
---


# Jenkins Setup and Configuration

Jenkins is a self-hosted automation server. Unlike managed CI services, you own the infrastructure, which means you control everything from plugin versions to executor capacity. This guide covers the three main installation methods and the configuration patterns that make Jenkins manageable at scale.

## Installation with Docker

The fastest way to run Jenkins locally or in a VM:

```bash
docker run -d \
  --name jenkins \
  -p 8080:8080 \
  -p 50000:50000 \
  -v jenkins_home:/var/jenkins_home \
  jenkins/jenkins:lts-jdk17
```

Port 8080 is the web UI. Port 50000 is the JNLP agent port for inbound agent connections. The volume mount is critical -- without it, all configuration and build history is lost when the container restarts.

Retrieve the initial admin password:

```bash
docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword
```

## Installation with Helm on Kubernetes

The `jenkins/jenkins` Helm chart is the standard approach for running Jenkins on Kubernetes:

```bash
helm repo add jenkins https://charts.jenkins.io
helm repo update

helm install jenkins jenkins/jenkins \
  --namespace jenkins \
  --create-namespace \
  -f jenkins-values.yaml
```

A practical `jenkins-values.yaml`:

```yaml
controller:
  image:
    tag: "lts-jdk17"
  resources:
    requests:
      cpu: "500m"
      memory: "1Gi"
    limits:
      cpu: "2"
      memory: "3Gi"
  serviceType: ClusterIP
  ingress:
    enabled: true
    hostName: jenkins.example.com
  installPlugins:
    - kubernetes:latest
    - workflow-aggregator:latest
    - git:latest
    - configuration-as-code:latest
    - credentials-binding:latest
  JCasC:
    configScripts:
      welcome-message: |
        jenkins:
          systemMessage: "Jenkins configured via Helm + JCasC"
persistence:
  enabled: true
  size: 20Gi
```

The `installPlugins` list runs during startup, so the controller pod comes up with everything it needs. The `JCasC.configScripts` block injects Configuration as Code YAML directly into the pod.

Get the admin password after install:

```bash
kubectl exec -n jenkins svc/jenkins -c jenkins -- cat /run/secrets/additional/chart-admin-password
```

## Installation with Package Managers

On Debian/Ubuntu:

```bash
curl -fsSL https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key | sudo tee /usr/share/keyrings/jenkins-keyring.asc > /dev/null
echo "deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc] https://pkg.jenkins.io/debian-stable binary/" | sudo tee /etc/apt/sources.list.d/jenkins.list > /dev/null
sudo apt update && sudo apt install jenkins
sudo systemctl enable --now jenkins
```

Jenkins runs on port 8080 by default. The initial password is at `/var/lib/jenkins/secrets/initialAdminPassword`.

## Jenkins Configuration as Code (JCasC)

JCasC eliminates manual UI configuration. You define Jenkins state in YAML files, and the configuration-as-code plugin applies them on startup or reload. Place YAML files in `$JENKINS_HOME/casc_configs/` or set the `CASC_JENKINS_CONFIG` environment variable.

A JCasC file covering common settings:

```yaml
jenkins:
  systemMessage: "Production Jenkins - managed by JCasC"
  numExecutors: 0  # no builds on controller
  securityRealm:
    local:
      allowsSignup: false
      users:
        - id: "admin"
          password: "${JENKINS_ADMIN_PASSWORD}"
  authorizationStrategy:
    roleBased:
      roles:
        global:
          - name: "admin"
            permissions:
              - "Overall/Administer"
            entries:
              - user: "admin"
          - name: "readonly"
            permissions:
              - "Overall/Read"
              - "Job/Read"
            entries:
              - user: "authenticated"
  nodes:
    - permanent:
        name: "build-agent-1"
        remoteFS: "/home/jenkins/agent"
        launcher:
          ssh:
            host: "agent1.internal"
            credentialsId: "agent-ssh-key"
            sshHostKeyVerificationStrategy: "knownHostsFileKeyVerificationStrategy"
        numExecutors: 4
        labels: "linux docker"

credentials:
  system:
    domainCredentials:
      - credentials:
          - usernamePassword:
              scope: GLOBAL
              id: "github-creds"
              username: "deploy-bot"
              password: "${GITHUB_TOKEN}"
          - basicSSHUserPrivateKey:
              scope: GLOBAL
              id: "agent-ssh-key"
              username: "jenkins"
              privateKeySource:
                directEntry:
                  privateKey: "${SSH_PRIVATE_KEY}"
          - string:
              scope: GLOBAL
              id: "slack-webhook"
              secret: "${SLACK_WEBHOOK_URL}"
```

Variable interpolation (`${VAR}`) pulls from environment variables, which keeps secrets out of the YAML. In Kubernetes, inject them from Kubernetes Secrets via the Helm chart's `controller.containerEnv` or `controller.additionalExistingSecrets`.

To reload JCasC without restarting Jenkins, go to Manage Jenkins > Configuration as Code > Apply new configuration, or hit the API:

```bash
curl -X POST "http://jenkins:8080/configuration-as-code/apply" \
  --user admin:$API_TOKEN
```

## Managing Plugins

Plugins are Jenkins's strength and its biggest maintenance burden. Key principles:

- **Pin versions in production.** Using `latest` in dev is fine; in production, pin: `kubernetes:4234.vdc5660543d1a`.
- **Use the Jenkins CLI or API for bulk operations:**

```bash
# List installed plugins
curl -s "http://jenkins:8080/pluginManager/api/json?depth=1" \
  --user admin:$API_TOKEN | jq '.plugins[] | {shortName, version}'

# Install a plugin via CLI
java -jar jenkins-cli.jar -s http://jenkins:8080/ install-plugin pipeline-stage-view -restart
```

- **The `installPlugins` list in the Helm chart** runs the `jenkins-plugin-cli` tool at startup. Plugins are downloaded before Jenkins boots, so the instance is ready immediately.

## Credentials Management

Jenkins credentials are scoped to domains and accessed by ID in pipelines. The three most common types:

1. **Username with password** -- for Git HTTPS, Docker registries, API tokens.
2. **SSH username with private key** -- for Git SSH, remote agents.
3. **Secret text** -- for webhook URLs, API keys, single-value secrets.

In a Jenkinsfile, bind credentials to environment variables:

```groovy
environment {
    DOCKER_CREDS = credentials('docker-registry')   // sets DOCKER_CREDS_USR and DOCKER_CREDS_PSW
    API_KEY = credentials('my-api-key')              // secret text, sets API_KEY directly
}
```

## Configuring Agents

Setting `numExecutors: 0` on the controller is a security and stability best practice. All builds should run on agents. Agents connect to Jenkins via SSH (Jenkins connects out to the agent) or JNLP/WebSocket (agent connects in to Jenkins).

For static agents, the JCasC `nodes` block shown above is the declarative approach. For dynamic agents on Kubernetes, the kubernetes plugin creates pods on demand -- see the Kubernetes integration article for details.

The key agent configuration parameters are `remoteFS` (the working directory on the agent), `labels` (used in pipeline `agent { label 'linux' }` directives), and `numExecutors` (how many concurrent builds the agent handles).

