diff --git a/.editorconfig b/.editorconfig index 5629222..a5dd553 100644 --- a/.editorconfig +++ b/.editorconfig @@ -9,7 +9,7 @@ trim_trailing_whitespace = true indent_style = space indent_size = 2 -[{Dockerfile,Makefile,*.Makefile,go.mod,go.sum,*.go,.gitmodules}] +[{Dockerfile,Caddyfile,Makefile,*.Makefile,go.mod,go.sum,*.go,.gitmodules}] indent_style = tab indent_size = 4 diff --git a/.env b/.env index 48a8704..b7a411b 100644 --- a/.env +++ b/.env @@ -4,9 +4,9 @@ POSTGRES_DB=django_db POSTGRES_HOST=postgres POSTGRES_PORT=5432 +GUNICORN_PORT=8000 GUNICORN_WORKERS=2 -# the value is in seconds -GUNICORN_TIMEOUT=60 +GUNICORN_TIMEOUT=60 # the value is in seconds GUNICORN_LOG_LEVEL=info # DJANGO_SECRET_KEY= diff --git a/Caddyfile b/Caddyfile new file mode 100644 index 0000000..a8b1927 --- /dev/null +++ b/Caddyfile @@ -0,0 +1,16 @@ +{$MY_DOMAIN} { + + handle_path /static/* { + root * /usr/share/caddy/static + file_server + } + + handle_path /media/* { + root * /usr/share/caddy/media + file_server + } + + handle { + reverse_proxy django:{$GUNICORN_PORT} + } +} diff --git a/README.md b/README.md index cf83095..b6ccb29 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ The technology stack used includes: - [`PostgreSQL`](https://www.postgresql.org) ver. 15 - [`Gunicorn`](https://gunicorn.org) ver. 21.2 - [`Traefik`](https://traefik.io/traefik/) ver. 2.9 +- [`Caddy`](https://caddyserver.com) ver. 2.7 - [`Docker`](https://docs.docker.com/get-docker/) and [`Docker Compose`](https://docs.docker.com/compose/) Nothing extra, only the essentials! You can easily add everything else yourself by expanding the existing configuration files: @@ -32,7 +33,7 @@ So, what do you get by using this project as a template for your project? Let's - A well-configured Django project, with individual settings that can be changed using environment variables - Building and debugging a Django project in Docker - Integrated [pytest](https://docs.pytest.org) and [coverage](https://coverage.readthedocs.io) for robust testing and code quality assurance ✅ -- A ready-made docker-compose file that brings together Postgres - Django - Gunicorn - Traefik +- A ready-made docker-compose file that brings together Postgres - Django - Gunicorn - Traefik (or Caddy) - Serving static files (and user-uploaded files) with Nginx - Automatic database migration and static file collection when starting or restarting the Django container - Automatic creation of the first user in Django with a default login and password @@ -192,6 +193,27 @@ docker compose exec django python manage.py check --deploy docker compose exec django python manage.py shell ``` +### Using Caddy Server Instead of Traefik + +Traefik is a great edge router, but it doesn't serve static files, which is why we pair it with [Nginx](https://github.com/amerkurev/django-docker-template/blob/master/docker-compose.yml#L26) in our setup. If you prefer a single tool that can handle everything, you might want to try [Caddy](https://caddyserver.com). + +Caddy can automatically handle the creation and renewal of Let's Encrypt certificates and also serve static files, which allows you to use just one server instead of two. + +Here's how to set up Caddy with your project: + +1. Ensure you have a [`Caddyfile`](Caddyfile) in your project directory. This file will tell Caddy how to deliver static and media files and how to forward other requests to your Django app. + +2. Swap out the `docker-compose.yml` and `docker-compose.tls.yml` with a single [`docker-compose.caddy.yml`](docker-compose.caddy.yml). This file is designed to set up Caddy with Django and Postgres, and it doesn't include Nginx, which makes the file shorter and easier to understand. + +3. To get your Django project up with Caddy, run the following command, making sure to replace `your.domain.com` with your actual domain: + +```console +MY_DOMAIN=your.domain.com docker compose -f docker-compose.caddy.yml up -d +``` + +Choosing Caddy simplifies your setup by combining the functionalities of Traefik and Nginx into one. It's straightforward and takes care of HTTPS certificates for you automatically. +Enjoy the ease of deployment with Caddy! + ## What's next? Now that you have a working project, you can extend it as you like, adding [dashboards for monitoring service health](https://doc.traefik.io/traefik/operations/dashboard/), [centralized log collection](https://www.fluentd.org), [secret storage](https://www.vaultproject.io), and of course, your own Django applications. All of this is beyond the scope of the current description, as the idea of this project is minimalism and providing only the essentials. Good luck! diff --git a/docker-compose.caddy.yml b/docker-compose.caddy.yml new file mode 100644 index 0000000..67b8ff6 --- /dev/null +++ b/docker-compose.caddy.yml @@ -0,0 +1,58 @@ +version: "3.9" +services: + postgres: + image: postgres:15 + env_file: .env + restart: unless-stopped + volumes: + - "postgres-data:/var/lib/postgresql/data/" + + django: + build: . + image: django-docker + env_file: .env + environment: + - "DJANGO_ALLOWED_HOSTS=${MY_DOMAIN}" + - "DJANGO_CSRF_TRUSTED_ORIGINS=https://${MY_DOMAIN}" + - "DJANGO_SESSION_COOKIE_SECURE=true" + - "DJANGO_CSRF_COOKIE_SECURE=true" + - "DJANGO_SECURE_SSL_REDIRECT=true" + restart: unless-stopped + volumes: + - "staticfiles-data:/var/www/static" + - "media-data:/var/www/media" + depends_on: + - postgres + + caddy: + image: caddy:2.7-alpine + env_file: .env + environment: + - "MY_DOMAIN=${MY_DOMAIN}" + restart: unless-stopped + ports: + - "80:80" + - "443:443" + volumes: + - "./Caddyfile:/etc/caddy/Caddyfile:ro" + - "caddy-data:/data" + - "caddy-config:/config" + - type: volume + source: media-data + target: /usr/share/caddy/media + read_only: true + volume: + nocopy: true + - type: volume + source: staticfiles-data + target: /usr/share/caddy/static + read_only: true + volume: + nocopy: true + +volumes: + caddy-data: + caddy-config: + media-data: + postgres-data: + staticfiles-data: diff --git a/docker-compose.debug.yml b/docker-compose.debug.yml index 989aec3..c0b4487 100644 --- a/docker-compose.debug.yml +++ b/docker-compose.debug.yml @@ -17,7 +17,7 @@ services: command: ["/docker-cmd.sh", "--debug"] volumes: - "media-data:/var/www/media" - - "./website:/usr/src/website" # mount the source code + - "./website:/usr/src/website" # mount the source code for watching changes depends_on: - postgres labels: diff --git a/website/polls/admin.py b/website/polls/admin.py index 603d1b1..2b7565a 100644 --- a/website/polls/admin.py +++ b/website/polls/admin.py @@ -12,7 +12,7 @@ class QuestionAdmin(admin.ModelAdmin): fieldsets = [ (None, {'fields': ['question_text']}), ('Date information', {'fields': ['pub_date'], 'classes': ['expand']}), - ('Files', {'fields': ['upload'], 'classes': ['collapse']}), + ('Files', {'fields': ['upload'], 'classes': ['expand']}), ] inlines = [ChoiceInline]