Anteru's blog
  • Consulting
  • Research
    • Assisted environment probe placement
    • Assisted texture assignment
    • Edge-Friend: Fast and Deterministic Catmull-Clark Subdivision Surfaces
    • Error Metrics for Smart Image Refinement
    • High-Quality Shadows for Streaming Terrain Rendering
    • Hybrid Sample-based Surface Rendering
    • Interactive rendering of Giga-Particle Fluid Simulations
    • Quantitative Analysis of Voxel Raytracing Acceleration Structures
    • Real-time Hybrid Hair Rendering
    • Real-Time Procedural Generation with GPU Work Graphs
    • Scalable rendering for very large meshes
    • Spatiotemporal Variance-Guided Filtering for Motion Blur
    • Subpixel Reconstruction Antialiasing
    • Tiled light trees
    • Towards Practical Meshlet Compression
  • About
  • Archive

Angular, Caddy, Gunicorn and Django

October 21, 2023
  • Programming
approximately 2 minutes to read

This took me way more time than I anticipated, so here’s the summary in case any of you (or future me) runs into the same situation. The stage: I have a Django application which provides a GraphQL endpoint, and an Angular frontend using it. Everything is hosted via Caddy, and Django is served through Gunicorn. So far so good. Now, I was using Django (via some plugins) to serve the Angular web application, so the typical request would be:

  • Caddy gets the requests and forwards it to Gunicorn
  • Gunicorn invokes Django
  • Django reads the static file and serves it

All of this mostly because I was too lazy to set this up correctly; Django has a static files module which seemed like it could do the trick, and it somewhat works, but the correct way to do this is as following:

  • Caddy serves all static files

  • If the path is /static/*, it serves from the Django STATIC_ROOT

  • Otherwise, if the file exists, it serves from the Angular root

  • If the path is unknown, it redirects it to the Angular root (as we assume this is an Angular route)

How do we achieve that? It’s actually not that complicated. On the Django side, there’s nothing to do really. Just set the STATIC_ROOT and remember what you set it to. Now comes the Caddyfile:

my.host.url {
        tls /srv/certs/caddy/cert.crt /srv/certs/caddy/cert.key

        @angular {
                not path /graphql
                not path /admin/*
                not path /account/*
        }

        handle_path /static/* {
                root * /srv/app/django/static
                file_server
        }

        handle {
                reverse_proxy unix//run/gunicorn.sock
        }

        handle @angular {
                root * /srv/app/angular
                try_files {path} {path}/ /index.html
                file_server
        }
}

What this does is:

  • Defines a named matcher to exclude all paths that should be handled by Angular (@angular) – this matches the paths that should not go to Django
  • Sends all /static/* requests to a file server (note: You can configure that path in case it conflicts with your Angular app via STATIC_URL)
  • Connects Caddy to Gunicorn/Django – everything that is not handled by Caddy will go here. This is important so we can run the admin console.
  • Sends the remaining requests to Angular: try_files tries to serve a local file, and if that fails, it will serve index.html

Voilà, that’s it. It’s easier if you don’t care about the Django admin page and so on, but in my case, I do want to keep the ability to open that. With this configuration, you get the optimal performance serving any static file (as both the Django and Angular static files get served by Caddy), while retaining all the usual Django goodness, without any additional build time complexity.

Previous post
Next post

Recent posts

  • Data formats: Why CSV and JSON aren't the best
    Posted on 2024-12-29
  • Replacing cron with systemd-timers
    Posted on 2024-04-21
  • Open Source Maintenance
    Posted on 2024-04-02
  • Angular, Caddy, Gunicorn and Django
    Posted on 2023-10-21
  • Effective meetings
    Posted on 2022-09-12
  • Older posts

Find me on the web

  • GitHub
  • GPU database
  • Projects

Follow me

Anteru NIV_Anteru
Contents © 2005-2025
Anteru
Imprint/Impressum
Privacy policy/Datenschutz
Made with Liara
Last updated October 21, 2023