Reference
MSBuild & CI
Protect your assemblies automatically on every build and in your CI pipeline.
For production, protect automatically rather than by hand. Nebula fits into both MSBuild and any CI system.
Nebula obfuscates your compiled assemblies, not your source. That means there is no source-code dependency: no attributes, no using, no API calls, and (with the CLI) not even a package reference in your projects. Your code stays completely Nebula-free; protection is applied to the build output.
Obfuscate only on the build server
A common requirement: developer builds stay unobfuscated; only the build that produces your official, shippable packages is protected. Because MSBuild automatically exposes environment variables as build properties, you gate obfuscation on a variable that exists only on the build agent — same source, same dotnet build, no flags, no code changes.
Build integration is a licensed feature. The Free edition is the CLI and desktop app only; obfuscating as part of a build requires a license on the build machine.
Two ways to license a build machine (don’t confuse them):
- Online key — run
nebula register --key LIC-…once on the agent. Best for a persistent build machine (it uses one seat for that machine).- Offline signed license file — set
NEBULA_LICENSE(orlicenseFilein the config, or theNebulaLicenseFileMSBuild property) to the path of a signed.licensefile. Best for ephemeral CI runners, since it needs no online seat activation.NEBULA_LICENSEis a file path, not a key — aLIC-…string there won’t resolve.
Option A — Nebula’s MSBuild task, gated by an environment variable. Nebula’s target only runs when the NebulaObfuscate property is true, and MSBuild reads that from the environment. On the build agent set:
NebulaObfuscate=true
NEBULA_LICENSE=C:\keys\nebula-license.json # path to a signed license file (or activate an online key once with: nebula register --key LIC-…)
Every build on that agent is obfuscated after compile; developer machines (variable absent) build exactly as before. This uses Nebula’s build-time MSBuild package (a build dependency with PrivateAssets, not a source/runtime dependency).
Option B — zero package reference (fully source- and dependency-free). A small build-infra file checked into the repo invokes the Nebula CLI on the output, gated by your own environment variable. It references no Nebula package or API:
<!-- Directory.Build.targets at the repo root -->
<Project>
<Target Name="NebulaObfuscate" AfterTargets="Build" Condition="'$(NEBULA_OBFUSCATE)' == '1'">
<Exec Command="nebula --config "$(MSBuildProjectDirectory)/nebula.config.json" --output "$(TargetDir)obf"" />
</Target>
</Project>
On the build agent set NEBULA_OBFUSCATE=1 (plus NEBULA_LICENSE=…) and install the nebula CLI. Developer boxes — where the variable isn’t set — skip the step and build unobfuscated. Nothing in your .csproj or C# references Nebula.
Setting the variables on the build agent
Set these once on the build machine, as the account your builds run under. Use whichever shell your agent uses (for Option A use NebulaObfuscate; for Option B use NEBULA_OBFUSCATE).
Windows — Command Prompt (cmd):
:: Persistent (applies to future build sessions):
setx NEBULA_OBFUSCATE 1
setx NEBULA_LICENSE "C:\keys\nebula-license.json"
:: Just the current session:
set NEBULA_OBFUSCATE=1
set NEBULA_LICENSE=C:\keys\nebula-license.json
Windows — PowerShell:
# Persistent, machine-wide (run PowerShell as Administrator):
[Environment]::SetEnvironmentVariable('NEBULA_OBFUSCATE', '1', 'Machine')
[Environment]::SetEnvironmentVariable('NEBULA_LICENSE', 'C:\keys\nebula-license.json', 'Machine')
# Just the current session:
$env:NEBULA_OBFUSCATE = '1'
$env:NEBULA_LICENSE = 'C:\keys\nebula-license.json'
Linux / macOS build agents (bash):
# Add to the agent's service environment or profile:
export NEBULA_OBFUSCATE=1
export NEBULA_LICENSE=/etc/nebula/nebula-license.json
Most CI systems also let you define these as pipeline/agent variables in their UI — set them on the build agent only, never in the repo. After setx or a machine-level change, restart the agent/shell so new builds pick them up.
For a multi-assembly product, obfuscate the published output as one step (all DLLs together) rather than per project, so cross-assembly references stay consistent — use
AfterTargets="Publish"or a dedicated release step, gated the same way. See Multiple assemblies.
In CI
Because the CLI is config-driven and returns meaningful exit codes, wiring it into a pipeline is a single step:
nebula --config nebula.config.json --json nebula-summary.json
If protection fails (bad config, missing license), the non-zero exit code fails the build. The --json summary can be archived as a build artifact.
Licensing in CI
CI runners are machines too, so an online activation uses a seat per machine. Choose by runner type:
- Persistent / self-hosted runner: activate once with
nebula register --key LIC-…. It uses one seat for that machine and every build reuses it. - Ephemeral runner (e.g. GitHub-hosted — a fresh VM each run): use an offline signed license file so you don’t burn a new seat every run. Store it as a secret, write it to a file in the job, and point
NEBULA_LICENSEat that path (not the key). Ask us for an offline license file for your build pipeline.
MSBuild integration
Nebula can run as part of dotnet build / dotnet publish so your output is protected without a separate step. The target runs after the compile and is controlled by MSBuild properties (any of which can come from an environment variable on the build agent, as above):
<PropertyGroup>
<NebulaObfuscate>true</NebulaObfuscate> <!-- set only where you want protection -->
<NebulaConfigFile>nebula.config.json</NebulaConfigFile> <!-- or use the individual switches below -->
<NebulaOutputDirectory>$(OutputPath)obf</NebulaOutputDirectory>
<NebulaPreservePublicApi>true</NebulaPreservePublicApi>
<NebulaControlFlow>true</NebulaControlFlow>
<NebulaEncryptStrings>true</NebulaEncryptStrings>
<NebulaStrongNameKeyFile>keys/mykey.snk</NebulaStrongNameKeyFile>
<NebulaLicenseFile>keys/nebula.license</NebulaLicenseFile> <!-- build integration is licensed -->
</PropertyGroup>
Because NebulaObfuscate is just a property, leaving it unset (the default) means dev builds do nothing, while an environment variable of the same name on the build agent turns it on there automatically.
Tip: keep
nebula.config.jsonin source control alongside your project so protection settings are versioned with your code.
Licensing only the build server
Because you obfuscate on the build server, you only need to license the build machine(s) — not every developer. Nebula licensing is per-machine: on a persistent agent activate an online key with nebula register --key LIC-…, or point NEBULA_LICENSE / licenseFile at the path of an offline signed license file (best for ephemeral runners). Developers need nothing installed.