diff --git a/CONTRIBUTORS.rst b/CONTRIBUTORS.rst index dc41463f..d8d312ab 100644 --- a/CONTRIBUTORS.rst +++ b/CONTRIBUTORS.rst @@ -93,6 +93,7 @@ Listed in alphabetical order. Davit Tovmasyan `@davitovmasyan`_ Davur Clementsen `@dsclementsen`_ @davur Delio Castillo `@jangeador`_ @jangeador + Demetris Stavrou `@demestav`_ Denis Orehovsky `@apirobot`_ Dónal Adams `@epileptic-fish`_ Diane Chen `@purplediane`_ @purplediane88 @@ -216,6 +217,7 @@ Listed in alphabetical order. .. _@Collederas: https://github.com/Collederas .. _@davitovmasyan: https://github.com/davitovmasyan .. _@ddiazpinto: https://github.com/ddiazpinto +.. _@demestav: https://github.com/demestav .. _@dezoito: https://github.com/dezoito .. _@dhepper: https://github.com/dhepper .. _@dot2dotseurat: https://github.com/dot2dotseurat diff --git a/README.rst b/README.rst index 37f36204..2c037e51 100644 --- a/README.rst +++ b/README.rst @@ -48,7 +48,7 @@ Features * Optional custom static build using Gulp and livereload * Send emails via Anymail_ (using Mailgun_ by default, but switchable) * Media storage using Amazon S3 -* Docker support using docker-compose_ for development and production (using Caddy_ with LetsEncrypt_ support) +* Docker support using docker-compose_ for development and production (using Traefik_ with LetsEncrypt_ support) * Procfile_ for deploying to Heroku * Instructions for deploying to PythonAnywhere_ * Run tests with unittest or py.test @@ -82,7 +82,7 @@ Optional Integrations .. _Sentry: https://sentry.io/welcome/ .. _docker-compose: https://github.com/docker/compose .. _PythonAnywhere: https://www.pythonanywhere.com/ -.. _Caddy: https://caddyserver.com/ +.. _Traefik: https://traefik.io/ .. _LetsEncrypt: https://letsencrypt.org/ Constraints diff --git a/docs/deployment-with-docker.rst b/docs/deployment-with-docker.rst index f6e21e82..904947e3 100644 --- a/docs/deployment-with-docker.rst +++ b/docs/deployment-with-docker.rst @@ -19,7 +19,7 @@ Before you begin, check out the ``production.yml`` file in the root of this proj * ``django``: your application running behind ``Gunicorn``; * ``postgres``: PostgreSQL database with the application's relational data; * ``redis``: Redis instance for caching; -* ``caddy``: Caddy web server with HTTPS on by default. +* ``traefik``: Traefik reverse proxy with HTTPS on by default. Provided you have opted for Celery (via setting ``use_celery`` to ``y``) there are three more services: @@ -63,11 +63,11 @@ It is always better to deploy a site behind HTTPS and will become crucial as the * Access to the Django admin is set up by default to require HTTPS in production or once *live*. -The Caddy web server used in the default configuration will get you a valid certificate from Lets Encrypt and update it automatically. All you need to do to enable this is to make sure that your DNS records are pointing to the server Caddy runs on. +The Traefik reverse proxy used in the default configuration will get you a valid certificate from Lets Encrypt and update it automatically. All you need to do to enable this is to make sure that your DNS records are pointing to the server Traefik runs on. -You can read more about this here at `Automatic HTTPS`_ in the Caddy docs. +You can read more about this feature and how to configure it, at `Automatic HTTPS`_ in the Traefik docs. -.. _Automatic HTTPS: https://caddyserver.com/docs/automatic-https +.. _Automatic HTTPS: https://docs.traefik.io/configuration/acme/ (Optional) Postgres Data Volume Modifications @@ -112,7 +112,7 @@ If you want to scale your application, run:: docker-compose -f production.yml scale django=4 docker-compose -f production.yml scale celeryworker=2 -.. warning:: don't try to scale ``postgres``, ``celerybeat``, or ``caddy``. +.. warning:: don't try to scale ``postgres``, ``celerybeat``, or ``traefik``. To see how your containers are doing run:: diff --git a/docs/developing-locally-docker.rst b/docs/developing-locally-docker.rst index 895140f9..10815419 100644 --- a/docs/developing-locally-docker.rst +++ b/docs/developing-locally-docker.rst @@ -105,7 +105,6 @@ The most important thing for us here now is ``env_file`` section enlisting ``./. │   ├── .django │   └── .postgres └── .production - ├── .caddy ├── .django └── .postgres @@ -120,7 +119,7 @@ Consider the aforementioned ``.envs/.local/.postgres``: :: POSTGRES_USER=XgOWtQtJecsAbaIyslwGvFvPawftNaqO POSTGRES_PASSWORD=jSljDz4whHuwO3aJIgVBrqEml5Ycbghorep4uVJ4xjDYQu0LfuTZdctj7y0YcCLu -The three envs we are presented with here are ``POSTGRES_DB``, ``POSTGRES_USER``, and ``POSTGRES_PASSWORD`` (by the way, their values have also been generated for you). You might have figured out already where these definitions will end up; it's all the same with ``django`` and ``caddy`` service container envs. +The three envs we are presented with here are ``POSTGRES_DB``, ``POSTGRES_USER``, and ``POSTGRES_PASSWORD`` (by the way, their values have also been generated for you). You might have figured out already where these definitions will end up; it's all the same with ``django`` service container envs. One final touch: should you ever need to merge ``.envs/production/*`` in a single ``.env`` run the ``merge_production_dotenvs_in_dotenv.py``: :: diff --git a/{{cookiecutter.project_slug}}/.envs/.production/.caddy b/{{cookiecutter.project_slug}}/.envs/.production/.caddy deleted file mode 100644 index 83d7fc7a..00000000 --- a/{{cookiecutter.project_slug}}/.envs/.production/.caddy +++ /dev/null @@ -1,3 +0,0 @@ -# Caddy -# ------------------------------------------------------------------------------ -DOMAIN_NAME={{ cookiecutter.domain_name }} diff --git a/{{cookiecutter.project_slug}}/compose/production/caddy/Caddyfile b/{{cookiecutter.project_slug}}/compose/production/caddy/Caddyfile deleted file mode 100644 index 323e4392..00000000 --- a/{{cookiecutter.project_slug}}/compose/production/caddy/Caddyfile +++ /dev/null @@ -1,15 +0,0 @@ -www.{% raw %}{$DOMAIN_NAME}{% endraw %} { - redir https://{% raw %}{$DOMAIN_NAME}{% endraw %} -} - -{% raw %}{$DOMAIN_NAME}{% endraw %} { - proxy / django:5000 { - header_upstream Host {host} - header_upstream X-Real-IP {remote} - header_upstream X-Forwarded-Proto {scheme} - header_upstream X-CSRFToken {~csrftoken} - } - log stdout - errors stdout - gzip -} diff --git a/{{cookiecutter.project_slug}}/compose/production/caddy/Dockerfile b/{{cookiecutter.project_slug}}/compose/production/caddy/Dockerfile deleted file mode 100644 index c32efb3e..00000000 --- a/{{cookiecutter.project_slug}}/compose/production/caddy/Dockerfile +++ /dev/null @@ -1,3 +0,0 @@ -FROM abiosoft/caddy:0.11.0 - -COPY ./compose/production/caddy/Caddyfile /etc/Caddyfile diff --git a/{{cookiecutter.project_slug}}/compose/production/traefik/Dockerfile b/{{cookiecutter.project_slug}}/compose/production/traefik/Dockerfile new file mode 100644 index 00000000..7088e6fe --- /dev/null +++ b/{{cookiecutter.project_slug}}/compose/production/traefik/Dockerfile @@ -0,0 +1,5 @@ +FROM traefik:alpine +RUN mkdir -p /etc/traefik/acme +RUN touch /etc/traefik/acme/acme.json +RUN chmod 600 /etc/traefik/acme/acme.json +COPY ./compose/production/traefik/traefik.toml /etc/traefik diff --git a/{{cookiecutter.project_slug}}/compose/production/traefik/traefik.toml b/{{cookiecutter.project_slug}}/compose/production/traefik/traefik.toml new file mode 100644 index 00000000..ad1f20e9 --- /dev/null +++ b/{{cookiecutter.project_slug}}/compose/production/traefik/traefik.toml @@ -0,0 +1,41 @@ +logLevel = "INFO" +defaultEntryPoints = ["http", "https"] + +# Entrypoints, http and https +[entryPoints] + # http should be redirected to https + [entryPoints.http] + address = ":80" + [entryPoints.http.redirect] + entryPoint = "https" + # https is the default + [entryPoints.https] + address = ":443" + [entryPoints.https.tls] + +# Enable ACME (Let's Encrypt): automatic SSL +[acme] +# Email address used for registration +email = "{{ cookiecutter.email }}" +storageFile = "/etc/traefik/acme/acme.json" +entryPoint = "https" +onDemand = false +OnHostRule = true + # Use a HTTP-01 acme challenge rather than TLS-SNI-01 challenge + [acme.httpChallenge] + entryPoint = "http" + +[file] +[backends] + [backends.django] + [backends.django.servers.server1] + url = "http://django:5000" + +[frontends] + [frontends.django] + backend = "django" + passHostHeader = true + [frontends.django.headers] + HostsProxyHeaders = ['X-CSRFToken'] + [frontends.django.routes.dr1] + rule = "Host:{{ cookiecutter.domain_name }}" diff --git a/{{cookiecutter.project_slug}}/merge_production_dotenvs_in_dotenv.py b/{{cookiecutter.project_slug}}/merge_production_dotenvs_in_dotenv.py index 5c3027a4..4e70e2ad 100644 --- a/{{cookiecutter.project_slug}}/merge_production_dotenvs_in_dotenv.py +++ b/{{cookiecutter.project_slug}}/merge_production_dotenvs_in_dotenv.py @@ -8,7 +8,6 @@ PRODUCTION_DOTENVS_DIR_PATH = os.path.join(ROOT_DIR_PATH, ".envs", ".production" PRODUCTION_DOTENV_FILE_PATHS = [ os.path.join(PRODUCTION_DOTENVS_DIR_PATH, ".django"), os.path.join(PRODUCTION_DOTENVS_DIR_PATH, ".postgres"), - os.path.join(PRODUCTION_DOTENVS_DIR_PATH, ".caddy"), ] DOTENV_FILE_PATH = os.path.join(ROOT_DIR_PATH, ".env") diff --git a/{{cookiecutter.project_slug}}/production.yml b/{{cookiecutter.project_slug}}/production.yml index fd8388ac..88cf8773 100644 --- a/{{cookiecutter.project_slug}}/production.yml +++ b/{{cookiecutter.project_slug}}/production.yml @@ -3,7 +3,7 @@ version: '3' volumes: production_postgres_data: {} production_postgres_data_backups: {} - production_caddy: {} + production_traefik: {} services: django:{% if cookiecutter.use_celery == 'y' %} &django{% endif %} @@ -30,17 +30,15 @@ services: env_file: - ./.envs/.production/.postgres - caddy: + traefik: build: context: . - dockerfile: ./compose/production/caddy/Dockerfile - image: {{ cookiecutter.project_slug }}_production_caddy + dockerfile: ./compose/production/traefik/Dockerfile + image: {{ cookiecutter.project_slug }}_production_traefik depends_on: - django volumes: - - production_caddy:/root/.caddy - env_file: - - ./.envs/.production/.caddy + - production_traefik:/etc/traefik/acme ports: - "0.0.0.0:80:80" - "0.0.0.0:443:443"