'Not able to find static file with GCP app engine

I am trying to deploy a flask app with bootstrap and Jinja2 on GCP app engine. I have a css file for custom style of bootstrap template. The deployment was succeeded and the app worked fine except this custom.css, which I get a 404 error from app engine dashboard.

It works fine locally, so I am guessing there is something wrong with my app.yaml configuration.

My project directory structure is like this:

app
|
|-static
|   |-custom.css
|
|-templates
|   |-base.html
|
|  __init__.py
|  auth.py
|  functions.py
|  main.py
|  app.yaml
|  requirements.txt


app.yaml

runtime: python39
entrypoint: gunicorn -b :$PORT main:app

handlers:
  - url: /static
    static_dir: public

  - url: /.*
    secure: always
    redirect_http_response_code: 301
    script: auto

base.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link
      rel="stylesheet"
      href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
      integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh"
      crossorigin="anonymous"
    />
    <link
      rel="stylesheet"
      href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"
      crossorigin="anonymous"
    />
    <link
      rel="stylesheet"
      type="text/css"
      href="/static/custom.css"
    />
  </head>

I am quite new to GCP and also unfamiliar with yaml, any help or suggestion will be appreciated.

Edit: Sorry I forgot to mentioned that I tried following approach and didn't work as well:

handlers:
  - url: /static
    static_dir: static


Solution 1:[1]

You don't have a folder called public and python3 doesn't have that concept but your app.yaml is referring to a public folder.

In app.yaml, make the change for your static handler to

    - url: /static
    static_dir: static

Extra Information:

  1. Your local environment is not always an exact replica of GAE Production. It is at best a simulation. So don't always assume what works in local will work in production.

  2. Bullet 1 is especially important if you are not running your local environment with dev_appserver.py command. For example, if you test on your local environment using the command - python run XXXX, flask run XXX, then you are not using a GAE Simulated environment and thus are not using app.yaml

Solution 2:[2]

The issue is with the mismatch of the folder names in your app.yaml:

handlers:
  - url: /static
    static_dir: public

What you're doing here is pointing the external /static path to the internal public path. Since the path public doesn't exist in your app, it will return a 404 not found error.

Change the static_dir value to static and it will work...

These docs are not exactly clear on this, but the docs for app.yaml explain it nicely (see the section about static_dir)

EDIT after comments

So I did some testing to be sure, see below for files used. I changed the local folder name to not_static to make sure that the /.* url handler in my app.yaml didn't actually trigger. Deploying this and looking at the website, I can see the style.css being correctly loaded. (I know I''m not using it, this was just testing. The HTML is the literal hello world from w3schools...)

As you can see in the screenshot, the style.css is downloaded correctly. style.css

The issue might be with caching, as that can be fun at times. But it should work...

my file structure

/not_static
  ?> style.css
app.yaml
requirements.txt
main.py

app.yaml

runtime: python39
service: testing123

instance_class: F1
entrypoint: gunicorn -b :$PORT main:app

automatic_scaling:
  max_instances: 1

handlers:
- url: /static
  static_dir: not_static
- url: /.*
  secure: always
  redirect_http_response_code: 301
  script: auto

main.py

from flask import Flask

app = Flask(__name__)


@app.route("/")
def hello_world():
    return """
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="static/style.css">
</head>
<body>

<h1>This is a heading</h1>
<p>This is a paragraph.</p>

</body>
</html>
"""

requirements.txt

flask
gunicorn

/not_static/style.css

@import url("https://fonts.googleapis.com/css2?family=Aclonica&family=Comfortaa:wght@400;500;600;700&family=Electrolize&family=Goldman:wght@400;700&family=Varela+Round&display=swap&family=Ubuntu:wght@300&display=swap");


:root {
    --text-color: #333333;
    --background-color: #eaeaea;
  }
  
  body {
  background: var(--background-color);
  margin: 0;
  font-family: 'Ubuntu';
  color: var(--text-color);
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 NoCommandLine
Solution 2