1
0
mirror of https://github.com/pypiserver/pypiserver synced 2024-12-20 13:55:49 +01:00

chore: cleanup README (#591)

* chore: make prettier callouts

* chore: some typography edits

* chore: small typos

* chore: mdformat

* chore: explicit links

* chore: mdformat

* chore: small styling
This commit is contained in:
Mitja O 2024-08-20 13:00:19 +02:00 committed by GitHub
parent c21c1e8fbe
commit d68355a371
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

293
README.md

@ -1,6 +1,6 @@
![pypi server logo](docs/__resources__/pypiserver_logo.png)
[**pypiserver - minimal PyPI server for use with pip/easy_install**](<>)
# [**pypiserver - minimal PyPI server for use with pip/easy_install**](#pypiserver)
[![pypi badge](https://img.shields.io/pypi/v/pypiserver.svg)](https://shields.io/)
[![ci workflow](https://github.com/pypiserver/pypiserver/actions/workflows/ci.yml/badge.svg)](https://github.com/pypiserver/pypiserver/actions/workflows/ci.yml)
@ -8,17 +8,19 @@
[![Generic badge](https://img.shields.io/badge/license-MIT%7Czlib/libpng-blue.svg)](https://raw.githubusercontent.com/pypiserver/pypiserver/master/LICENSE.txt)
| name | description |
| :---------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| :---------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Version | 2.1.1 |
| Date: | 2024-04-25 |
| Source | <https://github.com/pypiserver/pypiserver> |
| PyPI | <https://pypi.org/project/pypiserver/> |
| Tests | <https://github.com/pypiserver/pypiserver/actions> |
| Maintainers | Kostis Anagnostopoulos <ankostis@gmail.com>, Matthew Planchard <mplanchard@gmail.com>, Dmitrii Orlov <dmtree.dev@yahoo.com>, **Someone new?** We are looking for new maintainers! [#397](https://github.com/pypiserver/pypiserver/issues/397) |
| Maintainers | [`@ankostis`](https://github.com/ankostis), [`@mplanchard`](https://github.com/mplanchard), [`@dee-me-tree-or-love`](https://github.com/dee-me-tree-or-love), [`@pawamoy`](https://github.com/pawamoy), **Someone new?** *We are open for new maintainers! [#397](https://github.com/pypiserver/pypiserver/issues/397)* |
| License | zlib/libpng + MIT |
| Community | <https://pypiserver.zulipchat.com> |
Chat with us on [Zulip](https://pypiserver.zulipchat.com)!
> \[!TIP\]
> Reach out in [**Discussions**](https://github.com/pypiserver/pypiserver/discussions),
> or chat with us on [**Zulip**](https://pypiserver.zulipchat.com)
**pypiserver** is a minimal [PyPI](https://pypi.org/) compatible server for **pip** or **easy_install**.
It is based on [bottle](http://bottlepy.org/) and serves packages from regular directories.
@ -26,14 +28,14 @@ Wheels, bdists, eggs and accompanying PGP-signatures can be uploaded
either with **pip**, **setuptools**, **twine**, **pypi-uploader**, or simply copied
with **scp**.
Note
The official software powering [PyPI](https://pypi.org/) is
[Warehouse](https://github.com/pypa/warehouse/). However,
[Warehouse](https://github.com/pypa/warehouse/)
is fairly specialized to be **pypi.org**'s own software, and should not
be used in other contexts. In particular, it does not officially support
being used as a custom package index by users wishing to serve their own
packages.
> \[!Note\]
> The official software powering [PyPI](https://pypi.org/) is
> [Warehouse](https://github.com/pypa/warehouse/). However,
> [Warehouse](https://github.com/pypa/warehouse/)
> is fairly specialized to be **pypi.org**'s own software, and should not
> be used in other contexts. In particular, it does not officially support
> being used as a custom package index by users wishing to serve their own
> packages.
**pypiserver** implements the same interfaces as [PyPI](https://pypi.org/), allowing
standard Python packaging tooling such as **pip** and **twine** to
@ -44,6 +46,7 @@ making it much easier to get a running index server.
Table of Contents
- [**pypiserver - minimal PyPI server for use with pip/easy_install**](#pypiserver---minimal-pypi-server-for-use-with-pipeasy_install)
- [pypiserver](#pypiserver)
- [Quickstart Installation and Usage](#quickstart-installation-and-usage)
- [More details about pypi server run](#more-details-about-pypi-server-run)
@ -95,10 +98,10 @@ Older Python versions may still work, but they are not tested.
For legacy Python versions, use **pypiserver-1.x** series. Note that these are
not officially supported, and will not receive bugfixes or new features.
Tip
The commands below work on a unix-like operating system with a posix shell.
The **'~'** character expands to user's home directory.
> \[!TIP\]
>
> The commands below work on a unix-like operating system with a posix shell.
> The **'~'** character expands to user's home directory.
If you're using Windows, you'll have to use their "Windows counterparts".
The same is true for the rest of this documentation.
@ -110,16 +113,17 @@ The same is true for the rest of this documentation.
mkdir ~/packages # Copy packages into this directory.
```
See also [Alternative Installation methods](<>)
> \[!TIP\]
> See also [Alternative Installation methods](#alternative-installation-methods)
2. Copy some packages into your **~/packages** folder and then
1. Copy some packages into your **~/packages** folder and then
get your **pypiserver** up and running
```shell
pypi-server run -p 8080 ~/packages & # Will listen to all IPs.
```
3. From the client computer, type this
1. From the client computer, type this
```shell
# Download and install hosted packages.
@ -134,9 +138,12 @@ See also [Alternative Installation methods](<>)
# Note that pip search does not currently work with the /simple/ endpoint.
```
See also [Client-side configurations](#client-side-configurations) for avoiding tedious typing.
> \[!TIP\]
> See also [Client-side configurations](#client-side-configurations) for avoiding tedious typing.
4. Enter **pypi-server -h** in the cmd-line to print a detailed usage message
1. Enter **pypi-server -h** in the cmd-line to print a detailed usage message
<!-- NB: this text should be updated if the help message changes -->
```text
usage: pypi-server [-h] [-v] [--log-file FILE] [--log-stream STREAM]
@ -175,14 +182,14 @@ optional arguments:
--version show program's version number and exit
Visit https://github.com/pypiserver/pypiserver for more information
```
### More details about pypi server run
Enter **pypi-server run -h** in the cmd-line to print a detailed usage
<!-- NB: this text should be updated if the help message changes -->
```text
usage: pypi-server run [-h] [-v] [--log-file FILE] [--log-stream STREAM]
[--log-frmt FORMAT] [--hash-algo HASH_ALGO]
@ -335,8 +342,6 @@ optional arguments:
might pose a security risk - e.g. a malicious user
might publish a higher version of the private package,
containing arbitrary code.
```
## Client-Side Configurations
@ -362,12 +367,12 @@ or by adding the following lines to **~/.pip/pip.conf**
extra-index-url = http://localhost:8080/simple/
```
Note
If you have installed **pypiserver** on a remote url without *https*
you will receive an "untrusted" warning from *pip*, urging you to append
the **--trusted-host** option. You can also include this option permanently
in your configuration-files or environment variables.
> \[!NOTE\]
>
> If you have installed **pypiserver** on a remote url without *https*
> you will receive an "untrusted" warning from *pip*, urging you to append
> the **--trusted-host** option. You can also include this option permanently
> in your configuration-files or environment variables.
### Configuring easy_install
@ -385,9 +390,9 @@ Instead of copying packages directly to the server's folder (i.e. with **scp**),
you may use python tools for the task, e.g. **python setup.py upload**.
In that case, **pypiserver** is responsible for authenticating the upload-requests.
Note
We strongly advise to password-protected your uploads!
> \[!NOTE\]
>
> We strongly advise to ***password-protect*** your uploads!
It is possible to disable authentication for uploads (e.g. in intranets).
To avoid lazy security decisions, read help for **-P** and **-a** options.
@ -403,38 +408,39 @@ To avoid lazy security decisions, read help for **-P** and **-a** options.
pip install passlib
```
2. Create the Apache **htpasswd** file with at least one user/password pair
1. Create the Apache **htpasswd** file with at least one user/password pair
with this command (you'll be prompted for a password)
```shell
htpasswd -sc htpasswd.txt <some_username>
```
Tip
> \[!TIP\]
>
> Read this [SO](http://serverfault.com/questions/152950/how-to-create-and-edit-htaccess-and-htpasswd-locally-on-my-computer-and-then-u)
> question for running `htpasswd` cmd under *Windows*
> or if you have bogus passwords that you don't care because they are for
> an internal service (which is still "bad", from a security perspective...)
> you may use this [public service](http://www.htaccesstools.com/htpasswd-generator/)
Read this [SO](http://serverfault.com/questions/152950/how-to-create-and-edit-htaccess-and-htpasswd-locally-on-my-computer-and-then-u) question for running `htpasswd` cmd under *Windows*
or if you have bogus passwords that you don't care because they are for
an internal service (which is still "bad", from a security perspective...)
you may use this [public service](http://www.htaccesstools.com/htpasswd-generator/)
<!-- 2 tips separately -->
Tip
> \[!TIP\]
>
> When accessing pypiserver via the api, alternate authentication
> methods are available via the **auther** config flag. Any callable
> returning a boolean can be passed through to the pypiserver config in
> order to provide custom authentication. For example, to configure
> pypiserver to authenticate using the [python-pam](https://pypi.org/project/python-pam/)
>
> ```shell
> import pam
> pypiserver.default_config(auther=pam.authenticate)
> ```
When accessing pypiserver via the api, alternate authentication
methods are available via the **auther** config flag. Any callable
returning a boolean can be passed through to the pypiserver config in
order to provide custom authentication. For example, to configure
pypiserver to authenticate using the [python-pam](https://pypi.org/project/python-pam/)
Please see [`Using Ad-hoc authentication providers`](#using-ad-hoc-authentication-providers) for more information.
```shell
import pam
pypiserver.default_config(auther=pam.authenticate)
```
Please see `Using Ad-hoc authentication providers`\_ for more information.
3. You need to restart the server with the **-P** option only once
1. You need to restart the server with the **-P** option only once
(but user/password pairs can later be added or updated on the fly)
```shell
@ -575,7 +581,7 @@ available packages. It scans the package directory for available
packages and searches on pypi.org for updates. Without further
options **pypi-server update** will just print a list of commands which must
be run in order to get the latest version of each package. Output
looks like
looks like:
```shell
$ ./pypi-server update
@ -608,9 +614,10 @@ releases won't be considered.
### Serving Thousands of Packages
By default, **pypiserver** scans the entire packages directory each time an
incoming HTTP request occurs. This isn't a problem for a small number of
packages, but causes noticeable slow-downs when serving thousands of packages.
> \[!IMPORTANT\]
> By default, **pypiserver** scans the entire packages directory each time an
> incoming HTTP request occurs. This isn't a problem for a small number of
> packages, but causes noticeable slow-downs when serving thousands of packages.
If you run into this problem, significant speedups can be gained by enabling
pypiserver's directory caching functionality. The only requirement is to
@ -642,12 +649,12 @@ easily enable caching. For example, to allow nginx to cache up to
proxy_pass http://localhost:8080;
}
}
```
Using webserver caching is especially helpful if you have high request
volume. Using nginx caching, a real-world pypiserver installation was
able to easily support over 1000 package downloads/min at peak load.
> \[!TIP\]
> Using webserver caching is especially helpful if you have high request
> volume. Using nginx caching, a real-world pypiserver installation was
> able to easily support over 1000 package downloads/min at peak load.
### Managing Automated Startup
@ -716,8 +723,9 @@ From there, the process can be managed via **supervisord** using **supervisorctl
#### Running As a service with NSSM
For Windows download NSSM from <https://nssm.cc> unzip to a desired location such as Program Files. Decide whether you are going
to use win32 or win64, and add that exe to environment PATH.
For Windows download [NSSM](https://nssm.cc/) from <https://nssm.cc> unzip to a
desired location such as Program Files. Decide whether you are going
to use `win32` or `win64`, and add that `exe` to environment `PATH`.
Create a start_pypiserver.bat
@ -725,9 +733,11 @@ Create a start_pypiserver.bat
pypi-server run -p 8080 C:\Path\To\Packages &
```
Test the batch file by running it first before creating the service. Make sure you can access
the server remotely, and install packages. If you can, proceed, if not troubleshoot until you can.
This will ensure you know the server works, before adding NSSM into the mix.
> \[!TIP\]
> Test the batch file by running it first before creating the service.
> Make sure you can access the server remotely, and install packages. If you can,
> proceed, if not troubleshoot until you can. This will ensure you know the server
> works, before adding NSSM into the mix.
From the command prompt
@ -752,17 +762,17 @@ Start the service
nssm start pypiserver
```
Other useful commands
```shell
nssm --help
nssm stop <servicename>
nssm restart <servicename>
nssm status <servicename>
```
For detailed information please visit <https://nssm.cc>
> \[!TIP\]
> Other useful commands
>
> ```shell
> nssm --help
> nssm stop <servicename>
> nssm restart <servicename>
> nssm status <servicename>
> ```
>
> For detailed information please visit <https://nssm.cc>
### Using a Different WSGI Server
@ -778,7 +788,6 @@ For detailed information please visit <https://nssm.cc>
['cgi', 'gunicorn', 'cherrypy', 'eventlet', 'tornado', 'geventSocketIO',
'rocket', 'diesel', 'twisted', 'wsgiref', 'fapws3', 'bjoern', 'gevent',
'meinheld', 'auto', 'aiohttp', 'flup', 'gae', 'paste', 'waitress']
```
- If none of the above servers matches your needs, invoke just the
@ -794,12 +803,12 @@ For detailed information please visit <https://nssm.cc>
To use your *Apache2* with **pypiserver**, prefer to utilize **mod_wsgi** as
explained in [bottle's documentation](http://bottlepy.org/docs/dev/deployment.html#apache-mod-wsgi%3E).
Note
If you choose instead to go with **mod_proxy**, mind that you may bump into problems
with the prefix-path (see [#155](https://github.com/pypiserver/pypiserver/issues/155%3E)).
> \[!NOTE\]
> If you choose instead to go with **mod_proxy**, mind that you may bump into problems
> with the prefix-path (see [#155](https://github.com/pypiserver/pypiserver/issues/155%3E)).
1. Adapt and place the following *Apache* configuration either into top-level scope,
or inside some **<VirtualHost>** (contributed by Thomas Waldmann):
or inside some **`<VirtualHost>`** (contributed by Thomas Waldmann):
```shell
WSGIScriptAlias / /yoursite/wsgi/pypiserver-wsgi.py
@ -823,7 +832,7 @@ or if using older **Apache \< 2.4**, substitute the last part with this::
</Directory>
```
2. Then create the **/yoursite/cfg/pypiserver.wsgi** file and make sure that
1. Then create the **/yoursite/cfg/pypiserver.wsgi** file and make sure that
the **user** and **group** of the **WSGIDaemonProcess** directive
(**pypisrv:pypisrv** in the example) have the read permission on it
@ -838,24 +847,28 @@ or if using older **Apache \< 2.4**, substitute the last part with this::
```
Tip
If you have installed **pypiserver** in a virtualenv, follow **mod_wsgi**'s
[instructions](http://modwsgi.readthedocs.io/en/develop/user-guides/virtual-environments.html)
and prepend the python code above with the following
> \[!TIP\]
> If you have installed **pypiserver** in a virtualenv, follow **mod_wsgi**'s
> [instructions](http://modwsgi.readthedocs.io/en/develop/user-guides/virtual-environments.html)
> and prepend the python code above with the following
>
> ```python
> import site
>
> site.addsitedir('/yoursite/venv/lib/pythonX.X/site-packages')
> ```
```python
import site
<!-- tip and a note separately -->
site.addsitedir('/yoursite/venv/lib/pythonX.X/site-packages')
```
> \[!NOTE\]
> For security reasons, notice that the **Directory** directive grants access
> to a directory holding the **wsgi** start-up script, alone; nothing else.
Note
For security reasons, notice that the **Directory** directive grants access
to a directory holding the **wsgi** start-up script, alone; nothing else.
<!-- 2 notes separately -->
Note
To enable HTTPS support on Apache, configure the directive that contains the
WSGI configuration to use SSL.
> \[!NOTE\]
> To enable HTTPS support on Apache, configure the directive that contains the
> WSGI configuration to use SSL.
#### gunicorn
@ -901,21 +914,20 @@ unstable packages on different paths
port = 9000
workers = 5
accesslog = -
```
Note
You need to install some more dependencies for this to work, like::
```shell
pip install paste pastedeploy gunicorn pypiserver
```
The server can then start with
```shell
gunicorn_paster paste.ini
```
> \[!NOTE\]
> You need to install some more dependencies for this to work, like::
>
> ```shell
> pip install paste pastedeploy gunicorn pypiserver
> ```
>
> The server can then start with
>
> ```shell
> gunicorn_paster paste.ini
> ```
### Behind a Reverse Proxy
@ -940,7 +952,6 @@ Extend your nginx configuration
proxy_pass http://pypi;
}
}
```
As of pypiserver 1.3, you may also use the `X-Forwarded-Host` header in your
@ -996,18 +1007,21 @@ automatic HTTP redirection, using `nginx`
proxy_pass http://pypi;
}
}
```
Please see [nginx's HTTPS docs for more details](http://nginx.org/en/docs/http/configuring_https_servers.html).
Getting and keeping your certificates up-to-date can be simplified using,
for example, using [certbot and letsencrypt](https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-ubuntu-18-04%3E).
> \[!TIP\]
> Please see [nginx's HTTPS docs for more details](http://nginx.org/en/docs/http/configuring_https_servers.html).
>
> Getting and keeping your certificates up-to-date can be simplified using,
> for example, using [certbot and letsencrypt](https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-ubuntu-18-04%3E).
#### Traefik
It is also possible to use [Traefik](https://docs.traefik.io/) to put pypiserver behind HTTPS on port 443, with
automatic HTTP redirection using Docker Compose. Please see the provided [docker-compose.yml](https://github.com/pypiserver/pypiserver/blob/master/docker-compose.yml) example for more information.
It is also possible to use [Traefik](https://docs.traefik.io/) to put pypiserver
behind HTTPS on port 443, with automatic HTTP redirection using Docker Compose.
Please see the provided
[docker-compose.yml](https://github.com/pypiserver/pypiserver/blob/master/docker-compose.yml)
example for more information.
### Utilizing the API
@ -1015,7 +1029,8 @@ In order to enable ad-hoc authentication-providers or to use WSGI-servers
not supported by *bottle* out-of-the-box, you needed to launch **pypiserver**
via its API.
- The main entry-point for configuring **pypiserver** is the [pypiserver:app()](https://github.com/pypiserver/pypiserver/blob/master/pypiserver/__init__.py#L116)
- The main entry-point for configuring **pypiserver** is the
[pypiserver:app()](https://github.com/pypiserver/pypiserver/blob/master/pypiserver/__init__.py#L116)
function. This function returns the internal WSGI-app that you my then
send to any WSGI-server you like.
@ -1039,7 +1054,9 @@ these steps:
1. Ensure **python-pam** module is installed
```shell
pip install python-pam
```
1. Create a python-script along these lines
@ -1054,16 +1071,16 @@ these steps:
[Ctrl+ D]
```
3. Invoke the python-script to start-up **pypiserver**
1. Invoke the python-script to start-up **pypiserver**
```shell
python pypiserver-start.py
```
Note
The [python-pam](https://pypi.org/project/python-pam/) module, requires *read* access to **/etc/shadow** file;
you may add the user under which **pypiserver** runs into the *shadow*
group, with a command like this: **sudo usermod -a -G shadow pypy-user**.
> \[!NOTE\]
> The [python-pam](https://pypi.org/project/python-pam/) module, requires *read* access to **/etc/shadow** file;
> you may add the user under which **pypiserver** runs into the *shadow*
> group, with a command like this: **sudo usermod -a -G shadow pypy-user**.
### Use with MicroPython
@ -1076,7 +1093,6 @@ It can be tested with the UNIX port of **micropython**
```shell
cd micropython
ports/unix/micropython -m tools.upip install -i http://my-server:8080 -p /tmp/mymodules micropython-foobar
```
Installing packages from the REPL of an embedded device works in this way:
@ -1114,18 +1130,12 @@ Run pypiserver with **--health-endpoint** argument:
#### Configure a custom health endpoint by script
````python
import pypiserver
from pypiserver import bottle
app = pypiserver.app(root="./packages", health_endpoint="/action/health")
bottle.run(app=app, host="
```python
import pypiserver
from pypiserver import bottle
app = pypiserver.app(root="./packages", health_endpoint="/action/health")
bottle.run(app=app, host="0.0.0.0", port=8080, server="auto")
````
```
Try **curl <http://localhost:8080/action/health>**
@ -1146,9 +1156,10 @@ To receive any later changes, in the above folder use:
## Known Limitations
**pypiserver** does not implement the full API as seen on [PyPI](https://pypi.org/). It
implements just enough to make **easy_install**, **pip install**, and
**search** work.
> \[!IMPORTANT\]
> **pypiserver** does not implement the full API as seen on [PyPI](https://pypi.org/).
> It implements just enough to make **easy_install**, **pip install**, and
> **search** work.
The following limitations are known:
@ -1207,6 +1218,6 @@ may want to familiarize with:
# Licensing
**pypiserver** contains a copy of [bottle](http://bottlepy.org/) which is available under the
MIT license, and the remaining part is distributed under the zlib/libpng license.
See the **LICENSE.txt** file.
**pypiserver** contains a copy of [bottle](http://bottlepy.org/) which is
available under the MIT license, and the remaining part is distributed under
the zlib/libpng license. See the **LICENSE.txt** file.