/

Server Agent - Docker

Install the ByteHide Server Agent inside Docker containers for zero-code runtime protection. The agent is installed at image build time and protects all .NET 6+ processes in the container.


Key Difference vs Bare Metal

On a normal server, you run the installer once and it persists permanently. In Docker, the install happens at image build time, and you need to explicitly load the environment variables because Docker doesn't source /etc/profile.d/ or read the Windows Registry at runtime.


Linux Containers

Shell Script (No SDK Needed in Runtime Image)

DOCKERFILE
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY . .
RUN dotnet publish -c Release -o /app

FROM mcr.microsoft.com/dotnet/aspnet:8.0
WORKDIR /app
COPY --from=build /app .

# Install ByteHide Agent
RUN apt-get update && apt-get install -y --no-install-recommends curl ca-certificates \
    && rm -rf /var/lib/apt/lists/* \
    && curl -sSL https://raw.githubusercontent.com/bytehide/monitor-dotnet-agent/main/install.sh \
       | bash -s -- --token <your-token>

# Docker doesn't source /etc/profile.d/, so load env vars in entrypoint
ENTRYPOINT ["/bin/bash", "-c", "source /etc/profile.d/bytehide-agent.sh && exec dotnet myapp.dll"]

dotnet tool (If SDK Available in Build Stage)

DOCKERFILE
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY . .
RUN dotnet publish -c Release -o /app

# Install agent in the build stage (has SDK)
RUN dotnet tool install -g Bytehide.Monitor.AgentCli --version 1.0.5 \
    && /root/.dotnet/tools/bytehide-agent install --token <your-token>

FROM mcr.microsoft.com/dotnet/aspnet:8.0
WORKDIR /app
COPY --from=build /app .

# Copy agent files from build stage
COPY --from=build /opt/bytehide/agent /opt/bytehide/agent
COPY --from=build /etc/profile.d/bytehide-agent.sh /etc/profile.d/bytehide-agent.sh

ENTRYPOINT ["/bin/bash", "-c", "source /etc/profile.d/bytehide-agent.sh && exec dotnet myapp.dll"]

Alpine Linux

The installer auto-detects musl/Alpine. The only difference is using apk instead of apt:

DOCKERFILE
FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine
WORKDIR /app
COPY --from=build /app .

RUN apk add --no-cache curl bash \
    && curl -sSL https://raw.githubusercontent.com/bytehide/monitor-dotnet-agent/main/install.sh \
       | bash -s -- --token <your-token>

ENTRYPOINT ["/bin/bash", "-c", "source /etc/profile.d/bytehide-agent.sh && exec dotnet myapp.dll"]

Windows Containers

Windows Server Core

DOCKERFILE
FROM mcr.microsoft.com/dotnet/sdk:8.0-windowsservercore-ltsc2022 AS build
WORKDIR /src
COPY . .
RUN dotnet publish -c Release -o /app

FROM mcr.microsoft.com/dotnet/aspnet:8.0-windowsservercore-ltsc2022
WORKDIR /app
COPY /app .

# Install ByteHide Agent
SHELL ["powershell", "-Command"]
RUN & ([scriptblock]::Create((Invoke-WebRequest -Uri 'https://raw.githubusercontent.com/bytehide/monitor-dotnet-agent/main/install.ps1' -UseBasicParsing).Content)) -Token '<your-token>'

# Docker doesn't propagate Registry changes to runtime. Set env vars explicitly:
ENV DOTNET_STARTUP_HOOKS="C:\\Program Files\\ByteHide\\Agent\\Bytehide.Monitor.ServerAgent.dll"
ENV ASPNETCORE_HOSTINGSTARTUPASSEMBLIES="Bytehide.Monitor.ServerAgent"
ENV BYTEHIDE_MONITOR_TOKEN="<your-token>"
ENV BYTEHIDE_MONITOR_CONFIG="C:\\Program Files\\ByteHide\\Agent\\monitor.config.json"

ENTRYPOINT ["dotnet", "myapp.dll"]

Windows Nano Server

Nano Server doesn't have PowerShell by default. Use the dotnet tool approach in a multi-stage build:

DOCKERFILE
FROM mcr.microsoft.com/dotnet/sdk:8.0-nanoserver-ltsc2022 AS build
WORKDIR /src
COPY . .
RUN dotnet publish -c Release -o /app

# Install agent (SDK available in build stage)
RUN dotnet tool install -g Bytehide.Monitor.AgentCli --version 1.0.5
RUN bytehide-agent install --token <your-token>

FROM mcr.microsoft.com/dotnet/aspnet:8.0-nanoserver-ltsc2022
WORKDIR /app
COPY --from=build /app .

# Copy agent DLLs from build stage
COPY --from=build ["C:/Program Files/ByteHide/Agent", "C:/Program Files/ByteHide/Agent"]

ENV DOTNET_STARTUP_HOOKS="C:\\Program Files\\ByteHide\\Agent\\Bytehide.Monitor.ServerAgent.dll"
ENV ASPNETCORE_HOSTINGSTARTUPASSEMBLIES="Bytehide.Monitor.ServerAgent"
ENV BYTEHIDE_MONITOR_TOKEN="<your-token>"
ENV BYTEHIDE_MONITOR_CONFIG="C:\\Program Files\\ByteHide\\Agent\\monitor.config.json"

ENTRYPOINT ["dotnet", "myapp.dll"]

Docker Compose

Environment Variables via .env File

Instead of hardcoding the token in the Dockerfile, use Docker Compose with an env file:

docker-compose.yml:

YAML
services:
  myapp:
    build: .
    env_file:
      - bytehide.env
    ports:
      - "8080:8080"

bytehide.env:

ENV
DOTNET_STARTUP_HOOKS=/opt/bytehide/agent/Bytehide.Monitor.ServerAgent.dll
ASPNETCORE_HOSTINGSTARTUPASSEMBLIES=Bytehide.Monitor.ServerAgent
BYTEHIDE_MONITOR_TOKEN=bh_xxxxxxxxxxxx
BYTEHIDE_MONITOR_CONFIG=/opt/bytehide/agent/monitor.config.json

This way the Dockerfile only installs the agent files, and the environment variables come from Compose. Useful when the token differs per environment (staging, production).


Build Arguments for Tokens

Avoid hardcoding tokens in the Dockerfile:

DOCKERFILE
ARG BYTEHIDE_TOKEN
RUN curl -sSL https://raw.githubusercontent.com/bytehide/monitor-dotnet-agent/main/install.sh \
    | bash -s -- --token ${BYTEHIDE_TOKEN}

Build with:

Bash
docker build --build-arg BYTEHIDE_TOKEN=bh_xxxxxxxxxxxx -t myapp .

Or in CI/CD, inject from a secret:

Bash
docker build --build-arg BYTEHIDE_TOKEN=${{ secrets.BYTEHIDE_TOKEN }} -t myapp .

Verifying the Agent in Docker

After building and running the container:

Bash
# Check if the agent files are in the image
docker run --rm myapp ls /opt/bytehide/agent/

# Check if environment variables are set
docker run --rm myapp printenv | grep -E "DOTNET_STARTUP|BYTEHIDE|ASPNETCORE_HOSTING"

# Run the app and check for the agent init message
docker run --rm -e BYTEHIDE_DEBUG=true myapp
# Look for: [ByteHide Server Agent] Initialized (PID: xxxxx)

Platform Summary

Container OSInstall MethodEnv Vars
Linux (Debian/Ubuntu)curl | bash install.shsource /etc/profile.d/bytehide-agent.sh in entrypoint
Linux (Alpine)curl | bash install.sh (auto-detects musl)source /etc/profile.d/bytehide-agent.sh in entrypoint
Windows Server CorePowerShell install.ps1ENV in Dockerfile
Windows Nano Serverdotnet tool install + multi-stage copyENV in Dockerfile

Troubleshooting

Agent not loading in container

  1. Check the entrypoint sources the env vars:

    Bash
    docker run --rm myapp printenv DOTNET_STARTUP_HOOKS

    If empty, the entrypoint isn't loading them.

  2. For Linux containers, make sure the entrypoint uses bash:

    DOCKERFILE
    # Wrong - doesn't source profile
    ENTRYPOINT ["dotnet", "myapp.dll"]
    
    # Correct - sources profile first
    ENTRYPOINT ["/bin/bash", "-c", "source /etc/profile.d/bytehide-agent.sh && exec dotnet myapp.dll"]
  3. For Windows containers, ENV in Dockerfile is the most reliable approach.

curl not found

Some minimal images don't include curl. Install it first: apt-get install -y curl ca-certificates (Debian/Ubuntu) or apk add --no-cache curl bash (Alpine).

Permission denied during install

The agent installs to /opt/bytehide/agent/ which requires root. Docker RUN commands run as root by default. If you're using a non-root user:

DOCKERFILE
USER root
RUN curl -sSL ... | bash -s -- --token <token>
USER appuser

Next Steps

Previous
Linux & macOS