Ethan
Ethan

Reputation: 53

NGINX reverse proxy not working for .NET core webAPI running in Docker

I have a simple example webAPI in .NET core, running in a docker container. I'm running Nginx also in a docker container as a reverse proxy for https redirection. The webAPI is accessible on http, but when accessing the https url, the API is not responding.

I have tried many different configurations in the nginx.conf file. I've tried using localhost, 0.0.0.0, and 127.0.0.1. I've tried using several different ports such as 5000, 8000, and 80. I've tried using upstream and also specifying the url on the proxy_pass line directly.

docker-compose.yml:

version: '3.4'

networks:
  blogapi-dev:
    driver: bridge

services:
  blogapi:
    image: blogapi:latest
    depends_on:
      - "postgres_image"
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "8000:80"
    expose:
      - "8000"
    environment:
      DB_CONNECTION_STRING: "host=postgres_image;port=5432;database=blogdb;username=bloguser;password=bloguser"
      ASPNETCORE_ENVIRONMENT: development
      #REMOTE_DEBUGGING: ${REMOTE_DEBUGGING}
    networks:
      - blogapi-dev
    tty: true
    stdin_open: true

  postgres_image:
    image: postgres:latest
    ports:
      - "5000:80"
    restart: always
    volumes:
      - db_volume:/var/lib/postgresql/data
      - ./BlogApi/dbscripts/seed.sql:/docker-entrypoint-initdb.d/seed.sql
    environment:
      POSTGRES_USER: "bloguser"
      POSTGRES_PASSWORD: "bloguser"
      POSTGRES_DB: blogdb
    networks:
      - blogapi-dev

  nginx-proxy:
    image: nginx:latest
    container_name: nginx-proxy
    ports:
      - 80:80
      - 443:443
    networks:
      - blogapi-dev
    depends_on:
      - "blogapi"
    volumes:
      - ./nginx-proxy/nginx.conf:/etc/nginx/nginx.conf
      - ./nginx-proxy/error.log:/etc/nginx/error_log.log
      - ./nginx-proxy/cache/:/etc/nginx/cache
      - /etc/letsencrypt/:/etc/letsencrypt/
      - /var/run/docker.sock:/tmp/docker.sock:ro
      - ./:/etc/nginx/

networks:
  blogapi-dev:
    driver: bridge

volumes:
  db_volume:

nginx.conf:

events {}
http {
    upstream backend {
        server 127.0.0.1:8000;
    }
    server {
        server_name local.website.dev;
        rewrite ^(.*) https://local.website.dev$1 permanent;
    }
    server {
        listen 443 ssl;
        ssl_certificate      localhost.crt;
        ssl_certificate_key  localhost.key;
        ssl_ciphers          HIGH:!aNULL:!MD5;
        server_name          local.website.dev;
        location / {
            proxy_pass  http://backend;
        }
    }
}

Startup.cs:

namespace BlogApi
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            var connectionString = Environment.GetEnvironmentVariable("DB_CONNECTION_STRING");
                    services.AddDbContext<BlogContext>(options =>
                    options.UseNpgsql(
                    connectionString));

            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseMvc();
        }
    }

When I go to http://127.0.0.1:8000/api/blog, the browser returns the json response from my api. This tells me that the app us up and running on port 8000, although it should not be accessable via http:


[{"id":1,"title":"Title 1","body":"Body 1","timeStamp":"1999-01-08T04:05:06"},{"id":2,"title":"Title 2","body":"Body 2","timeStamp":"2000-01-08T04:05:06"},{"id":3,"title":"Title 3","body":"Body 3","timeStamp":"2001-01-08T04:05:06"},{"id":4,"title":"Title 4","body":"Body 4","timeStamp":"2002-01-08T04:05:06"}]

When I go to 127.0.0.1, the browser properly redirects to https://local.website.dev/ but I get no response from the api, just the chrome local.website.dev refused to connect. ERR_CONNECTION_REFUSED. I get the same response when to go to https://local.website.dev/api/blog.

Also, this is the output from docker-compose up:

Starting blog_postgres_image_1 ... done
Starting blog_blogapi_1        ... done
Starting nginx-proxy           ... done
Attaching to blog_postgres_image_1, blog_blogapi_1, nginx-proxy
blogapi_1         | Hosting environment: development
blogapi_1         | Content root path: /app
blogapi_1         | Now listening on: http://[::]:80
blogapi_1         | Application started. Press Ctrl+C to shut down.
postgres_image_1  | 2019-06-27 11:20:49.441 UTC [1] LOG:  listening on IPv4 address "0.0.0.0", port 5432
postgres_image_1  | 2019-06-27 11:20:49.441 UTC [1] LOG:  listening on IPv6 address "::", port 5432
postgres_image_1  | 2019-06-27 11:20:49.577 UTC [1] LOG:  listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
postgres_image_1  | 2019-06-27 11:20:49.826 UTC [25] LOG:  database system was shut down at 2019-06-27 10:26:12 UTC
postgres_image_1  | 2019-06-27 11:20:49.893 UTC [1] LOG:  database system is ready to accept connections

Upvotes: 1

Views: 3146

Answers (1)

Ethan
Ethan

Reputation: 53

I got it working. There were a couple of issues. First, I was missing some boilerplate at the top of the nginx.conf file. Second, I needed to set the proxy_pass to the name of the docker container housing the service that I wanted to route to, in my case http://blogapi/, instead of localhost.

nginx.conf

worker_processes 1;

events {
    worker_connections 1024;
}

http {
    proxy_set_header Host $host;
    proxy_pass_request_headers on;

    gzip on;
    gzip_proxied any;

    map $sent_http_content_type $expires {
        default off;
        ~image/ 1M;
    }

    server {
        listen 80;
        listen [::]:80;
        server_name localhost; 
        return 301 https://172.24.0.1$request_uri;
    }

    server {
        listen 443 ssl;
        server_name localhost;
        ssl_certificate      localhost.crt;
        ssl_certificate_key  localhost.key;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers HIGH:!aNULL:!MD5;
        location / {
            proxy_pass http://blogapi/;
        }
    }
}

With the above configuration, I can access the webAPI at: https://172.24.0.1/api/blog/ If http://localhost/api/blog is entered, the browser will redirect to https://172.24.0.1/api/blog/ The IP address is the address of the blogapi-dev bridge network gateway as shown below.

docker inspect 20b

    "Networks": {
        "blog_blogapi-dev": {
            "IPAMConfig": null,
            "Links": null,
            "Aliases": [
                "20bd90d1a80a",
                "blogapi"
            ],
            "NetworkID": "1edd39000ac3545f9a738a5df33b4ea90e082a2be86752e7aa6cd9744b72d6f0",
            "EndpointID": "9201d8a1131a4179c7e0198701db2835e3a15f4cbfdac2a4a4af18804573fea9",
            "Gateway": "172.24.0.1",
            "IPAddress": "172.24.0.3",
            "IPPrefixLen": 16,
            "IPv6Gateway": "",
            "GlobalIPv6Address": "",
            "GlobalIPv6PrefixLen": 0,
            "MacAddress": "02:42:ac:18:00:03",
            "DriverOpts": null
        }
    }

Upvotes: 1

Related Questions