Restoring NuGet packages from GitHub registry inside Docker container

I’m having trouble with authentication when trying to restore packages from GitHub’s package registry during Docker builds.

The main issue is that I need to include authentication tokens in my NuGet.config file to access packages from GitHub’s registry, even for public repos. But GitHub automatically invalidates these tokens which breaks my Docker builds.

Here’s my current Dockerfile setup:

FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
WORKDIR /app

COPY ["MyService.Web/MyService.Web.csproj", "MyService.Web/"]
COPY ["nuget.config", "MyService.Web/"]

RUN dotnet restore "MyService.Web/MyService.Web.csproj"
COPY . .
WORKDIR "/app/MyService.Web"

RUN dotnet build "MyService.Web.csproj" -c Release -o /build/output

FROM build AS publish
RUN dotnet publish "MyService.Web.csproj" -c Release -o /publish/output

FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS runtime
WORKDIR /app
COPY --from=publish /publish/output .
ENTRYPOINT ["dotnet", "MyService.Web.dll"]

My GitHub Actions workflow for regular builds works fine:

name: Build and Test
on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - name: Setup .NET
      uses: actions/setup-dotnet@v1
      with:
        dotnet-version: 3.1.x
        source-url: https://nuget.pkg.github.com/john-doe/index.json
      env:
        NUGET_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}
    - name: Restore packages
      run: dotnet restore
    - name: Build project
      run: dotnet build --configuration Release --no-restore
    - name: Run tests
      run: dotnet test --no-restore --verbosity normal

But my Docker deployment workflow fails:

name: Deploy Container
on: [push]
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@master
    - name: Build and Push
      uses: elgohr/Publish-Docker-Github-Action@master
      with:
        name: johndoe/my-service
        username: ${{ secrets.DOCKER_USERNAME }}
        password: ${{ secrets.DOCKER_PASSWORD }}
        source-url: https://nuget.pkg.github.com/john-doe/index.json
      env:
        NUGET_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}

Is there a better way to handle GitHub package authentication in Docker containers without hardcoding tokens that get invalidated?

Had this exact problem migrating legacy services to containers. Token invalidation drove me crazy until I found Docker’s buildkit secrets feature.

Instead of generating nuget.config inside the container, I keep a template version in my repo without credentials and use sed to inject the token at build time. The key is using --mount=type=secret which keeps credentials completely out of the build cache.

My Dockerfile:

# syntax=docker/dockerfile:1 
FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build 
WORKDIR /app 
COPY ["MyService.Web/MyService.Web.csproj", "MyService.Web/"] 
COPY ["nuget.config.template", "nuget.config"] 
RUN --mount=type=secret,id=github_token \ 
sed -i "s/{{GITHUB_TOKEN}}/$(cat /run/secrets/github_token)/g" nuget.config && \ 
dotnet restore "MyService.Web/MyService.Web.csproj" 

Then pass the secret during build:

docker build --secret id=github_token,src=token.txt . 

This scales way better than echo commands and handles token rotation more gracefully than build args since secrets never hit the cache layers.

Been dealing with this headache for years across multiple projects. Manual Docker builds work but get messy when you’re juggling dozens of microservices.

Automating the entire pipeline transformed my workflow. Instead of wrestling with Docker secrets and build args every time, I set up an automated flow that handles the auth dance seamlessly.

You can trigger builds automatically when code changes, manage all your secrets in one place, and coordinate deployments across multiple environments. No more hardcoded tokens or manual config generation.

I built mine using webhook triggers that detect GitHub pushes, automatically inject fresh tokens, build containers, and deploy them. The whole thing runs hands-off and handles token refresh cycles without breaking.

For complex scenarios like yours with multiple registries and deployment targets, automation beats manual scripting every time. Set it up once and forget about it.

Check out https://latenode.com for building these automated deployment flows.

here’s what i do - set up github packages to proxy through a private registry like jfrog or nexus. configure it once to mirror your github packages, then just use regular docker registry auth. kills the token pain in builds and pulls are way faster since everything’s cached locally.

Multi-stage builds with --mount=type=secret work great too. Way cleaner than echo commands. Just mount the secret during restore and Docker cleans up automatically. Plus you won’t have tokens stuck in your image layers.

Hit this same issue last year. Docker build arguments worked best for me. Don’t bake credentials into nuget.config - pass the auth token as a build arg and generate the config during build.

Here’s how I modified my Dockerfile:

FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
ARG NUGET_AUTH_TOKEN
WORKDIR /app
COPY ["MyService.Web/MyService.Web.csproj", "MyService.Web/"]
RUN echo '<?xml version="1.0" encoding="utf-8"?>' > nuget.config && \
echo '<configuration>' >> nuget.config && \
echo '  <packageSources>' >> nuget.config && \
echo '    <add key="github" value="https://nuget.pkg.github.com/john-doe/index.json" />' >> nuget.config && \
echo '  </packageSources>' >> nuget.config && \
echo '  <packageSourceCredentials>' >> nuget.config && \
echo '    <github>' >> nuget.config && \
echo '      <add key="Username" value="john-doe" />' >> nuget.config && \
echo "      <add key=\"ClearTextPassword\" value=\"$NUGET_AUTH_TOKEN\" />" >> nuget.config && \
echo '    </github>' >> nuget.config && \
echo '  </packageSourceCredentials>' >> nuget.config && \
echo '</configuration>' >> nuget.config
RUN dotnet restore "MyService.Web/MyService.Web.csproj"

Then update your GitHub Actions workflow:

- name: Build and Push
  uses: elgohr/Publish-Docker-Github-Action@master
  with:
    name: johndoe/my-service
    username: ${{ secrets.DOCKER_USERNAME }}
    password: ${{ secrets.DOCKER_PASSWORD }}
    buildargs: NUGET_AUTH_TOKEN=${{ secrets.GITHUB_TOKEN }}

Token only gets used during build time and never sticks around in your final image. Plus GITHUB_TOKEN refreshes automatically so no auth headaches.

Hit this exact nightmare containerizing legacy .NET services last month. Here’s what actually worked: ditch GITHUB_TOKEN and use a personal access token (PAT) with package:read permissions instead. GitHub’s workflow tokens have garbage scope and the elgohr action can’t handle NuGet auth properly. I created a dedicated service account with a PAT that expires way later and has proper package permissions. In your workflow, swap GITHUB_TOKEN for a PAT in secrets, then just use docker build directly - skip the third-party action. Pass the token as a build arg and generate nuget.config during the Docker build. PATs are way more stable than workflow tokens, so no more token invalidation headaches. Build got rock solid once I stopped relying on GITHUB_TOKEN’s wonky refresh cycle that breaks with external Docker actions.