pypiserver: A Directory-Backed PyPI Endpoint for pip and twine
Minimal PyPI server for uploading & downloading packages with pip/easy_install
At a glance
- What is it?
- pypiserver is a Bottle-based server that implements the PyPI upload and download interfaces over ordinary filesystem directories. It is a good fit for internal package hosting, and a poor fit for anyone who needs the index features that Warehouse provides.
- Who is it for?
- Adopt pypiserver if you need an internal index that pip and twine already know how to talk to, and you are content to manage the package directory yourself, including the htpasswd file that guards uploads. Do not adopt it if you need per-project permissions, a search UI, or the metadata services that Warehouse exposes, because pypiserver serves files from directories and does not build that layer.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 14 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The gap pypiserver fills between a shared folder and Warehouse
Python packaging tooling assumes an index. pip resolves names to files through the simple API, and twine uploads through the legacy upload endpoints. If you want to distribute private packages without publishing them, you need something that speaks those protocols. A network share does not, and PyPI itself is not an option for internal artifacts.
Warehouse is the software behind pypi.org, and the README is explicit that it is specialized to that role and does not officially support use as a custom package index. So the realistic choice for a small internal index is either a hosted product or something like pypiserver, which the README describes as a minimal PyPI-compatible server for pip and easy_install, based on Bottle and serving packages from regular directories.
The audience is narrow and identifiable. Teams that already build wheels in CI, that want pip install to resolve an internal name, and that do not want to operate a database-backed application to get there. The README also points at the Docker Hub image as the project homepage, which suggests container deployment is a first-class path rather than an afterthought.
How pypiserver turns directories into an index
The design is deliberately thin. There is no database and no package metadata store. The server scans configured directories and presents the files it finds through the same interfaces PyPI exposes, so pip and twine interact with it as they would with pypi.org. Wheels, bdists, eggs and accompanying PGP signatures are all in scope.
That has a direct consequence for how you populate the index. Uploads can go through pip, setuptools, twine or pypi-uploader, but the README also lists plain scp as a supported method. Copying a file into the directory is equivalent to publishing it. This is the mechanism and also the main operational hazard: the directory is the source of truth, so anything that can write to it can publish a package.
Because the server reads the filesystem, package visibility is a function of file placement. There is no separate registration step, and no per-package record to update when a file is removed. Whether the server caches directory listings is not something the supplied material states, so treat the refresh behaviour of a running instance as something to confirm against the source or the documentation before you rely on it.
Installing and starting the server
The README leads with a quickstart section covering installation and usage, then a subsection on the pypi-server run command and another on pypi-server update. The command name is pypi-server, with a hyphen, which is worth noting because the project and the PyPI distribution are both named pypiserver.
A typical invocation points the server at a package directory and binds a port. The README's recipes include managing the package directory, serving thousands of packages, and running the server under systemd, supervisor, or NSSM on Windows. It also documents using a different WSGI server, with an Apache section, so the built-in server is not the only deployment shape.
For clients, the README covers configuring pip and configuring easy_install, and for uploads it covers Apache-like authentication via htpasswd, uploading with setuptools, and uploading with twine. Those are the three pieces you need to wire together: where the files live, who may write, and how clients find the index. The precise flag names and config keys are in the README's quickstart and client-side sections rather than in this review, and they should be read there before you commit to a deployment.
Authentication covers uploads, not reads
The README's upload section is headed Apache Like Authentication (htpasswd). That tells you the intended security model: an htpasswd file gates the write path, and the read path is whatever the surrounding network allows. There is no mention of per-user accounts, token scopes, or project-level permissions in the supplied material.
For an internal index behind a VPN this is usually acceptable. For anything reachable more broadly it is a real constraint. Anyone who can reach the download endpoints can enumerate and fetch your internal packages, and anyone who can reach the upload endpoints with valid credentials can publish. There is no review step between an upload and its availability, because the file lands in the directory the server is already serving.
A second limitation follows from the same design. The README notes that packages can simply be copied with scp. That is convenient for bootstrapping an index, but it means the htpasswd file is not the only path to publication. Filesystem access is publishing access. If you care about provenance, the control you need is on the directory, not on the HTTP layer.
Where pypiserver is the wrong tool
The README itself draws the boundary. Warehouse is the software that powers PyPI, and the project states that it is fairly specialized to that role and should not be used in other contexts, in particular because it does not officially support being used as a custom package index. That sentence is about Warehouse, but it also frames what pypiserver is not: it is not a substitute for the full PyPI experience.
If you need search across packages, release history with metadata, per-project ownership, or an API that returns structured information about a distribution, this is not the project. It serves files. Anything that depends on querying metadata rather than resolving a filename to a download will not find it here.
Scale is the other boundary. The README includes a recipe titled Serving Thousands of Packages, which implies the maintainers expect that to be a case worth documenting. It does not state a limit, and this review will not invent one. The honest position is that the project documents the recipe, and whether your specific package count is comfortable is something you determine by trying it against your own directory.
Alternatives and the actual difference in approach
The obvious alternative is Warehouse, and the difference is architectural rather than cosmetic. Warehouse is a database-backed web application with a metadata model, accounts, and the operational surface that running pypi.org implies. pypiserver has no database. Its state is a set of directories, and its behaviour is determined by what is in them. Choosing between them is choosing whether you want to operate an application or a directory.
A second alternative is a general-purpose artifact repository that also speaks the Python simple API. Those systems typically add proxying of upstream PyPI, multi-format storage, and access control at the repository level. pypiserver does none of that. It does not proxy upstream in the material provided, and its access control is the htpasswd mechanism described in the README. If you need a single service to hold Python, container images, and other artifacts, pypiserver is the wrong shape.
There is also the option of not running a server at all and installing from local paths or a shared filesystem. That works until you need pip to resolve a name rather than a path, or until twine needs an endpoint to upload to. pypiserver exists precisely at the point where those two requirements appear.
Maintenance, releases and licence
The release cadence visible in the material is slow and irregular. v2.3.2 was published in November 2024, v2.4.0 in August 2025, and v2.4.1 in February 2026. The repository is not archived and the last push is dated 2026-09-01, so the project is active, but the gaps between tagged releases are measured in months.
That matters for how you plan upgrades. There is a documented pypi-server update command, which the README covers in its own subsection, so the intended upgrade path is a command rather than a manual migration. Because there is no database, upgrades do not involve schema changes, and your package directory survives independently of the server version. That is a genuine operational advantage of the directory-backed design.
The licence is listed as zlib/libpng plus MIT, and the repository metadata reports NOASSERTION, which means the automated classifier did not resolve it. The README's badge links to a LICENSE.txt file in the repository root. If you need to redistribute pypiserver or bundle it into a product, read that file rather than the badge. This review is not legal advice.
One more maintenance signal is worth flagging without reading it as a quality measure: the maintainer table in the README ends with a line inviting new maintainers and linking to issue 397. A project that is openly recruiting maintainers is telling you something about bus factor. That is a fact about the project's own communication, not an inference about the code.
Editorial conclusion
Adopt pypiserver if you need an internal index that pip and twine already know how to talk to, and you are content to manage the package directory yourself, including the htpasswd file that guards uploads. Do not adopt it if you need per-project permissions, a search UI, or the metadata services that Warehouse exposes, because pypiserver serves files from directories and does not build that layer. Verify first that your upload path is authenticated, that the directory is on storage you can back up, and that the WSGI server in front of it is the one you intend to run in production.
Community notes