skip to Main Content

Goal: Reverse-proxy to private pypi server with nginx (eventually with SSL, but I can’t get it to work without yet.) in docker-compose

I can access pypi server on port 8080 when I launch it exclusively.
I can access nginx on port 80 when I launch it solo, or with pypi.

With the config below (both,) I can access nginx on port 80, but the /pypi path returns a 404.

When the nginx container is commented out, the pypi server responds on port 8080 as expected.

What’s misconfigured?

docker-compose.yml

version: '3.3'
services:
# NGINX container
  nginx:
    container_name: nginx
    image: nginx:1.22.0-alpine
    ports:
      - 80:80
    volumes:
      - ./nginx/conf.d/pypi.conf:/etc/nginx/conf.d/pypi.conf
      - ./nginx/nginx_cache:/var/nginx/cache

# PYPI container
  pypi-server:
    image: pypiserver/pypiserver:latest
    container_name: pypi-server
    volumes:
      - type: bind
        source: /home/ec2-user/auth
        target: /data/auth
      - type: volume
        source: pypi-server
        target: /data/packages
    command: run -P . -a .
    restart: always

volumes:
  pypi-server:

pypi.conf

server {
  location /pypi {
      proxy_set_header  X-Forwarded-Host $host:$server_port/pypi;
      proxy_set_header  X-Forwarded-Proto $scheme;
      proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header  X-Real-IP $remote_addr;
      proxy_pass        http://127.0.0.1:8080/;
  }
}

and from the docker-compose logs output, these two lines seem pertinent:

pypi-server    | Serving on http://0.0.0.0:8080
...
nginx          | 2023/06/12 00:29:02 [error] 31#31: *1 open() "/usr/share/nginx/html/pypi" failed (2: No such file or directory), client: 10.90.0.5, server: localhost, request: "GET /pypi HTTP/1.1", host: "10.102.96.109"

Is it just ignoring the proxy config, or pypi.conf altogether? Is that due to some yml syntax, docker syntax, or permissions issues on the directories?

2

Answers


  1. Chosen as BEST ANSWER

    RESOLVED--and well, there were a few issues here.

    First, docker-compose required mapping or exposing the pypi port 8080, because nginx running in one container can't see pypi running in the other unless the ports are exposed.

    Second, the tutorial I was following implicitly omitted nginx/conf.d/default.conf without explicitly stating that. As a result, the settings in my nginx/conf.d/pypi.conf were ostensibly being overridden.

    Third, there are some idiosyncrasies in the nginx configs, like trailing slashes in the correct places, that had an impact.

    This now works with a single nginx/conf.d/default.conf that defines the reverse proxy in a way similar to the intended in the question.

    nginx/conf.d/default.conf

    server {
        listen       80;
        listen  [::]:80;
        server_name  localhost;
     
        access_log  /var/log/nginx/host.access.log  main;
     
        root   /usr/share/nginx/html;
     
        location / {
            index  index.html index.htm;
        }
     
        error_page  404              /404.html;
     
        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
     
        }
     
        location /pypi {
            proxy_pass        http://pypi-server:8080/;
            proxy_set_header  X-Forwarded-Host $host;
            proxy_set_header  X-Forwarded-Port $server_port;
            proxy_set_header  X-Forwarded-Proto $scheme;
            proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header  X-Real-IP $remote_addr;
        }
     
        location ~ ((?:simple|packages).*) {
            proxy_pass        http://pypi-server:8080/$1;
            proxy_set_header  X-Forwarded-Host $host;
            proxy_set_header  X-Forwarded-Port $server_port;
            proxy_set_header  X-Forwarded-Proto $scheme;
            proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header  X-Real-IP $remote_addr;
        }
    }
    

    docker-compose.yml

    version: '3.3'
    services:
    # NGINX container
      nginx:
        container_name: nginx
        hostname: nginx
        image: nginx:1.22.0-alpine
        ports:
          - "80:80"
        volumes:
          - ./nginx/conf.d/default.conf:/etc/nginx/conf.d/default.conf
          - ./nginx/nginx.conf:/etc/nginx/nginx.conf
          - ./nginx/nginx_cache:/var/nginx/cache
     
    # PYPI container
      pypi-server:
        image: pypiserver/pypiserver:latest
        expose:
          - "8080"
        container_name: pypi-server
        volumes:
          - type: bind
            source: /home/ec2-user/auth
            target: /data/auth
          - type: volume
            source: pypi-server
            target: /data/packages
        command: run -P . -a .
        restart: always
     
    volumes:
      pypi-server:
    

    Some references:
    Setting up a Private Pypi Server with nginx and docker-compose
    nginx beginners guide
    nginx pitfalls and common mistakes
    Pypi documentation


  2. I have further questions, this solution did work for me with regards to pypiserver working with NGINX, but it breaks my SVN repository, which I also have under NGINX.

    It comes down to the fact that location ~ ((?:simple|packages).*) is intersecting requests to my SVN repository towards pulling and committing to things like https://mysvnrepo.com/svnroot/mylibary/packages/mydev.

    So my question is there a way to just handle the pip installation to /simple and /packages within the location /pypi?

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search