Configuration
Configuration File
The service reads its settings from appsettings.json, located in the same directory as the executable. The Jenkins section contains all service-specific settings.
Settings Reference
| Setting | Required | Default | Description |
|---|---|---|---|
JenkinsURL |
Yes | — | Full Jenkins URL including port. Must include an explicit port — default ports (80/443) are rejected. Example: https://jenkins.example.com:8443 |
AgentName |
No | Machine hostname | The agent/node name as configured in Jenkins. Case-sensitive. |
AgentSecret |
Yes | — | The JNLP secret generated by Jenkins for this agent. Case-sensitive. |
JavaPath |
No | JAVA_HOME env var |
Full path to the JDK/OpenJDK bin folder. Example: C:\Program Files\Java\jdk-21.0.2\bin |
CustomArguments |
No | (empty) | Additional arguments passed to java.exe. Space-separated, supports quoted values and escaped quotes (\"). Example: -noCertificateCheck |
DebugMode |
No | false |
true to enable debug-level logging, false to disable. |
CompactLog |
No | false |
true to write CLEF (Compact Log Event Format) JSON to agent.clef instead of human-readable agent.log. |
RetainedLogs |
No | 3 |
Number of rolled log files to keep. Oldest are permanently deleted (skips recycle bin). |
MaxRetries |
No | 0 |
Maximum auto-recovery attempts before the watchdog gives up. 0 = infinite retries (recommended). |
SecretMode |
No | Unprotected |
How AgentSecret is stored/resolved. See Secret Protection Modes below. |
JSON Format
{
"Jenkins": {
"JenkinsURL": "https://jenkins.example.com:8443",
"AgentSecret": "your-agent-secret-here",
"SecretMode": "Unprotected",
"AgentName": "",
"JavaPath": "",
"CustomArguments": "",
"DebugMode": false,
"CompactLog": false,
"RetainedLogs": 3,
"MaxRetries": 0
},
"Telemetry": {
"Enabled": false,
"OtlpEndpoint": "http://localhost:4317",
"ServiceName": "JenkinsAsService"
}
}
The AgentName defaults to the machine hostname if left empty. This is usually the correct value unless the Jenkins node name differs from the hostname.
Validation Flow
flowchart TD
A["Read appsettings.json"] --> B["Bind to ServiceSettings via IOptions"]
B --> C{JenkinsURL filled?}
C -->|No| D[Log error & stop]
C -->|Yes| E{AgentSecret filled?}
E -->|No| D
E -->|Yes| F["Parse URL via System.Uri"]
F --> G{Explicit port?}
G -->|No / default port| D
G -->|Yes| H[Resolve Java path]
H --> I["Test TCP connectivity (2s timeout)"]
I -->|Fail| D
I -->|Pass| J["Download agent.jar (ETag cached)"]
J --> K[Start agent + watchdog]
Java Path Resolution
The service resolves the Java executable in this order:
- Use
JavaPathfrom config if set andjava.exeexists at that path - Fall back to
JAVA_HOMEenvironment variable root - Fall back to
JAVA_HOME\bin - If none work → log error and stop
URL Validation
The JenkinsURL is parsed using System.Uri:
- Must be a valid URI (parse failure → error)
- Must include an explicit port —
Uri.IsDefaultPortrejects 80/443 since Jenkins typically runs on non-standard ports - TCP connectivity is tested asynchronously with a 2-second timeout
Secret Protection Modes
SecretMode controls how the AgentSecret is stored and resolved at runtime.
| Mode | AgentSecret field contains |
How resolved |
|---|---|---|
Unprotected |
Plaintext secret | Returned as-is |
Dpapi |
Base64-encoded DPAPI ciphertext | ProtectedData.Unprotect (machine-scoped, non-portable) |
EnvironmentVariable |
Name of a system env var (default: JENKINS_SECRET) |
Environment.GetEnvironmentVariable(..., Machine) |
CredentialManager |
Windows Credential Manager target name | CredentialManager.GetCredentials(targetName).Password |
DPAPI mode binds the secret to the machine. Moving appsettings.json to another machine will fail decryption. Re-run update-secret after a machine migration.
CLI: update-secret
The JenkinsAsService.exe update-secret subcommand writes (or re-writes) appsettings.json with the secret processed for the chosen mode. Used by the MSI installer and manually.
JenkinsAsService.exe update-secret [options]
--secret <value> Plaintext secret (command-line)
--secret-file <path> Read from file (deleted after reading)
--secret-env <var> Read from named environment variable
--url <value> Jenkins controller URL
--mode <value> Dpapi | EnvironmentVariable | CredentialManager | Unprotected
--agent-name <value> Node name (default: hostname)
--java-path <value> Java bin folder (default: JAVA_HOME)
--impersonate Run Credential Manager write as a different user
--username <value> Username for impersonation (DOMAIN\user)
--silent Non-interactive (all values from flags)
In silent mode with --impersonate, provide the password via the JAS_IMPERSONATE_PASSWORD environment variable to avoid command-line exposure.
Telemetry (OpenTelemetry)
Disabled by default. Set Enabled: true to export metrics via OTLP.
| Setting | Default | Description |
|---|---|---|
Enabled |
false |
Enable OpenTelemetry metrics export |
OtlpEndpoint |
http://localhost:4317 |
OTLP gRPC endpoint (Datadog agent, Grafana Alloy, etc.) |
ServiceName |
JenkinsAsService |
service.name resource attribute |
Exported metrics:
jenkins_agent_restarts_total— counter, increments on each successful agent restartjenkins_agent_severe_events_total— counter, increments on eachSEVERE:log line- .NET runtime metrics (GC, thread pool, memory) via
OpenTelemetry.Instrumentation.Runtime