<img height="1" width="1" style="display:none" src="https://www.facebook.com/tr?id=1678611822423757&amp;ev=PageView&amp;noscript=1">
Defrag This

| Read. Reflect. Reboot.

Setting up an Internal Chocolatey Repository

Dan Franciscus| February 21 2018

| IT insights


If your organization is serious about using Chocolatey as a means for Windows package management, then setting up your own internal package repository is a must.

While, the Chocolatey repository is full of great Windows packages, chances are you do not want all your internal client machines reaching out to the internet for every package install. It is obviously insecure, not mention will undoubtedly be slower.

There is a slew of solutions for hosting your own repository, such as ProGet, Teamcity, SCCM or just a plain old file share. In this article, I will illustrate setting up a Chocolatey Simple Server, which is an IIS web server with some NuGet framework stuff. It is a great choice if your organization is on the small-medium side due to the cost (free) and setup.

Installing Chocolatey Server with Chocolatey

There are a few ways to install Chocolatey Server, but the one I prefer is using the Puppet module. The reason for this is that it automates almost all that you will need to get your server up and running. What the module does not do is some added configuration that I will add on in Puppet. These configurations are setting the firewall, configuring the app pool identify and setting a virtual directory to point to a UNC share which will house our Chocolatey packages. Keep in mind there could be others depending on your needs such as using an SSL certificate.

If you do not want to use Puppet for this, you can simple use the Chocolatey CLI to install it, which will do most of the setup:

PS C:\Users\Administrator> choco install chocolatey.server –y

Creating Puppet configuration for Chocolatey Server

On my Puppet master server, I will first install the Chocolatey Server module:

[vagrant@puppet production]$ puppet module install chocolatey-chocolatey_server 

Notice: Preparing to install into /home/vagrant/.puppetlabs/etc/code/modules ...

Notice: Downloading from https://forgeapi.puppet.com ...


Notice: Installing -- do not interrupt ...


└─┬ chocolatey-chocolatey_server (v0.0.5)

  ├─┬ puppet-iis (v1.4.1)

  │ └── puppetlabs-stdlib (v4.24.0)

  ├── puppet-windowsfeature (v1.1.0)

  ├── puppetlabs-acl (v1.1.2)

  └── puppetlabs-powershell (v1.0.6)

You can see it installs some other dependencies such as puppet-iis, windowsfeature and powershell. For this example, I will also install these modules from Puppet forge:

[vagrant@puppet production]$ puppet module install chocolatey-chocolatey

[vagrant@puppet production]$ puppet module install puppet-windows_firewall

Now, I will create my own Puppet module, using puppet module generate in order to create some additional configurations for my server.

[vagrant@puppet production]$ puppet module generate --skip-interview my-chocoserver

Enhance your IT career by learning how to automate with Python. Get started  with this free Python guide.

From here, I want to edit the init.pp file in my module and create my class that I will call in my main manifest. My class, will do the following:

  • Install the Chocolatey Server using the chocolatey_server module
  • Allow a firewall exception for port 8080 (which I will use for the Chocolatey Server)
  • Ensure Basic authentication is installed
  • Create a virtual directory pointing to a UNC share
  • Change the App pool to run under the network service
  • Increase the MaxAllowedContentLength on my web server to 50000000. This allows for larger packages.

Here is the init.pp:

class chocoserver {

   class {'chocolatey_server':

      port => '8080',


