Quasar in the front, Django in the back.
Blended to perfection and served up in your containers.
- Fast Development ⚡ Live Reloading environment with a single
docker-compose up
- Easy Deployment 📦 Package your project for Production into a single
.tar.gz
git clone https://github.com/GreenRefuge/quango-smoothie.git
cd quango-smoothie
Container images will be built on-demand (depending on the commands run below)
docker-compose -f dev.yml up
The application can be accessed at https://127.0.0.1
- Django Dev Environment
DEBUG=True
is enabled insettings.py
collectstatic
command is run before server start
- Live/Hot Reloading
- the Quasar server will watch for file changes under
./mount/quasar_app/quango_frontend
- the Django server will watch for file changes under
./mount/django_app/quango_backend
- ℹ️ changes to settings-related things (e.g.
quasar.conf.js
orsettings.py
) will possibly require a restart of the container - ℹ️ changes to package-related things (e.g.
package.json
orrequirements.txt
) will likely require a rebuild of the container image - ℹ️ changes to Django static files will requre a re-run of
collectstatic
command
- the Quasar server will watch for file changes under
ℹ️ This step is only necessary if you have never run the Development containers, or static files changed since the last run
docker-compose -f dev.yml run --rm django_app /bin/bash -c ". ~/venv_django/bin/activate && cd /home/user/app_src/quango_backend && python manage.py collectstatic --noinput"
- The static files will now be located in the
django_staticfiles
Docker named volume
docker-compose -f dev.yml run --rm quasar_app /bin/bash -c "cd app_src/quango_frontend && npx quasar build"
- The build artifacts will now be located in the
quasar_dist
Docker named volume
docker-compose -f prod.yml up
- This will start the Production containers in your local environment
- The application can be accessed at
https://127.0.0.1
- ℹ️ make sure to provide your own config/secrets in
./config/prod
- you can just copy all the files under
./config/dev
if you want to mirror the Development config/secrets - these will not be included by "pack" script (see Step 3) and are ignored by
.gitignore
- you can just copy all the files under
⚠️ avoid doing this while Development containers are running! (volumes/ports are shared across environments)
This will create a minimal archive for easy deployment:
- Production-related files are isolated, static files are extracted, and final config tweaks are applied
- (this default project compresses down to
1.2 MB
💾)
docker-compose -f deploy.yml run --rm deploy_app
- The generated
prod_[TIMESTAMP].tar.gz
file will now be located in./mount/deploy_app
- Move and extract
prod_[TIMESTAMP].tar.gz
to somewhere on your Production server- 🔑 IMPORTANT you must provide your own config/secrets
- these will be
.txt
files under./config/prod
- use
./config/dev
as a reference (just copy each file, replacing the contents with your own config)
- these will be
- 🔑 IMPORTANT you must provide your own config/secrets
docker-compose build
docker-compose up
- things under the
./build
directory are used during container image build(s) only - things under the
./mount
directory are mounted within the container(s) during runtime - things under the
./config
directory are Docker Secrets, distinguished bydev
andprod
subdirectories - on first run, Django creates a file
db.sqlite3
in the (host-mounted)./mount/databases
directory - on each (Development) run, a symbolic link
node_modules
is created in the (host-mounted)./mount/quasar_app/quango_frontend
directory - on running "pack" script, the Production archive is created in the (host-mounted)
./mount/deploy_app
directory
./mount/django_app/quango_backend
is:- a minimal Django app created with the
django-admin startproject
command (uses the defaultSQLite
for storage)
- a minimal Django app created with the
./mount/quasar_app/quango_frontend
is:- a minimal Quasar app created with the
quasar create
command (base installation)
- a minimal Quasar app created with the
- Both apps operate independently
- The files generated by
quasar build
are served at the site root (i.e./
) - All other routes are covered by Django (i.e. Django's static files, the
/admin
routes, and routes fromurls.py
)
NGINX is used as a reverse proxy in both Development and Production environments in order to:
- provide central point for SSL termination (HTTPS)
- serve static files (Django static files and Quasar build artifacts)
- facilitate environment-dependent routing
NGINX matches URLs according to the following rules:
- anything under
/static/
will be served from Django static files directory- errors for missing static files/routes are handled by NGINX directly (Django server is bypassed)
⚠️ as you extend your Quasar project make sure it does not emit a directory/static
, or else path conflict here
- all other routes are handled as follows:
- the Quasar dist directory is searched, file is returned if a match
- when in Development mode, this request is passed to the Quasar dev server
- if no match, the route is finally passed to the
@fallback
location (i.e. Django server)
- the Quasar dist directory is searched, file is returned if a match
- when the NGINX image is built, a self-signed certificate is generated in order to facilitate HTTPS handling
- in Production, you will probably want to use a "real" certificate (e.g. via Caddy and/or Let's Encrypt)
- by default, nothing is done to redirect clients from HTTP to HTTPS (both protocols are served)
⚠️ if a client switches between protocols, may cause unexpected issues in browser (e.g. with protocol-dependent Cookies or Local Storage or remote resources)
- Django has a setting
SECURE_SSL_REDIRECT
to address this (see commented-out line insettings.py
)- (however, probably should handle redirect at NGINX layer only for better predictability)
- NGINX could be configured to handle the redirection (as described here)
- this would ensure all static assets are properly redirected in addition to Django routes
- Uvicorn is used to serve the Django project within its container
- the server is bound to a Unix domain socket, which is exposed to the NGINX container via shared volume
- in Production mode, Gunicorn is used to "drive" Uvicorn (as is recommended by the docs)