Howto Setup a Private Package Repository with reprepro and nginx

As the number of servers I am responsible for grows, I have been trying to eliminate all non packaged software in production. Although ubuntu and Debian have massive software repositories, there are some things which just aren't available yet or are internal meta packages. Once the packages are built they need to be deployed to servers. The simplest way to do this is to run a private apt repository. There are a few options for building an apt repository, but the most popular and simplest seems to be reprepro. I used Sander Marechal and Lionel Porcheron's reprepro howtos as a basis for getting my repository up and running.

nginx is a lightweight http server (and reverse proxy). It performs very well serving static files, which is perfect for a package repository. I also wanted to minimise the memory footprint of the server, which made nginx appealing.

To install the packages we need, run the following command:

$ sudo apt-get install reprepro nginx 

Then it is time to configure reprepro. First we create our directory structure:

$ sudo mkdir -p /srv/reprepro/ubuntu/{conf,dists,incoming,indices,logs,pool,project,tmp}
$ cd /srv/reprepro/ubuntu/
$ sudo chown -R `whoami` . # changes the repository owner to the current user

Now we need to create some configuration files.


Origin: Your Name
Label: Your repository name
Codename: karmic
Architectures: i386 amd64 source
Components: main
Description: Description of repository you are creating


basedir .

If you have a package ready to load, add it using the following command:

$ reprepro includedeb karmic /path/to/my-package_0.1-1.deb \
# change /path/to/my-package_0.1-1.deb to the path to your package

Once reprepro is setup and you have some packages loaded, you need to make it so you can serve the files over http. I run an internal dns zone called "internal" and so the package server will be configured to respond to packages.internal. You may need to change the server_name value to match your own environment. Create a file called

with the following content:

server {
  listen 80;
  server_name packages.internal;

  access_log /var/log/nginx/packages-access.log;
  error_log /var/log/nginx/packages-error.log;

  location / {
    root /srv/reprepro;
    index index.html;

  location ~ /(.*)/conf {
    deny all;

  location ~ /(.*)/db {
    deny all;

Next we need to increase the server_names_hash_bucket_size. Create a file called

which should just contain the following line:

server_names_hash_bucket_size 64;

Note: Many sites advocate sticking this value in the http section of the

/etc/nginx/nginx.conf config
file, but in Debian and Ubuntu
is included in the http section. I think my method is cleaner for upgrading and clearly delineates the stock and custom configuration.

To enable and activate the new virtual host run the following commands:

$ cd /etc/nginx/sites-enabled
$ sudo ln -s ../sites-available/packages.internal.conf .
$ sudo service nginx reload

You should get some output that looks like this

Reloading nginx configuration: the configuration file /etc/nginx/nginx.conf syntax is ok
configuration file /etc/nginx/nginx.conf test is successful

Now you can add the new repository to your machines. I recommend creating a file called

and put the following line in the file:

To make the machine aware of the new repository and associated packages, simply run:

$ sudo apt-get update

That's it. Now you have a lightweight package repository with a lightweight webserver - perfect for running in a virtual machine. Depending on your setup you could probably get away with using 256Mb of RAM and a few gig of disk.

Hey Dave, Good concise

Anonymous wrote:

Hey Dave,

Good concise howto.

I have a similar setup at work also using approx on the same machine though to proxy the standard ubuntu repos too.

apache2 proxies to approx running on port 81 for /ubuntu

My sources list is then just:

deb http://apt/ubuntu karmic main deb http://apt/ubuntu karmic-updates main deb http://apt/ubuntu karmic-security main deb http://apt/internal karmic main

Added Sun, 2010-02-07 18:03

Thanks for the handy reference!

Alan S. Rojer wrote:

You might consider fixing a typo in vhost-packages.conf: access_log should be /var/log/nginx/packages-access.log (or similar); as configured, both logs are going to the error.log. E.g.:

access_log /var/log/nginx/packages-access.log;

In my adaptation, I ditched the sites-available/enabled vhost thingy, avoiding complicating symlinks, and just dropped the conf-file in /etc/nginx/conf.d (it's under puppet control so the vhost symlink thing seems sort of redundant). Many thanks!

Added Thu, 2011-05-19 04:42

RE: Thanks for the handy reference!

Dave wrote:

Alan, thanks for noticing the error. I've updated the post.

Added Sun, 2011-05-22 01:54

Why increase

Dominic wrote:

Why increase 'server_names_hash_bucket_size'? That seems to be something you'd do if you had a very long server name (it doesn't increase the maximum number of buckets, just their size).

But in the example above the server name is only 18 characters long, and the default bucket size is something like 32.

Is this something you actually "need" to do, or is it a superstition, copied from config to config?

Added Fri, 2011-12-09 15:44

Bucket Sizes

Dave wrote:

I can't remember what the problem was I was having back when I wrote this, but increasing the server_names_hash_bucket_size to 64 fixed it.

Added Sun, 2011-12-11 17:38

Change the nginx rules.

Jorge Cardona wrote:

Hi, with this rule: location ~ /(.*)/db your are denying access to packages like libdb since they are in pool/d/db/... I imagine the same happens with conf.

Added Mon, 2012-07-16 06:26

Hello. I like the guide but

Matt wrote:

Hello. I like the guide but have a daft question; I have a wordpress site but want to put an apt repo along side it. I have set up another server in the nginx config which works when the wordpress is commented out. Without the comments, only the wordpress site works. Whats the best way to organise this and configure it?

Added Sat, 2012-12-22 11:05

Signing with key-id

ram wrote:

How to sign with key-id? can u explain more on this one.

Thanks, ram

Added Wed, 2013-06-26 16:44

Signing with key-id

AjayKumar wrote:

Hey Ram, Visit Lionel Porcheron's page for how to 'key-id':

(Also mentioned in the first para of this blog)

Added Tue, 2013-08-06 22:48

To enable and activate the new virtual host

Anonymous wrote:

first thanks for your post and sorry for my english.

in your post: sudo ln -s ../sites-available/packages.internal.conf .

perhaps you mean sudo ln -s ../sites-available/vhost-packages.conf

and in the absence of DNS you need do this: sudo nano /etc/hosts and write: packages.internal

in advance...

Added Fri, 2015-11-20 07:14

Thanks for Complete Guid

Gloria Walton wrote:

Thanks for the complete guide on Private Package Repository with rep repro and Nginx. I am searching for a long time for particular topics but never find interesting like your post at any other places. Actually, i am working on project Dedicated Proxies I need information about Private package repository with reprepro and nginx. Thanks for helping me on my project.

Added Fri, 2017-05-19 17:09

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Lines and paragraphs break automatically.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <p> <div> <blockquote> <pre>

More information about formatting options

By submitting this form, you accept the Mollom privacy policy.