1

Overview

I have a frontend using Vue and a backend using FastAPI.

I have made Docker containers of both and a docker-compose.yml to hook it all together. It all works fine locally when I am developing.

When I move it to Azure, I am receiving a CORS error, specifically Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://<my-site>.azurewebsites.net:8080/login.

I have looked at several CORS questions (here is another) and Azure multi-container tutorials (another one, yet another and one last one). None of the suggestions solved the problem, but none of them were my exact situation:

  • Azure Web App
  • Using Multi-Container
  • With a separate front end (Vue) and back end (FastAPI)

Code

Here are the relevant parts of my code:

docker-compose.yml

version: "3.8"
services:
  frontend:
    image: <my-acr>.azurecr.io/<my-fe-image>:1
    networks:
      - fullstack
    ports:
      - "80:80"
  backend:
    image: <my-acr>.azurecr.io/<my-be-image>:1
    networks:
      - fullstack
    ports:
      - "8080:80"
networks:
  fullstack:

Front End Dockerfile

# develop stage
FROM node:14.8-alpine3.12 as develop-stage

ENV CONTAINER_PATH /vue

WORKDIR $CONTAINER_PATH

COPY package*.json ./

RUN yarn install

COPY . .

# build stage
FROM develop-stage as build-stage
RUN ["yarn", "build"]

# production stage
FROM nginx:1.19.2-alpine as production-stage
COPY --from=build-stage /vue/dist /usr/share/nginx/html
EXPOSE 8080 2222 80 443
CMD ["nginx", "-g", "daemon off;"]

Front End Axios Code

import axios from "axios";

export default () => {
  return axios.create({
    baseURL: `https://<my-site>.azurewebsites.net:8080/`,
    headers: { "Access-Control-Allow-Origin": "*" },
  });
};

Back End Dockerfile

FROM tiangolo/uvicorn-gunicorn:python3.8

RUN ["pip", "install", "--upgrade", "pip"]

RUN ["pip", "install", "--upgrade", "--ignore-installed", \
    "--use-feature=2020-resolver", "--no-cache-dir", "jwcrypto", "fastapi", "passlib", \
    "sqlalchemy", "toml", "topicaxis-opengraph", "sqlalchemy_imageattach", \
    "email_validator", "bcrypt"]

EXPOSE 8080 2222 80 443

COPY ./src /app

Back End FastAPI Code

app = FastAPI()

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

I know much of that is too loose... I will fix it once I can get anything to work.


Azure Commands

First, I read that only ports 80 and 8080 are recognized, so I put my FE on 80 and my BE on 8080.

Next, these are the relevant Azure commands, once I pushed the containers up:

  1. az webapp create -g <my-rg> -p <my-plan> -n <app-name> --multicontainer-config-file ./docker-compose.yml --multicontainer-config-type COMPOSE --assign-identity /subscriptions/<my-subscription/resourceGroups/<my-rg>/providers/Microsoft.ManagedIdentity/userAssignedIdentities/<my-userid>
  2. az webapp config appsettings set -g <my-rg> -n <my-app> --settings WEBSITES_PORT=80
  3. az role assignment create --assignee <my-info> --scope /subscriptions/<my-subscription>/resourceGroups/<my-rg>/providers/Microsoft.ContainerRegistry/registries/<my-acr> --role "AcrPull"
  4. az webapp cors add -g <my-rg> -n <app-name> --allowed-origins "*"
  5. az webapp config container set -n <app-name> -g <my-rg> --multicontainer-config-file ./docker-compose.yml --multicontainer-config-type COMPOSE --docker-registry-server-url https://<my-site>.azurecr.io
  6. az webapp restart -n <app-name> -g <my-rg>

The docker-compose.yml mentioned above is the same one that is shown earlier.


I am able to see all of the front end fine, but any time the front-end tries to reach the back end, it hangs for a while and then comes back with the Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://<my-site>.azurewebsites.net:8080 error.

I am also unable to hit the back end directly, either just to see the raw API, or using FastAPI's auto-generated docs page.

