diff --git a/README.md b/README.md index a850c67..6178241 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,11 @@ # [**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) -[![Generic badge](https://img.shields.io/badge/python-3.8%7C3.9+-blue.svg)](https://pypi.org/project/pypiserver/) -[![Generic badge](https://img.shields.io/badge/license-MIT%7Czlib/libpng-blue.svg)](https://raw.githubusercontent.com/pypiserver/pypiserver/main/LICENSE.txt) +[![PyPi project badge](https://img.shields.io/pypi/v/pypiserver.svg)](https://pypi.org/project/pypiserver/) +[![Python Versions](https://img.shields.io/badge/python-3.8%7C3.9+-blue.svg)](https://pypi.org/project/pypiserver/) +[![CI workflow](https://github.com/pypiserver/pypiserver/actions/workflows/ci.yml/badge.svg)](https://github.com/pypiserver/pypiserver/actions/workflows/ci.yml) +[![Licenses](https://img.shields.io/badge/license-MIT%7Czlib/libpng-blue.svg)](https://raw.githubusercontent.com/pypiserver/pypiserver/main/LICENSE.txt) +[![Stable Docker Tag](https://img.shields.io/docker/v/pypiserver/pypiserver/latest?label=Docker%20Hub%20%28stable%29%0A)](https://hub.docker.com/r/pypiserver/pypiserver/tags) | name | description | | :---------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | @@ -91,20 +92,26 @@ Table of Contents ## Quickstart Installation and Usage -**pypiserver** works with Python 3.6+ and PyPy3. +> [!IMPORTANT] +> **pypiserver** works with Python 3.8+ and PyPy3. -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. +> [!WARNING] +> 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 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. +> +> If you're using Windows, you'll have to use their "Windows counterparts".\ +> The same is true for the rest of this documentation. 1. Install **pypiserver** with this command @@ -347,9 +354,12 @@ optional arguments: ## Client-Side Configurations Always specifying the pypi url on the command line is a bit -cumbersome. Since **pypiserver** redirects **pip/easy_install** to the -**pypi.org** index if it doesn't have a requested package, it is a -good idea to configure them to always use your local pypi index. +cumbersome. + +> [!TIP] +> Since **pypiserver** redirects **pip/easy_install** to the **pypi.org** index +> if it doesn't have a requested package, it is a good idea to configure them to +> always use your local pypi index. ### Configuring pip @@ -362,7 +372,7 @@ export PIP_EXTRA_INDEX_URL=http://localhost:8080/simple/ or by adding the following lines to **~/.pip/pip.conf** -```shell +```ini [global] extra-index-url = http://localhost:8080/simple/ ``` @@ -379,7 +389,7 @@ extra-index-url = http://localhost:8080/simple/ For **easy_install** command you may set the following configuration in **~/.pydistutils.cfg** -```shell +```ini [easy_install] index_url = http://localhost:8080/simple/ ``` @@ -387,10 +397,10 @@ index_url = http://localhost:8080/simple/ ### Uploading Packages Remotely 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**. +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] +> [!IMPORTANT] > > We strongly advise to ***password-protect*** your uploads! @@ -405,14 +415,14 @@ To avoid lazy security decisions, read help for **-P** and **-a** options. (see next steps) ```shell - pip install passlib + pip install passlib ``` 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 + htpasswd -sc htpasswd.txt ``` > [!TIP] @@ -433,9 +443,9 @@ To avoid lazy security decisions, read help for **-P** and **-a** options. > 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) +> ```python +> import pam +> pypiserver.default_config(auther=pam.authenticate) > ``` Please see [`Using Ad-hoc authentication providers`](#using-ad-hoc-authentication-providers) for more information. @@ -444,34 +454,34 @@ Please see [`Using Ad-hoc authentication providers`](#using-ad-hoc-authenticatio (but user/password pairs can later be added or updated on the fly) ```shell - ./pypi-server run -p 8080 -P htpasswd.txt ~/packages & + ./pypi-server run -p 8080 -P htpasswd.txt ~/packages & ``` #### Upload with setuptools 1. On client-side, edit or create a **~/.pypirc** file with a similar content: - ```shell - [distutils] - index-servers = - pypi - local + ```ini + [distutils] + index-servers = + pypi + local - [pypi] - username: - password: + [pypi] + username: + password: - [local] - repository: http://localhost:8080 - username: - password: + [local] + repository: http://localhost:8080 + username: + password: ``` 1. Then from within the directory of the python-project you wish to upload, issue this command: ```shell - python setup.py sdist upload -r local + python setup.py sdist upload -r local ``` #### Upload with twine @@ -482,7 +492,7 @@ To avoid storing you passwords on disk, in clear text, you may either: like that ```shell - python setup.py sdist register -r local upload -r local + python setup.py sdist register -r local upload -r local ``` - use *twine* library, which @@ -491,13 +501,14 @@ To avoid storing you passwords on disk, in clear text, you may either: to **pypiserver**:: ```shell - twine upload -r local --sign -identity user_name ./foo-1.zip + twine upload -r local --sign -identity user_name ./foo-1.zip ``` ## Using the Docker Image Starting with version 1.2.5, official Docker images will be built for each push to `main`, each dev, alpha, or beta release, and each final release. + The most recent full release will always be available under the tag **latest**, and the current `main` branch will always be available under the tag **unstable**. @@ -508,7 +519,7 @@ You can always check to see what tags are currently available at our To run the most recent release of **pypiserver** with Docker, simply ```shell - docker run pypiserver/pypiserver:latest run +docker run pypiserver/pypiserver:latest run ``` This starts **pypiserver** serving packages from the **/data/packages** @@ -522,7 +533,7 @@ Of course, just running a container isn't that interesting. To map port 80 on the host to port 8080 on the container:: ```shell - docker run -p 80:8080 pypiserver/pypiserver:latest run +docker run -p 80:8080 pypiserver/pypiserver:latest run ``` You can now access your **pypiserver** at **localhost:80** in a web browser. @@ -530,13 +541,13 @@ You can now access your **pypiserver** at **localhost:80** in a web browser. To serve packages from a directory on the host, e.g. **~/packages** ```shell - docker run -p 80:8080 -v ~/packages:/data/packages pypiserver/pypiserver:latest run +docker run -p 80:8080 -v ~/packages:/data/packages pypiserver/pypiserver:latest run ``` To authenticate against a local **.htpasswd** file:: ```shell - docker run -p 80:8080 -v ~/.htpasswd:/data/.htpasswd pypiserver/pypiserver:latest run -P .htpasswd packages +docker run -p 80:8080 -v ~/.htpasswd:/data/.htpasswd pypiserver/pypiserver:latest run -P .htpasswd packages ``` You can also specify **pypiserver** to run as a Docker service using a @@ -635,7 +646,7 @@ reverse-proxy as described below in `Behind a reverse proxy`, you can easily enable caching. For example, to allow nginx to cache up to 10 gigabytes of data for up to 1 hour:: -```shell +```nginx proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=pypiserver_cache:10m @@ -670,7 +681,7 @@ an easy task without a third party tool such as *NSSM*. it is an excellent option for managing the pypiserver process. An example config file for **systemd** can be seen below -```shell +```ini [Unit] Description=A minimal PyPI server for use with pip/easy_install. After=network.target @@ -709,7 +720,7 @@ More useful information about *systemd* can be found at package and as such, it provides excellent cross-platform support for process management. An example configuration file for **supervisor** is given below -```shell +```ini [program:pypi] command=/home/pypi/pypi-venv/bin/pypi-server run -p 7001 -P /home/pypi/.htpasswd /home/pypi/packages directory=/home/pypi @@ -728,7 +739,7 @@ For Windows download [NSSM](https://nssm.cc/) from 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 +Create a `start_pypiserver.bat` ```shell pypi-server run -p 8080 C:\Path\To\Packages & @@ -811,7 +822,7 @@ explained in [bottle's documentation](http://bottlepy.org/docs/dev/deployment.ht 1. Adapt and place the following *Apache* configuration either into top-level scope, or inside some **``** (contributed by Thomas Waldmann): - ```shell + ```apache WSGIScriptAlias / /yoursite/wsgi/pypiserver-wsgi.py WSGIDaemonProcess pypisrv user=pypisrv group=pypisrv umask=0007 \ processes=1 threads=5 maximum-requests=500 \ @@ -826,7 +837,7 @@ explained in [bottle's documentation](http://bottlepy.org/docs/dev/deployment.ht or if using older **Apache < 2.4**, substitute the last part with this:: - ```shell + ```apache Order deny,allow Allow from all @@ -838,14 +849,12 @@ explained in [bottle's documentation](http://bottlepy.org/docs/dev/deployment.ht (**pypisrv:pypisrv** in the example) have the read permission on it ```python - import pypiserver conf = pypiserver.default_config( root = "/yoursite/packages", password_file = "/yoursite/htpasswd", ) application = pypiserver.app(**conf) - ``` > [!TIP] @@ -894,27 +903,27 @@ of packages on different paths. The following example **paste.ini** could be used to serve stable and unstable packages on different paths -```shell - [composite:main] - use = egg:Paste#urlmap - /unstable/ = unstable - / = stable +```ini +[composite:main] +use = egg:Paste#urlmap +/unstable/ = unstable +/ = stable - [app:stable] - use = egg:pypiserver#main - root = ~/stable-packages +[app:stable] +use = egg:pypiserver#main +root = ~/stable-packages - [app:unstable] - use = egg:pypiserver#main - root = ~/stable-packages - ~/unstable-packages +[app:unstable] +use = egg:pypiserver#main +root = ~/stable-packages + ~/unstable-packages - [server:main] - use = egg:gunicorn#main - host = 0.0.0.0 - port = 9000 - workers = 5 - accesslog = - +[server:main] +use = egg:gunicorn#main +host = 0.0.0.0 +port = 9000 +workers = 5 +accesslog = - ``` > [!NOTE] @@ -938,7 +947,7 @@ You can run **pypiserver** behind a reverse proxy as well. Extend your nginx configuration -```shell +```nginx upstream pypi { server pypiserver.example.com:12345 fail_timeout=0; } @@ -959,7 +968,7 @@ As of pypiserver 1.3, you may also use the `X-Forwarded-Host` header in your reverse proxy config to enable changing the base URL. For example if you want to host pypiserver under a particular path on your server -```shell +```nginx upstream pypi { server localhost:8000; } @@ -981,7 +990,7 @@ Using a reverse proxy is the preferred way of getting pypiserver behind HTTPS. For example, to put pypiserver behind HTTPS on port 443, with automatic HTTP redirection, using `nginx` -```shell +```nginx upstream pypi { server localhost:8000; }