djangodockernginxuwsgi

Pass requests from host to container with domain socket


I have uwsgi running on a docker container. Nginx running on host.

Current setup:

;uwsgi.ini

http-socket=:8080

With docker, I've forwarded the host's 8080 port to containers 8080 port. Nginx is configured like

server {
    listen 443 ssl http2;
    server_name domain.example.com;
    location / {
        proxy_pass http://127.0.0.1:8080;
    }
}

This works fine, only problem: my port 8080 is exposed and I can directly request the port on the public IP. I should be able to use domain sockets to mitigate this, but I don't know how the set up would look like.

Here's my half attempt:

; uwsgi.ini in container

socket=/path/uwsgi.sock
# nginx on host

upstream prod_server {
    server unix:///path/uwsgi.sock;
}

server {
    listen 443 ssl http2;
    server_name example.domain.com;
    location {
        uwsgi_pass pror_server;
    }
}

Since nginx is in host, it will look for the path on host server, is adding the socket as a volume the right way to go? Is there another best practice? How would you recommend the setup? Thank you.


Solution

  • my port 8080 is exposed and I can directly request the port on the public IP

    When you publish the port, the docker run -p and Compose ports: options take an optional IP address. This is the IP address on the host that Docker should bind the external listening socket to. It defaults to 0.0.0.0, or "all interfaces", but you can specify 127.0.0.1 to bind only to the host's localhost interface, and the backend won't be reachable from other systems.

    docker run -p 127.0.0.1:8080:8080 ...
    #             ^^^^^^^^^
    
    ports:
      - '127.0.0.1:8000:8000'
      #  ^^^^^^^^^
    

    is adding the [Unix] socket as a volume the right way to go?

    If you want to use a Unix socket here, you need a Docker bind mount (not a named volume), and you need to mount the directory containing the socket and not the socket itself. That probably means the directory needs to be an otherwise-empty directory, since the contents of the host directory will completely replace the image's contents – don't try to use the directory containing your application code here.

    docker run -v /path:/path ...
    #          -v /host/path:/container/path ...
    
    volumes:
      - "/path:/path
    

    The first path is the host path, and matches your Nginx configuration; the second is the container path and matches your uwsgi.ini file. The two paths don't need to match.

    Unix sockets may not work at all on Docker Desktop or other VM-based setups; it may only work on a native-Linux host directly running the Docker engine.

    How would you recommend the setup?

    I'd run Nginx in a container if possible. Then the two containers can use Docker networking to communicate, and you're not required to publish the backend's port at all.

    If the proxy is on the host system already (maybe you're proxying a mix of container and non-container applications, or multiple applications and it doesn't make sense to attach the proxy to any one specifically) then I'd use a TCP socket but published only to the host, as in the first half. It's a simpler setup and avoids problems around filesystem permissions.