{"id":460,"date":"2026-10-14T13:11:23","date_gmt":"2026-10-14T13:11:23","guid":{"rendered":"http:\/\/www.scmgalaxy.com\/tutorials\/2015\/11\/21\/hosting-your-own-nuget-feed\/"},"modified":"2026-10-14T13:11:23","modified_gmt":"2026-10-14T13:11:23","slug":"hosting-your-own-nuget-feed","status":"publish","type":"post","link":"https:\/\/www.devopsschool.com\/blog\/hosting-your-own-nuget-feed\/","title":{"rendered":"Host Your Own NuGet Feed: Local Source vs NuGet.Server vs NuGetGallery"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">If your team publishes internal .NET libraries, running a private NuGet feed gives you control over package distribution, versioning, and access. This guide explains three self-hosted approaches\u2014local folder sources, <code>NuGet.Server<\/code>, and <code>NuGetGallery<\/code>\u2014and shows how to publish and consume packages with each.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>Originally published on 2015-11-21; fully revised and updated.<\/em><\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img decoding=\"async\" src=\"https:\/\/www.devopsschool.com\/blog\/wp-content\/uploads\/2015\/11\/hosting-your-own-nuget-feed.png\" alt=\"Hosting your own NuGet feed\" \/><\/figure>\n<\/div>\n\n\n<h2 class=\"wp-block-heading\">Choose the right hosting option<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The best private feed setup depends on how much management, UI, and automation your team needs.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Option<\/th><th>Setup complexity<\/th><th>Package publish method<\/th><th>Web UI<\/th><th>Best for<\/th><\/tr><\/thead><tbody><tr><td>Local folder source<\/td><td>Low<\/td><td>Copy files or <code>nuget add<\/code> to a folder\/share<\/td><td>No<\/td><td>Small teams and simple internal sharing<\/td><\/tr><tr><td>NuGet.Server<\/td><td>Medium<\/td><td><code>nuget push<\/code> to HTTP endpoint with API key<\/td><td>Minimal<\/td><td>Internal feeds with basic server capabilities<\/td><\/tr><tr><td>NuGetGallery<\/td><td>High<\/td><td>Server-backed publish flow<\/td><td>Yes<\/td><td>Organizations needing a full package portal<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Option 1: Local file-based package source<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A folder source is the fastest way to share packages. Packages are stored as <code>.nupkg<\/code> files on disk or a network share. It is easy to start, but there is no built-in web feed UI or server-side management layer.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php language-bash\">mkdir -p \/srv\/nuget-feed\nnuget add MyLibrary<span class=\"hljs-number\">.1<\/span><span class=\"hljs-number\">.0<\/span><span class=\"hljs-number\">.0<\/span>.nupkg -Source \/srv\/nuget-feed\nnuget <span class=\"hljs-keyword\">list<\/span> -Source \/srv\/nuget-feed<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\">Option 2: Host NuGet.Server in an ASP.NET app<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">This is the closest match to the original tutorial: create an empty ASP.NET web app in Visual Studio, install <code>NuGet.Server<\/code>, and use the generated <code>\/nuget<\/code> endpoint as a private package source.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Minimal setup flow<\/h3>\n\n\n\n<ul class=\"wp-block-list\"><li>Create an empty ASP.NET web application in Visual Studio.<\/li><li>Open Package Manager Console and install <code>NuGet.Server<\/code>.<\/li><li>Run the app and browse to <code>http:\/\/localhost:&lt;port&gt;\/nuget<\/code>.<\/li><li>Configure an API key in app settings, restart, then publish with <code>nuget push<\/code>.<\/li><\/ul>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css language-powershell\"><span class=\"hljs-selector-tag\">Install-Package<\/span> <span class=\"hljs-selector-tag\">NuGet<\/span><span class=\"hljs-selector-class\">.Server<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">appSettings<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">add<\/span> <span class=\"hljs-attr\">key<\/span>=<span class=\"hljs-string\">\"apiKey\"<\/span> <span class=\"hljs-attr\">value<\/span>=<span class=\"hljs-string\">\"CHANGE_ME\"<\/span> \/&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">appSettings<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php language-bash\">nuget setApiKey SECRETKEY -Source http:<span class=\"hljs-comment\">\/\/localhost:42386\/nuget<\/span>\nnuget push MyLibrary<span class=\"hljs-number\">.1<\/span><span class=\"hljs-number\">.0<\/span><span class=\"hljs-number\">.0<\/span>.nupkg -Source http:<span class=\"hljs-comment\">\/\/localhost:42386\/nuget<\/span>\nnuget <span class=\"hljs-keyword\">list<\/span> -Source http:<span class=\"hljs-comment\">\/\/localhost:42386\/nuget<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\">Option 3: Run NuGetGallery for a full portal experience<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">If you need a richer, gallery-style package experience, use <a href=\"https:\/\/github.com\/NuGet\/NuGetGallery\">NuGetGallery<\/a>. The original post pointed to this repository. Compared with <code>NuGet.Server<\/code>, it is a larger deployment with more operational overhead.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php language-bash\">git <span class=\"hljs-keyword\">clone<\/span> https:<span class=\"hljs-comment\">\/\/github.com\/NuGet\/NuGetGallery.git<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\">Package publish and consume workflow<\/h2>\n\n\n\n<pre class=\"mermaid\">\nflowchart LR\n    A[Developer creates nupkg] --> B[Publish package]\n    B --> C{Feed type}\n    C --> D[Folder source]\n    C --> E[NuGet.Server]\n    C --> F[NuGetGallery]\n    D --> G[Consumer restores package]\n    E --> G\n    F --> G\n    G --> H[Build and release]\n<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Client configuration example<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">To make a private feed available to developers and CI agents, add it to <code>NuGet.Config<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml language-xml\"><span class=\"hljs-meta\">&lt;?xml version=\"1.0\" encoding=\"utf-8\"?&gt;<\/span>\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">configuration<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">packageSources<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">add<\/span> <span class=\"hljs-attr\">key<\/span>=<span class=\"hljs-string\">\"PrivateFeed\"<\/span> <span class=\"hljs-attr\">value<\/span>=<span class=\"hljs-string\">\"http:\/\/nuget.example.com\/nuget\"<\/span> \/&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">packageSources<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">configuration<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\">Best practices and common pitfalls<\/h2>\n\n\n\n<ul class=\"wp-block-list\"><li>Start simple: use a folder source or NuGet.Server first, then move to NuGetGallery only if you need portal features.<\/li><li>Secure publishing endpoints with strong API keys and controlled network access.<\/li><li>Standardize feed configuration in source-controlled <code>NuGet.Config<\/code> files.<\/li><li>Define package retention and cleanup policies to avoid uncontrolled storage growth.<\/li><li>Validate commands and app settings against the exact NuGet tooling and server version you run.<\/li><\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Learn how to host a private NuGet feed using three practical approaches: a local folder source, NuGet.Server, and NuGetGallery. This revised guide includes setup steps, command examples, and a workflow diagram to help you choose the right model.<\/p>\n","protected":false},"author":1,"featured_media":3144,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_joinchat":[],"footnotes":""},"categories":[2],"tags":[1122,1347,1349,545,933,1348,1334,593,399,230,1339,213],"class_list":["post-460","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorised","tag-guide","tag-host","tag-host-own-nuget-feed","tag-how","tag-nuget","tag-nuget-feed","tag-nuget-gallery","tag-process","tag-server","tag-setup","tag-step","tag-tutorial"],"_links":{"self":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/460","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/comments?post=460"}],"version-history":[{"count":4,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/460\/revisions"}],"predecessor-version":[{"id":79335,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/460\/revisions\/79335"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/media\/3144"}],"wp:attachment":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/media?parent=460"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/categories?post=460"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/tags?post=460"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}