This is a clean rewrite of a stack that I've evolved over the past 2 years. It is also my entry to the Bunnyshell hackathon, all components used here have free-to-use licenses.
This stack is designed for dynamic real-time web apps with mobile clients. Backend changes can be directly sent to clients using a live WebSocket connection, state in the client is managed with Redux. This allows automatically updating all affected clients on any backend changes.
For the web-application setting, the Django backend dynamically requests Next.js pages, this includes dynamic page data so we get full SSR for all pages.
The Next.js frontend is integrated with Capacitor and directly exports to Android and iOS. In a native setting, the frontend will try to request user data from the backend, if it fails it can fallback to a cached version allowing the user to view the full state of the app in an 'offline' mode.
-
Next.js + React frontend (deployment)
- Tailwind CSS + DaisyUI
- Automatic platform adjustments for API calls, authentication, and native functions (my custom implementation)
- Global Redis store + auto background update WebSocket
- Capacitor setup for native integrations and iOS / Android PWA export
-
Django backend (deployment)
- Celery for task management (or for offloading time-intensive tasks)
- Django REST Framework + django_rest_dataclasses for rapid REST API development
- Django proxy for authenticating views on other pods like the docs
- DRF Spectacular for auto-generated API documentation
- Django Channels for managing WebSockets and sending updates to clients
-
Documentation (deployment)
- pdoc3 code documentation generated from backend code
-
PostgreSQL (helm chart)
- Main backend database
-
Redis (helm chart)
- Broker for Celery
- Database for Django Channels
As this repo uses Helm charts, you will need either a Bunnyshell business account or a private cluster to connect to your Bunnyshell account.
There are two templates here:
tims-stack-django-nextjs
: The stack shown in the demo video, automatically rebuilds backend and frontend images and manages the ingress for your personal domain.tims-stack-django-nextjs-static
: Same stack as above but uses pre-built images and uses ingress annotationbns-ingress
There is not static template. but even better there is a compose template now, this can be deployed completely on the bunnyshell cluster, check it here: ``
As AWS Kubernetes or Google Cloud Kubernetes servers are quite expensive, I prefer to set up a small private cluster running on a 15 euro / mo VPS. Using the right provider, this is more than sufficient to run multiple development servers or even a low-traffic production deployment.
The Helm chart ingress is configured to expose the kubectl API server at k8s.<your-domain>
; we will use this route and given credentials to set up our cluster integration in Bunnyshell.
- Install Microk8s on the server.
- Open the port to the kubeapi server and set up DNS records
<your-domain> -> server IP
andk8s.<your-domain> -> server IP
. - View Microk8s client config and copy values to configure Bunnyshell cluster.
- Configure required storage classes (I've not completed this step) the following is a comment from the Bunnyshell support on what you'd need to set up for the cluster to be fully compatible.
TODO: Insert comment
- Install cluster issuer and configure ingress to kubeapi server:
microk8s kubectl apply -f configs/ingress.yaml
(this is used by this chart to connect a host URL set by yourself). Also, configure a wildcard DNS record*.<your-host>
so that later exposed services can be routed to.
NOTE: I have not yet managed to correctly set up MetalLB to issue public IP addresses, but with the right configuration, it should be possible to also make this work with the regular bunnyshell-env.com URLs.
This section outlines manual usage; for usage with Bunnyshell.com, check the section above.
For full local development, you have the choice between running the full stack within Microk8s
locally or using Docker
and the Makefile
to run individual components.
This is harder to debug but allows testing microservice interactions
This will spin up the stack configured for local development (helm/values.yaml
); this is configured to mount directories back/
and front/
directly into the respective containers, so you will have hot code reloading!
- Set up
Microk8s
:make microk8s_setup
- Build images and push them to the local Microk8s registry:
make full_build_deploy
- Install the Helm chart:
make helm_install
(or usemake helm_update
to update an existing chart installation)
You can switch Microk8s off when you're finished with development:
microk8s stop
This is the simplest way to develop and debug but has some differences in local routing strategies
This setup also mounts front/
and back/
directories. It configures the host route host.docker.internal:host-gateway
so that containers can interact with each other.
- Build all images:
make full_build
- Start all containers:
make start_all
(or start individual onesmake frontend_run
,make backend_run
,make start_redis
)
You can configure any container registry by updating Makefile
and helm/values.yaml
. I currently like using the GitHub container registry; the Helm chart is set up to authorize pulling images from a GitHub container registry.
You can build all production images without any of the production secrets; they are only required for the deployed containers. To build all production images, use make full_build_prod
(TODO).
Add your subdomain to the DNS records of Microk8s /var/snap/microk8s/current/certs/csr.conf.template
Now you need to authorize your Docker installation to push to your private registry; with the GitHub container registry, you can use make authorize_github_push gha_token=<your-token>
.
Now you can push the built production images make push_prod
.
For deployment, create a copy of helm/values.yaml -> heml/production-values.yaml
, then choose secure usernames and passwords for all the services. Now you can install the Helm chart on your cluster.
This project is licensed under the Apache License, Version 2.0 (the "License"). You may not use these files except in compliance with the License. A copy of the License is included in the "LICENSE" file of this repository or you can also obtain a copy at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
Tim Schupp (@tbscode) is the author of all other code as marked in the NOTICE section. Attribution is always welcome but not required.
Special custom code written by me (@tbscode), all (Apache 2.0 see LICENSE section):
helm/*
Helm chart for deploying all services, flags configured for deploying only parts of the servicesMakefile
build and development scripts.github/workflows/*
GitHub Actions for building and pushing container imagesfront/pages/_app.js
based on mobile layout detector & global state managerfront/utils/tools.tsx
Capacitor-based environment switch and tools for handling streaming requests to Next.js pagesfront/components/connection-banner.jsx
Automatic Capacitor-based platform detector, manages fetching user_data or falling back to cached user data for offline usageback/core/api/user_data.py
Example API handling core user-databack/core/consumer.py
Simple Django Channels consumer to handle client callbacks and update actionsconfig/*
Kubernetes configs for preparing private Microk8s cluster + Bunnyshell setupDockerfile.*
Dockerfiles for building all services; builds differ in dev (_dev
) vs prod
These are the main custom components; other things are just general configs/settings and some scripts.
Backend libraries (back/requirements.txt
):
django-cors-headers
: MIT LicensePython Markdown
:BSD-style
django-filter
: Modified BSDDjango
: BSD 3-Clausedjango-channels
: BSD 3-Clausedjango-channels-redis
: BSD 3-clausecelery
: BSD 3-clausedjango-celery-results
: BSD 3-clausedjango-celery-beat
: BSD 3-clausedjangorestframework
: BSD 3-clausedjangorestframework-dataclasses
: BSD 3-Clausedrf-spectacular
: BSD 3-Clausedjango_nextjs
: MITopenai
: MITipython
: BSD 3-Clausedjango-jazzmin
: MIT- (AWS PostgreSQL DB only)
psycopg2-binary
: LGPL uvicorn
: BSD 3-clausewhitenoise
: MITjinja2
: BSD 3-clause
Frontend libraries (front/package.json
):
next.js
: MITcapacitor
: MIT- Capacitor plugins:
preferences (MIT)
react
: MITreact-dom
: MIT (part of React)daisyui
: MITeslint
: MITeslint-config-next
: MIT (part of Next.js)postcss
: MITtailwindcss
: MITtypescript
: Apache 2.0
Development dependencies:
Runtime dependencies: