Skip to content


Switch branches/tags

Latest commit

The virtual-modules field is used by ghc-prim to provide a magic module
which doesn't exist on disk but still has documentation and so-on. By
including it here the module appears in the module list on the package

Git stats


Failed to load latest commit information.
Latest commit message
Commit time


Build Status Build status Build status

This is the hackage-server code. This is what powers, and many other private hackage instances. The master branch is suitable for general usage. Specific policy and documentation for the central hackage instance exists in the central-server branch.

Installing dependencies

hackage-server depends on icu and zlib. You'll also need libbrotli-dev for enabling tests.

ICU stands for "International Components for Unicode". The icu4c is a set of libraries that provide Unicode and Globalization support. The text-icu Haskell package uses the icu4c library to build.


If you have the Nix package manager installed, the easiest way to run hackage-server is by using the nix-shell. It should be unnecessary to install any dependencies manually. In this repository:

nix-shell --pure

[nix-shell]$ cabal v2-run -- hackage-server init

[nix-shell]$ cabal v2-run -- hackage-server run --static-dir=datafiles/ --base-uri=
hackage-server: Ready! Point your browser at


You can also install dependencies manually via your operating system's package manager.


You'll need to do the following to get hackage-server's dependency text-icu to build:

  • Mac OS X

    brew install icu4c
    brew link icu4c --force

    Besides that, you might also need to include these in the cabal.project.local you created:

    package text-icu
      extra-include-dirs: /usr/local/opt/icu4c/include
      extra-lib-dirs:     /usr/local/opt/icu4c/lib
  • Ubuntu/Debian

    sudo apt-get update
    sudo apt-get install unzip libicu-dev
  • Fedora/CentOS

    sudo dnf install unzip libicu-devel
  • Nix/NixOS

    nix-shell --packages icu


  • Ubuntu/Debian

    sudo apt update
    sudo apt install libbrotli-dev
  • Fedora/CentOS

    sudo dnf install brotli-devel


  • Fedora/CentOS

    sudo dnf install openssl-devel


  • Mac OS X

    brew install zlib
  • Ubuntu/Debian

    sudo apt-get update
    sudo apt-get install zlib
  • Fedora/CentOS

    sudo dnf install zlib
  • Nix/NixOS

    nix-shell --packages zlib

Setting up security infrastructure

Out of the box the server comes with some example keys and TUF metadata. The example keys are in example-keys/; these keys were used to create


While these files will enable you to start the server without doing anything else, you should replace all these files before deploying your server. In the remainder of this section we will explain how to do that.

The first step is to create your own keys using the hackage-repo-tool:

hackage-repo-tool create-keys --keys /path/to/keys

Then copy over the timestamp and snapshot keys to the TUF directory:

cp /path/to/keys/timestamp/<id>.private datafiles/TUF/timestamp.private
cp /path/to/keys/snapshot/<id>.private  datafiles/TUF/snapshot.private

Create root information:

hackage-repo-tool create-root --keys /path/to/keys -o datafiles/TUF/root.json

And finally create a list of mirrors (this is necessary even if you don't have any mirrors):

hackage-repo-tool create-mirrors --keys /path/to/keys -o datafiles/TUF/mirrors.json

The create-mirrors command takes a list of mirrors as additional arguments if you do want to list mirrors.

In order for secure clients to bootstrap the root security metadata from your server, you will need to provide them with the public key IDs of your root keys; you can find these as the file names of the files created in /path/to/keys/root (as well as in the generated root.json under the signed.roles.root.keyids). An example cabal client configuration might look something like

repository my-private-hackage
  secure: True
  root-keys: 865cc6ce84231ccc990885b1addc92646b7377dd8bb920bdfe3be4d20c707796
  key-threshold: 2

Note that if you elect to not use a secure client, the hackage server will not provide your client the most recent versions of packages from its index. The cabal-version:2.0 format packages are thus only available in the newer secure repository mode. See Issue #4625 for further information.


cabal install

hackage-server init
hackage-server run

If you want to run the server directly from the build tree, run

cabal v2-run -- hackage-server init

once to initialise the state. After that you can run the server with

cabal v2-run -- hackage-server run --static-dir=datafiles/ --base-uri=

By default the server runs on port 8080 with the following settings:

URL:      http://localhost:8080/
username: admin
password: admin

To specify something different, see hackage-server init --help for details.

The is used to add users (e.g. admin) to Uploaders group.

The server can be stopped by using Control-C.

This will save the current state and shutdown cleanly. Running again will resume with the same state.


To reset everything, kill the server and delete the server state:

rm -rf state/

Note that the datafiles/ and state/ directories differ: datafiles is for static html, templates and other files. The state directory holds the database (using acid-state and a separate blob store).

Creating users & uploading packages

Currently there is no restriction on registering, but only an admin user can grant privileges to registered users e.g. by adding them to other groups. In particular there are groups:

  • admins http://localhost:8080/users/admins/ -- administrators can do things with user accounts like disabling, deleting, changing other groups etc.
  • trustees http://localhost:8080/packages/trustees/ -- trustees can do janitorial work on all packages
  • mirrors http://localhost:8080/packages/mirrorers/ -- for special mirroring clients that are trusted to upload packages
  • per-package maintainer groups http://localhost:8080/package/foo/maintainers -- users allowed to upload packages
  • uploaders http://localhost:8080/packages/uploaders/ -- for uploading new packages


There is a client program included in the hackage-server package called hackage-mirror. It's intended to run against two servers, syncing all the packages from one to the other, e.g. getting all the packages from the old hackage and uploading them to a local instance of a hackage-server.

To try it out:

  1. On the target server, add a user to the mirrorers group via http://localhost:8080/packages/mirrorers/.

  2. Create a config file that contains the source and target servers. Assuming you are cloning the packages on locally, create the file servers.cfg:

    source "hackage"
      type: secure
    target "mirror"
      uri: http://admin:admin@localhost:8080
      type: hackage2
      post-mirror-hook: "shell command to execute"

    Recognized types are hackage2, secure and local. The target server name was displayed when you ran.

    Note, the target must not have a trailing slash, or confusion will tend to occur. Additionally, if you have ipv6 setup on the machine, you may need to replace localhost with

    Also note that you should mirror from hackage2 or secure typically and mirror to hackage2. Only mirroring from secure will include dependency revision information.

    hackage-server run
  3. Run the client, pointing to the config file:

    hackage-mirror servers.cfg

    This will do a one-time sync, and will bail out at the first sign of trouble. You can also do more robust and continuous mirroring. Use the flag --continuous. It will sync every 30 minutes (configurable with --interval). In this mode it carries on even when some packages cannot be mirrored for some reason and remembers them so it doesn't try them again and again. You can force it to try again by deleting the state files it mentions.