    windows_firewall::exception { 'Choco server':

    ensure       => present,

    direction    => 'in',

    action       => 'Allow',

    enabled      => 'yes',

    protocol     => 'TCP',

    local_port   => '8080',

    remote_port  => 'any',

    display_name => 'Chocolatey Simple Server',

    description  => 'Inbound rule for Chocolatey Server. [TCP 8080]',



  windowsfeature { 'Web-Basic-Auth':

    ensure => present,

    require => Class["chocolatey_server"]



  exec { 'VirtualDir':

    command   => '$(Import-Module WebAdministration;New-Item IIS:\Sites\chocolatey.server\App_Data\Packages -type VirtualDirectory -physicalPath \\\\server\\packages$ -Force)',

    provider  => powershell,

    logoutput => true,

    require => Class["chocolatey_server"],



  exec { 'ChocoAppPoolID':

    command => '$(Import-Module WebAdministration;Set-ItemProperty IIS:\AppPools\chocolatey.server -name processModel -value @{identitytype=2})',

    provider => powershell,

    logoutput => true,

    require => Class["chocolatey_server"],



  exec { 'MaxAllowedContentLength':

    command => '$(Import-Module WebAdministration;Set-WebConfigurationProperty -filter /system.webserver/security/requestfiltering/requestLimits -name maxAllowedContentLength -value 50000000)',

    provider => powershell,

    logoutput => true,

    require => Class["chocolatey_server"],




As you can see the first thing we do in our “chocoserver” class is ensuring that “chocolatey_server” is installed and running on port 8080. From here, we ensure the firewall has 8080 open.

To show how PowerShell can be used in Puppet, I use the exec resource to run PowerShell code. In the first example in the class, I run:

Import-Module WebAdministration;New-Item IIS:\Sites\chocolatey.server\App_Data\Packages -type VirtualDirectory -physicalPath \\\\server\\packages$ -Force

What this does is create a virtual directory in our Chocolatey server and point it to a UNC share - \\server\packages$. This ensures that our data is kept separate from our server. To ensure that our app pool identify has permission, we change the app pool identity for  chocolatey.server to “network service”. Keep in mind that means the computer object needs permission on the UNC share. Note - As you can see to indicate a UNC path in Puppet you need to add two extra slashes for the server and one for the share name.

Related: Chocolatey Is Quite Yummy

Finally, the “maxAllowedContentLength” increases the site to allow for large packages, in this case 50GB (excessive I know!).

Now, in our main manifest file (site.pp in this case), we include this:

node 'puppetagent-win' {

 include chocolatey

 include chocoserver


This guarantees that the Chocolatey client is installed and then our chocoserver module, that includes Chocolatey Server.

Now on our puppet node we just run this to apply the configuration and install our Chocolatey Server:

PS C:\Users\Administrator> puppet agent –test

As you can see below, running Get-WebSite on our node in PowerShell shows the web server is up and running:

PS C:\Users\Administrator> Get-Website                                                                                         


Name              ID   State      Physical Path                  Bindings                                                       

----              --   -----      -------------                  --------                                                       

chocolatey.server 1    Started    C:\tools\chocolatey.server     http *:8080:

As I noted before there may be additional changes you want to make to your internal repo. One would be to change the API key, needed to push packages. To do this, change the web.config in c:\tools\chocolatey.server:

<add key="apiKey" value="chocolateyrocks" />

Adding and installing Chocolatey Packages

To add new packages to our internal repository, we use the command choco push. In this example, I want to push my package named “test”. I will need to point to the directory my package is located, in this case it is c:\testpackage.

PS C:\Users\Administrator> choco push c:\testpackage --source "'http://choco-server:8080'" -k="'MyOwnApiKey"  

To install the test package from my internal repository I just run:

PS C:\Users\Administrator> choco install test –source "'http://choco-server:8080'" -y

Topics: IT insights

Leave a Reply

Your email address will not be published. Required fields are marked *


Dan Franciscus is a systems engineer and VMware Certified Professional (VCP) specializing in VMware, PowerShell, and other Microsoft-based technologies. You can reach Dan at his blog (http://www.winsysblog.com/) or Twitter at @dan_franciscus.

Free Trials

Getting started has never been easier. Download a trial today.

Download Free Trials

Contact Us

Let us know how we can help you. Focus on what matters. 

Send us a note

Subscribe to our Blog

Let’s stay in touch! Register to receive our blog updates.