postgresqldockerasp.net-coredocker-composeblazor

Dockerised WASM, ASP.NET Core Web API & Postgres - 405 Error


I have a project with 3 docker containers/services: Blazor WASM client, ASP.NET Core Web API, and a Postgres database. I have set up SSL in Nginx and can reach the client without issues. All containers appear to run fine, and no errors are being thrown during docker-compose build.

Although I try not to reach out too often, I'm really stumped by issues connecting between API and db container, with previous 502 error resolved by removing proxy reference from nginx.conf but an ongoing 405 error as the only response coming back. All database migration attempts have failed using code in Program.cs and in API Dockerfile.

I can overcome this with SQL script, but still after this is done and the database & table schema is built, the http 405 error persists. Any advice from those more experienced would be greatly appreciated.

Please note: the pgAdmin4 service/container was only added for troubleshooting, and is not part of the project itself - it will be removed, but I left it here in case it helps guide a potential response - no issues in connecting from pgAdmin4 to postgres container.

EDIT: adding the proxy config into the Nginx.conf caused a http 502 Bad gateway response, as previously experienced. This was initially masked it seems by cached data in the browser.

The relevant code segments are shown here - Nginx.conf:

worker_processes 4;
events {
    worker_connections 1024;

http {
    sendfile on;
    upstream app_servers {
        server backend:7000;
        # server 127.0.0.1:5432;
    }

include /etc/nginx/mime.types; 
server {
    listen 443 ssl;
    server_name 192.168.20.144;
    ssl_certificate /etc/nginx/certs/cert.pem;
    ssl_certificate_key /etc/nginx/certs/key.pem;
    root /usr/share/nginx/html;
    location /api/ {
        proxy_pass http://backend:7000/api;
        proxy_http_version 1.1;
        proxy_set_header   Host $host;
        proxy_set_header   X-Real-IP $remote_addr;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Host $server_name;
    }
}

This is the Docker-compose.yml file:

services:

  frontend:
    build:
      context: .
      dockerfile: Dockerfile-app
    ports:
      - '80:80'
      - '443:443'
    tty: true
    networks:
      - frontend

  backend:
    build:
      context: .
      dockerfile: Dockerfile-api
    ports:
      - '7000:7000'
    depends_on:
      - database
    networks:
      - frontend
      - backend
  
  pgadmin:
    container_name: pgadmin
    image: dpage/pgadmin4:snapshot
    restart: always
    environment:
      PGADMIN_DEFAULT_EMAIL: admin@admin.com
      PGADMIN_DEFAULT_PASSWORD: password
      PGADMIN_LISTEN_PORT: 80
    ports:
      - "8000:80"
    networks:
      - backend
    depends_on:
      - database
    volumes:
      - data:/data/db

  database:
    build:
      context: .
      dockerfile: Dockerfile-db
    restart: always
    volumes:
      - data:/data/db
      - ./cert.pem://var/lib/postgresql/cert.pem
      - ./key.pem://var/lib/postgresql/key.pem
    ports:
      - '5432:5432'
    environment:
      POSTGRES_PASSWORD: pass
      POSTGRES_USERNAME: postgres
      POSTGRES_DB: mpau
    networks:
      - backend

volumes:
  data:

networks:
  frontend:
    name: custom_frontend
  backend:
    name: custom_backend

Dockerfile for the Web API looks like this:

FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:9.0 AS build
ARG TARGETARCH
WORKDIR /source

# Copy project file and restore as distinct layers
COPY --link Server/*.csproj .
RUN dotnet restore -a $TARGETARCH
RUN dotnet tool restore
ENTRYPOINT dotnet ef database update --project ./*.csproj --connection "host=database-1 port=5432 dbname=mpau user=postgres password=pass connect_timeout=10 sslmode=prefer sslcert=<STORAGE_DIR>/.postgresql/cert.pem sslkey=<STORAGE_DIR>/.postgresql/key.pem"

# Copy source code and publish app
COPY --link Server/. .
RUN dotnet publish -a $TARGETARCH -o /app

# Runtime stage
FROM mcr.microsoft.com/dotnet/aspnet:9.0
EXPOSE 8080
WORKDIR /app
COPY --link --from=build /app .
USER $APP_UID
ENTRYPOINT ["dotnet", "wasm.Server.dll"]

Solution

  • I’ve dealt with this setup Blazor WASM + ASP.NET Core API behind Nginx with SSL and came across into the same 405 Method Not Allowed headache. In your case, the issue is probably that Nginx isn’t properly forwarding API calls to the backend.

    Right now, your nginx.conf only has a generic location / block, which means all requests including /api/... are either served as static files or fall back to index.html. So when the frontend sends a POST to /api/whatever, it never reaches your API it hits the frontend instead, which doesn't support that method, and you get a 405.

    To fix it, you need to add a dedicated location /api block in your Nginx config to proxy those requests to the backend container. Something like:

    location /api {
        proxy_pass http://backend:7000/api;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
    

    One more thing — if you're getting blocked even after fixing the proxy, it might be CORS. If your frontend is served from the same origin (like https://192.168.20.144), make sure your API allows that origin and all methods/headers via CORS:

    builder.Services.AddCors(options =>
    {
        options.AddDefaultPolicy(policy =>
            policy.WithOrigins("https://192.168.20.144")
                  .AllowAnyHeader()
                  .AllowAnyMethod());
    });