2

I have a dockerised Django app where nginx uses proxy_pass to send requests to the Django backend. I am looking to pre-publish certain pages that dont change often so Django doesnt have to deal with them.

I am trying to use try_files to check if that page exists locally and pass to Django if not.

Our URL structure requires that all URLs end with a forward slash and we dont use file type suffixes e.g. a page might be www.example.com/hello/. This means the $uri param in nginx in this instance is /hello/ and when try_files looks at that it is expecting a directory due to the trailing slash. If I have a directory with a list of files how do I get try_files to look at them without re-writing the URL to remove the slash as Django requires it?

My nginx conf is below.

server {
    listen 443 ssl http2 default_server;
    listen [::]:443 ssl http2 default_server;
    server_name example.com;

    root /home/testuser/example;

    location / {
        try_files $uri uri/ @site_root;
    }

    location @site_root {
       proxy_pass         http://127.0.0.1:12345;
    }
}

If I have a file "hello" at /home/testuser/example/hello and call https://www.example.com/hello/ how can I get it to load the file correctly?

P.S. the permissions on the static content folder and its contents are all 777 (for now to rule out permissions issues)

Cheers in advance!

5
  • Try using django cache instead. It can cache whole pages. Commented Mar 8, 2020 at 18:53
  • By default Nginx will try to return /home/testuser/example/hello/index.html. Commented Mar 8, 2020 at 19:06
  • @IvanStarostin I use the django cache atm, its too slow at scale though, requires a hit to redis and after 10k reqs per sec or so redis doesnt like that while nginx doesnt break a sweat Commented Mar 8, 2020 at 19:52
  • @RichardSmith Yeah thats the problem, how to I get it to just return "hello" or "hello.html" (as long as URL can still just be "/hello/" Commented Mar 8, 2020 at 19:52
  • There is a memcached plugin for Nginx which makes possible this scenario: Nginx tries to hit memcached, if key is missing it goes to Django, which generates the page, returns it as a response and stores into memcached cache; on next URL hit Nginx will obtain page from memcached and will not invoke Django. Commented Mar 9, 2020 at 12:26

2 Answers 2

3

You can point the URI /hello/ to a local file called hello or hello.html using try_files, but you must first extract the filename using a regular expression location. See this document for details.

The advantage of using .html is that you will not need to provide the Content-Type of the response.

For example, using hello.html:

root /path/to/root;

location / {
    try_files $uri uri/ @site_root;
}
location ~ ^(?<filename>/.+)/$ {
    try_files $filename.html @site_root;
}
location @site_root {
   proxy_pass  ...;
}

If you prefer to store the local files without an extension, and they are all text/html, you will need to provide the Content-Type. See this document for details.

For example, using hello:

root /path/to/root;

location / {
    try_files $uri uri/ @site_root;
}
location ~ ^(?<filename>/.+)/$ {
    default_type text/html;
    try_files $filename @site_root;
}
location @site_root {
   proxy_pass  ...;
}
Sign up to request clarification or add additional context in comments.

3 Comments

Amazing! That works, thanks! Was bashing my head against this for hours!
r.smith for president! Thanks a lot, you save my day!
Thanks Richard! It works great! I replaced @site_root in the try_files with /404.html to have an easy "page not found" setup.
0

In my case using NextJS, leaving the final slash causes errors.

So here is the solution I found to make it work nicely:

root /path/to/static/files/directory; # no trailing slash
rewrite ^/(.*)/$ /$1 permanent; # automatically remove the trailing slash

location / {
  try_files $uri $uri.html $uri/index.html /404.html;
  # try the provided uri
  # then try adding .html
  # then try uri/index.html (ex: homepage)
  # finally serve the 404 page
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.