Mike Williamson
  • 4,915
  • 14
  • 67
  • 104
  • all requests (GET/POST/PUT etc...) have same issue? could you open the browser console, then add the raw header of the `request` and `response` for one http request failed due to CORS. – Sphinx Sep 16 '20 at 21:22
  • Make sure to use browser navigation for OAuth login endpoint as opposed to making XHR request through axios, that is one of the gotchas. – Dipen Shah Sep 17 '20 at 03:55
  • @DipenShah Can you explain what you mean? I am not sure what you mean by "browser navigation for OAuth"? What would I use instead of axios? – Mike Williamson Sep 17 '20 at 10:01
  • if you cannot access swagger docs - it might mean your FastAPI container does not start at all. can you check the logs or otherwise verify the container runs? – timur Sep 17 '20 at 10:29
  • @MikeWilliamson what I meant was that make sure you are not calling `/login` endpoint from Axiom but rather use `a` tag or `window.location` to redirect user to `/login` end point. – Dipen Shah Sep 17 '20 at 15:29
  • @timur Yes, the back end is up and running; I can see the container logs. I just cannot access it. @DipenShah I will try that. I have always just used `/login` or whatever endpoint. I did not know I could use other means like `window.location`. But just to be clear: I am talking about communication between my front end and back end, which I have put on 2 different containers. Don't I need to provide a valid URI path to connect them? It's not just SPA directing like you get with [Vue router](https://router.vuejs.org/). – Mike Williamson Sep 18 '20 at 08:39
  • @Mike Williamson Did you try to set ```http://backend:8080``` as the value of your ```baseURL``` configuration property? As long as both containers share the same docker network, maybe you can reference them by name. On the other hand, what error do you get when trying to access your backend directly or the FastAPI docs? Not found? Forbidden? – jccampanero Sep 18 '20 at 16:59

3 Answers3

4

I must admit that I never ran a multi-container deployment in App Service with frontend and backend, only self-contained apps or single container ones. Having said that...

I think there are several problems here.

The first is why you can't connect to your backend service externally.

If you are using a Linux based Azure App Service, according to the Azure documentation, in a multi-container deployment, only one container is open to access over the internet. Which one? Here are the rules:

Here are the rules for determining which container is accessible - in the order of precedence:

  • Application setting WEBSITES_WEB_CONTAINER_NAME set to the container name
  • The first container to define port 80 or 8080
  • If neither of the above is true, the first container defined in the file will be accessible (exposed)

(Sorry, I was unable to format the list correctly).

This may be the reason why the backend container is not accessible from the externally, and, if both containers should be accessed from the internet, it will be a good reason to change your deployment for two single-container ones instead.

Another problem is why you are getting the CORS error.

There are several things that could cause the problem.

On one hand, it is not necessary to configure CORS for your web app as long as your frontend need not to be consumed in that way. So this configuration is not necessary:

az webapp cors add -g <my-rg> -n <app-name> --allowed-origins "*"

For the same reason, you do not need to configure CORS in Axios, so you can safely remove the following configuration line from your code:

headers: { "Access-Control-Allow-Origin": "*" },

And a question remains: how can you contact your backend service from your frontend?

First of all, it looks like your FastAPI configuration is right.

As proposed in my comment, my best advice is that you configure your Axios client to take advantage of the docker internal networking and configure Axios to use backend as the host to which sent their requests.

If you review the first multi-container example that you indicated (https://learn.microsoft.com/en-us/azure/app-service/tutorial-multi-container-app), when they configure the Wordpress container, they are referencing, in their configuration properties, db as the hostname, being db an exposed service:

WORDPRESS_DB_HOST: db:3306

In short, I think the multi-container setup is best suited for use cases when you have a service and multiple resources (SQL databases, Kafka, Redis) required for that service to function properly.

It might also be appropriate if you don't need to access your backend externally, only through your frontend.

In any other case, a deployment with two single container web applications should be more suitable.

One last thought ... If you necessarily need to implement a multi-container solution, maybe you can include some kind of webserver like nginx, the idea of a reverse proxy as also suggested in @timur's comment, that you can expose at the 80 port, and define rules to access the frontend and backend services. It should be tested, but this could help you greatly simplify your CORS setup and even avoid the need to use it.

jccampanero
  • 50,989
  • 3
  • 20
  • 49
  • I wonder if sitting two containers behind a reverse proxy would allow OP to bypass the single visible container limitation – timur Sep 18 '20 at 19:10
  • 1
    Sorry @timur, I just saw your comment. Thank you very much. Yes indeed, it should be tried, but I think it could also be a possible solution. In fact, I had already updated my answer with something similar to your proposal. – jccampanero Sep 18 '20 at 19:44
  • @timur I updated the answer again to reflect your contribution. – jccampanero Sep 18 '20 at 19:53
  • Thank you so much, @jccampanero. I have not had a chance to try this yet, but the bounty time was running out soon (I wish it gave more time), so I wanted to award the bounty before it expired. Once I have confirmed that this resolved it, I will also accept the answer. – Mike Williamson Sep 22 '20 at 07:22
  • Thank you very much Mike. I hope the answer will help you solve your problem. Please, feel free to continue posting on the thread if you think I can be of any help, I'll be happy to help you as much as I can. – jccampanero Sep 22 '20 at 08:23
1

We face these issues on the front end side when deploying an application using Docker in remote machines, even though the back end works fine, the front end returns CORS issues. To fix this, we allow the following headers in the response

"Content-Type": "application/json"
"Access-Control-Allow-Origin": "*"
"Access-Control-Allow-Methods": 'POST, GET, PUT, DELETE, OPTIONS'
"Access-Control-Allow-Headers": "Access-Control-Allow-Origin,Authorization, "Access-Control-Allow-Methods,"Content-Type"
Mehdi Khlifi
  • 405
  • 8
  • 21
0

Using multi container in Azure WebApp currently doesn't support CORS. And as others have mentioned, you can only expose one container to the outside world (only port 80/8080 is supported).

From the Azure Documentation:

Preview limitations

Multi-container is currently in preview. The following App Service platform features are not supported:

  • Authentication / Authorization
  • Managed Identities
  • CORS
  • VNET integration is not supported for Docker Compose scenarios
  • Docker Compose on Azure App Services currently has a limit of 4,000 characters at this time.
adiesner
  • 676
  • 9
  • 11