{"id":13616887,"url":"https://github.com/haskell/hackage-server","last_synced_at":"2025-05-15T06:02:59.354Z","repository":{"id":10160323,"uuid":"12241186","full_name":"haskell/hackage-server","owner":"haskell","description":"Hackage-Server: A Haskell Package Repository","archived":false,"fork":false,"pushed_at":"2025-05-01T00:38:43.000Z","size":12388,"stargazers_count":428,"open_issues_count":252,"forks_count":198,"subscribers_count":33,"default_branch":"master","last_synced_at":"2025-05-08T16:51:08.621Z","etag":null,"topics":["cabal","hackage","haskell"],"latest_commit_sha":null,"homepage":"http://hackage.haskell.org","language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/haskell.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2013-08-20T11:08:21.000Z","updated_at":"2025-04-30T07:52:47.000Z","dependencies_parsed_at":"2024-01-01T04:03:06.999Z","dependency_job_id":"a723589f-be21-4b1c-b98a-946a910b3a1e","html_url":"https://github.com/haskell/hackage-server","commit_stats":{"total_commits":2074,"total_committers":152,"mean_commits":"13.644736842105264","dds":0.718900675024108,"last_synced_commit":"888247675243cf158753d4fec1465bd56142be0a"},"previous_names":[],"tags_count":25,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haskell%2Fhackage-server","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haskell%2Fhackage-server/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haskell%2Fhackage-server/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haskell%2Fhackage-server/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/haskell","download_url":"https://codeload.github.com/haskell/hackage-server/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254283336,"owners_count":22045140,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cabal","hackage","haskell"],"created_at":"2024-08-01T20:01:34.419Z","updated_at":"2025-05-15T06:02:59.335Z","avatar_url":"https://github.com/haskell.png","language":"Haskell","funding_links":[],"categories":["Haskell"],"sub_categories":[],"readme":"# hackage-server\n\n[![Build status](https://github.com/haskell/hackage-server/actions/workflows/haskell-ci.yml/badge.svg)](https://github.com/haskell/hackage-server/actions/workflows/haskell-ci.yml)\n[![Build status](https://github.com/haskell/hackage-server/actions/workflows/nix-flake.yml/badge.svg)](https://github.com/haskell/hackage-server/actions/workflows/nix-flake.yml)\n\nThis is the `hackage-server` code. This is what powers \u003chttp://hackage.haskell.org\u003e, 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.\n\n## Installing dependencies\n\n`hackage-server` depends on `libgd`, `zlib`, and other system libraries. You'll also need `libbrotli-dev` for enabling tests.\n\nYou can use the Nix package manager to provide these dependencies, or install them manually.\n\n### Using the [Nix package manager](https://nixos.org/) and provided [Nix Flake](https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-flake.html)\n\nIf you have the Nix package manager installed, you can build and run `hackage-server` without manually installing any dependencies:\n\n    $ nix run\n\n    'state' state-dir already exists\n    hackage-server: Ready! Point your browser at http://127.0.0.1:8080\n    \nIf the required `state` directory does not already exist, `nix run` will create and initialize it.\n\nThe `flake.nix` is implemented with [`srid/haskell-flake`](https://github.com/srid/haskell-flake).\n\nAlternatively, open the [`nix develop`](https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-develop.html) shell:\n\n    $ nix develop\n\n    (in develop shell)\n    \n    # if state directory does not already exist\n    $ cabal v2-run -- hackage-server init --static-dir=datafiles --state-dir=state\n\n    $ cabal v2-run -- hackage-server run --static-dir=datafiles --state-dir=state --base-uri=http://127.0.0.1:8080\n    hackage-server: Ready! Point your browser at http://127.0.0.1:8080\n\n#### Populate the local package index\n\nThis copies packages from real Hackage Server to local Hackage Server.\n\nAdd the default `admin` user to the `mirrorers` group here:\nhttp://localhost:8080/packages/mirrorers/\n\nThen\n\n     $ nix run .#mirror-hackage-server\n\n#### Not working\n\nPlease note this App *cannot* be run [directly from GitHub](https://determinate.systems/posts/nix-run) like this:\n\n    nix run github:haskell/hackage-server -- init --static-dir=datafiles\n\n    nix run github:haskell/hackage-server -- run --static-dir=datafiles --base-uri=http://127.0.0.1:8080\n\nbecause `hackage-server` expects the directories `state` and `datafiles` to exist in the working directory.\n\n### Manually\n\nYou can also install dependencies manually via your operating system's package\nmanager.\n\n#### Libgd\n\nYou'll need to do the following to get `hackage-server`'s dependency `hs-captcha` (and transitively `gd`) to build:\n\n  - Mac OS X\n\n        brew install libgd\n\n  - Ubuntu/Debian\n\n        sudo apt-get update\n        sudo apt-get install unzip libgd-dev\n\n  - Fedora/CentOS\n\n        sudo dnf install unzip libgd-devel\n\n  - Nix/NixOS\n\n        nix-shell --packages gd\n\n#### libbrotli\n\n  - Ubuntu/Debian\n\n        sudo apt update\n        sudo apt install libbrotli-dev\n\n  - Fedora/CentOS\n\n        sudo dnf install brotli-devel\n\n#### openssl\n\n  - Fedora/CentOS\n\n      sudo dnf install openssl-devel\n\n#### zlib\n\n  - Mac OS X\n\n        brew install zlib\n\n  - Ubuntu/Debian\n\n        sudo apt-get update\n        sudo apt-get install zlib\n\n  - Fedora/CentOS\n\n        sudo dnf install zlib\n\n  - Nix/NixOS\n\n        nix-shell --packages zlib\n\n#### Mac OS X\n\nIn addition to the above commands, you'll need to run\n\n```bash\nbrew install pkg-config\n```\n\nAfter running the above `brew install` commands, you also need to update `cabal.project.local` with the following:\n\n```bash\ncat \u003e\u003e cabal.project.local \u003c\u003cEOF\npackage gd\n  extra-include-dirs:\n    $(echo $(brew --prefix)/Cellar/gd/*/include)\n  extra-lib-dirs:\n    $(echo $(brew --prefix)/Cellar/gd/*/lib)\n    $(echo $(brew --prefix)/Cellar/libpng/*/lib)\n    $(echo $(brew --prefix)/Cellar/jpeg-turbo/*/lib)\n    $(echo $(brew --prefix)/Cellar/fontconfig/*/lib)\n    $(echo $(brew --prefix)/Cellar/freetype/*/lib)\n\nconstraints:\n  , HsOpenSSL +use-pkg-config\nEOF\n```\n\n\n## Setting up security infrastructure\n\nOut of the box the server comes with some example keys and\n[TUF](https://theupdateframework.io) metadata. The example keys are in\n`example-keys/`; these keys were used to create\n\n    datafiles/TUF/root.json\n    datafiles/TUF/mirrors.json\n    datafiles/TUF/timestamp.private\n    datafiles/TUF/snapshot.private\n\nWhile these files will enable you to start the server without doing anything\nelse, you should replace all these files before deploying your server. In the\nremainder of this section we will explain how to do that.\n\nThe first step is to create your own keys using the\n[hackage-repo-tool](http://hackage.haskell.org/package/hackage-repo-tool):\n\n    hackage-repo-tool create-keys --keys /path/to/keys\n\nThen copy over the timestamp and snapshot keys to the TUF directory:\n\n    cp /path/to/keys/timestamp/\u003cid\u003e.private datafiles/TUF/timestamp.private\n    cp /path/to/keys/snapshot/\u003cid\u003e.private  datafiles/TUF/snapshot.private\n\nCreate root information:\n\n    hackage-repo-tool create-root --keys /path/to/keys -o datafiles/TUF/root.json\n\nAnd finally create a list of mirrors (this is necessary even if you don't have\nany mirrors):\n\n    hackage-repo-tool create-mirrors --keys /path/to/keys -o datafiles/TUF/mirrors.json\n\nThe `create-mirrors` command takes a list of mirrors as additional arguments if\nyou do want to list mirrors.\n\nIn order for secure clients to bootstrap the root security metadata from your\nserver, you will need to provide them with the public key IDs of your root keys;\nyou can find these as the file names of the files created in\n`/path/to/keys/root` (as well as in the generated root.json under the\n`signed.roles.root.keyids`). An example `cabal` client configuration might look\nsomething like\n\n    repository my-private-hackage\n      url: http://example.com:8080/\n      secure: True\n      root-keys: 865cc6ce84231ccc990885b1addc92646b7377dd8bb920bdfe3be4d20c707796\n                 dd86074061a8a6570348e489aae306b997ed3ccdf87d567260c4568f8ac2cbee\n                 e4182227adac4f3d0f60c9e9392d720e07a8586e6f271ddcc1697e1eeab73390\n      key-threshold: 2\n\nNote that if you elect to not use a secure client, the hackage server will not\nprovide your client the most recent versions of packages from its index. The\ncabal-version:2.0 format packages are thus only available in the newer secure\nrepository mode. See [Issue #4625](https://github.com/haskell/cabal/issues/4624)\nfor further information.\n\n## Running\n\n    cabal install\n\n    hackage-server init\n    hackage-server run\n\nIf you want to run the server directly from the build tree, run\n\n    cabal v2-run -- hackage-server init\n\nonce to initialise the state. After that you can run the server with\n\n    cabal v2-run -- hackage-server run --static-dir=datafiles/ --base-uri=http://127.0.0.1:8080\n\nBy default the server runs on port `8080` with the following settings:\n\n    URL:      http://localhost:8080/\n    username: admin\n    password: admin\n\nTo specify something different, see `hackage-server init --help` for details.\n\nThe http://127.0.0.1:8080/packages/uploaders/edit is used to add users\n(e.g. `admin`) to *Uploaders* group.\n\nThe server can be stopped by using `Control-C`.\n\nThis will save the current state and shutdown cleanly. Running again\nwill resume with the same state.\n\n### Resetting\n\nTo reset everything, kill the server and delete the server state:\n\n```bash\nrm -rf state/\n```\n\nNote that the `datafiles/` and `state/` directories differ:\n`datafiles` is for static html, templates and other files.\nThe `state` directory holds the database (using `acid-state`\nand a separate blob store).\n\n### Creating users \u0026 uploading packages\n\n* Admin front-end: \u003chttp://localhost:8080/admin\u003e\n* List of users: \u003chttp://localhost:8080/users/\u003e\n* Register new users: \u003chttp://localhost:8080/users/register\u003e\n\nCurrently there is no restriction on registering, but only an admin\nuser can grant privileges to registered users e.g. by adding them to\nother groups. In particular there are groups:\n\n * admins `http://localhost:8080/users/admins/` -- administrators can\n   do things with user accounts like disabling, deleting, changing\n   other groups etc.\n * trustees `http://localhost:8080/packages/trustees/` -- trustees can\n   do janitorial work on all packages\n * mirrors `http://localhost:8080/packages/mirrorers/` -- for special\n   mirroring clients that are trusted to upload packages\n * per-package maintainer groups\n   `http://localhost:8080/package/foo/maintainers` -- users allowed to\n   upload packages\n * uploaders `http://localhost:8080/packages/uploaders/` -- for\n   uploading new packages\n\n### Mirroring\n\nThere is a client program included in the `hackage-server` package called\n`hackage-mirror`. It's intended to run against two servers, syncing all the\npackages from one to the other, e.g. getting all the packages from the old\nhackage and uploading them to a local instance of a hackage-server.\n\nTo try it out:\n\n1. On the target server, add a user to the mirrorers group via\n   http://localhost:8080/packages/mirrorers/.\n\n2. Create a config file that contains the source and target\n   servers. Assuming you are cloning the packages on\n   \u003chttp://hackage.haskell.org\u003e locally, create the file `servers.cfg`:\n\n   ```\n   source \"hackage\"\n     uri: http://hackage.haskell.org\n     type: secure\n\n   target \"mirror\"\n     uri: http://admin:admin@localhost:8080\n     type: hackage2\n\n     post-mirror-hook: \"shell command to execute\"\n   ```\n   Recognized types are `hackage2`, `secure` and `local`.\n   The target server name was displayed when you ran.\n\n   Note, the target must _not_ have a trailing slash, or confusion\n   will tend to occur.  Additionally, if you have ipv6 setup on the\n   machine, you may need to replace `localhost` with `127.0.0.1`.\n\n   Also note that you should mirror _from_ `hackage2` or `secure`\n   typically and mirror _to_ `hackage2`. Only mirroring from `secure`\n   will include dependency revision information.\n\n   ```bash\n   hackage-server run\n   ```\n\n3. Run the client, pointing to the config file:\n\n   ```bash\n   hackage-mirror servers.cfg\n   ```\n\n   This will do a one-time sync, and will bail out at the first sign of\n   trouble. You can also do more robust and continuous mirroring. Use the\n   flag `--continuous`. It will sync every 30 minutes (configurable with\n   `--interval`). In this mode it carries on even when some packages\n   cannot be mirrored for some reason and remembers them so it doesn't\n   try them again and again. You can force it to try again by deleting\n   the state files it mentions.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhaskell%2Fhackage-server","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhaskell%2Fhackage-server","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhaskell%2Fhackage-server/lists"}