Get hands-on experience with 20+ free Google Cloud products and $300 in free credit for new customers.

I can't deploy Django API+React+Django admin projects in one Google Cloud Run service

I wan to deploy the Django API+React+Django admin in one Google cloud run service with multiple containers, but when I do that, the django api and react frontend works ok, but I can not open django admin platform. 

 

First I will introduce my project structure:

Frontend: React+ViteJS

Backend: Django-ninja for the api stuff

Admin Platform: Django original admin framework

Custom Domain: Google Firebase host (integrate with google cloud run), for example: the website is (URL Removed by Staff)

Right now I use the Google Cloud Run multicontainer service to deploy the whole project.

For the frontend docker Dockerfile:

FROM node:20-slim as build

WORKDIR /app

COPY package*.json ./

RUN npm install
COPY . .
RUN npm run build

# Use Nginx as the production server
FROM nginx:alpine

COPY nginx.conf /etc/nginx/conf.d/default.conf

# Copy the built React app to Nginx's web server directory
COPY --from=build /app/dist /usr/share/nginx/html

# Expose port 80 for the Nginx server
EXPOSE 8000

# Start Nginx when the container runs
CMD ["nginx", "-g", "daemon off;"]

This is the nginx.conf:

server {
    listen       8000;
    # listen  [::]:80;
    # server_name  localhost;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
        try_files $uri $uri/ /index.html;
    }

    location /api/ {
        proxy_pass http://localhost:8080;
        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;
    }

    location /admin/ {
        proxy_pass http://localhost:8080;
        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;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

For the backend Dockerfile:

FROM python:3.11-buster
RUN apt-get update && apt-get install -y cmake
RUN pip install poetry==1.8.2
ENV POETRY_NO_INTERACTION=1 \
    POETRY_VIRTUALENVS_IN_PROJECT=1 \
    POETRY_VIRTUALENVS_CREATE=1 \
    POETRY_CACHE_DIR=/tmp/poetry_cache

ENV PORT 8080

WORKDIR /app
COPY . .
RUN poetry install --no-root

EXPOSE 8080

CMD poetry run gunicorn mysite.wsgi:application --bind :$PORT --timeout 1000 --workers 1 --threads 8

For the django-ninja settings, the important part is here:(just follow the google tutorial)

# env setup
env = environ.Env(DEBUG=(bool, False))
env_file = os.path.join(BASE_DIR, ".env")
# Attempt to load the Project ID into the environment, safely failing on error.
try:
    _, os.environ["GOOGLE_CLOUD_PROJECT"] = google.auth.default()
except google.auth.exceptions.DefaultCredentialsError:
    pass

if os.path.isfile(env_file):
    # Use a local secret file, if provided in local
    env.read_env(env_file)
elif os.environ.get("GOOGLE_CLOUD_PROJECT", None):
    # Pull secrets from Secret Manager
    project_id = os.environ.get("GOOGLE_CLOUD_PROJECT")

    client = secretmanager.SecretManagerServiceClient()
    settings_name = os.environ.get("SETTINGS_NAME", "ps_plugin_settings")
    name = f"projects/{project_id}/secrets/{settings_name}/versions/latest"
    payload = client.access_secret_version(name=name).payload.data.decode("UTF-8")
    env.read_env(io.StringIO(payload))
else:
    raise Exception("No local .env or GOOGLE_CLOUD_PROJECT detected. No secrets found.")


SECRET_KEY = env("SECRET_KEY")
BASE_API_URL = env("BASE_API_URL")
BASE_APP_URL = env("BASE_APP_URL")
GOOGLE_OAUTH2_CLIENT_ID = env("GOOGLE_OAUTH2_CLIENT_ID")
GOOGLE_OAUTH2_CLIENT_SECRET = env("GOOGLE_OAUTH2_CLIENT_SECRET")

DEBUG = env("DEBUG")

# [START cloudrun_django_csrf]
# SECURITY WARNING: It's recommended that you use this when
# running in production. The URL will be known once you first deploy
# to Cloud Run. This code takes the URL and converts it to both these settings formats.
CLOUDRUN_SERVICE_URL = env("CLOUDRUN_SERVICE_URL", default=None)
if CLOUDRUN_SERVICE_URL:
    ALLOWED_HOSTS = [
        urlparse(CLOUDRUN_SERVICE_URL).netloc,
        urlparse(BASE_API_URL).netloc,
        urlparse(BASE_APP_URL).netloc,
    ]
    CSRF_TRUSTED_ORIGINS = [CLOUDRUN_SERVICE_URL, BASE_API_URL, BASE_APP_URL]
    SECURE_SSL_REDIRECT = True
    SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")

    # for the custom domain cookie and session in order to login successfully
    # CSRF_COOKIE_DOMAIN = urlparse(BASE_APP_URL).netloc
    # SESSION_COOKIE_DOMAIN = urlparse(BASE_APP_URL).netloc
else:
    ALLOWED_HOSTS = ["*"]
# [END cloudrun_django_csrf]

Besides I also setup the google cloud storage, and execute the collectstatic command. So the admin platform static files have been already in the google storage for the public.

After these 2 containers were deployed, I found that the frontend and backend works find, I can open the website (URL Removed by Staff) works well.

But the django admin platform does not work, when I open (URL Removed by Staff), I can not open it. But I have already set the proxy for /admin router in the Nginx.

I also tried another thing, I deploy a totally new google cloud run service, it is just one container, just deploy the django project, no frontend, no nginx, now I can open the django admin platform with the cloud run website, like (URL Removed by Staff), but if I open the custom firebase domain, like (URL Removed by Staff), after I input the right username and password, it redirect the login page again. 🤣 I have already add the (URL Removed by Staff) into the CSRF_TRUSTED_ORIGINS

Someone help me, please.

0 0 414
0 REPLIES 0
Top Labels in this Space
Top Solution Authors