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"]
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());
});