3👍
Since I haven’t found any better approach using YAML files, I am using a Python script to modify the original Apache wsgi.conf
file in the most agnostic way I can think of (no matters if Amazon modifies it in the future).
I share it here in case anyone can find it useful. With this approach, you don’t have to hardcode the hosts whitelist anywhere in code.
- First add a new command in
.ebextensions/deploy.config
container_commands:
01__apache_block_invalid_hosts:
command: python .ebextensions/apache_block_invalid_hosts.py
Notice that you can consider adding leader_only: true
if you are not planning to change the DJANGO_ALLOWED_HOSTS
environment variable at any time (explained later) and if you understand the implications.
- Create the python script in
.ebextensions/apache_block_invalid_hosts.py
from enum import Enum, auto
import os
NEW_AUTH_DIRECTIVE = """
Require expr "%{{HTTP_HOST}} in {{{hosts}}}"
Options
"""
class Step(Enum):
BEFORE_AUTH = auto()
INSIDE_AUTH = auto()
AFTER_AUTH = auto()
step = Step.BEFORE_AUTH
with open('/etc/httpd/conf.d/wsgi.conf', 'r') as file_in, open('../wsgi.conf', 'w') as file_out:
for line in file_in.readlines():
if step == Step.BEFORE_AUTH:
file_out.write(line)
if "<Directory /opt/python/current/app/>" in line:
hosts = ", ".join([f"'{i}'" for i in os.environ['DJANGO_ALLOWED_HOSTS'].split('__')])
file_out.write(NEW_AUTH_DIRECTIVE.format(hosts=hosts))
step = Step.INSIDE_AUTH
elif step == Step.INSIDE_AUTH:
if "</Directory>" in line:
file_out.write(line)
step = Step.AFTER_AUTH
elif step == Step.AFTER_AUTH:
file_out.write(line)
Notice that the output path of the edited file is ../wsgi.conf
and not /etc/httpd/conf.d/wsgi.conf
. Trust me on this, it works.
- Define an environment variable with all the whitelisted hosts in the AWS EB configuration website:
DJANGO_ALLOWED_HOSTS whatever.com__www.whatever.com__whatever.us-east-1.elasticbeanstalk.com
Notice that I am using the __
separator on purpose, instead of a comma. This is because I sometimes create/clone environments directly from my command line using eb clone
while providing changes in the values of environment variables. If you do that, you can’t include commas inside values, and there is no way to escape them.
- Make use of the same envorinment variable from your Django settings file (I use the
django-environ
library to read enviroment variables from the system):
import environ
env = environ.Env()
env.read_env()
ALLOWED_HOSTS = env('DJANGO_ALLOWED_HOSTS', default='*').split('__')
0👍
Apache looks at the Host
HTTP request header when it decides on the name based routing: https://httpd.apache.org/docs/2.4/vhosts/name-based.html
Just have a default virtual host serving static 404 page and allow to route to Django only when proper Host
HTTP request header is specified.
It is also documented in Django: https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/#allowed-hosts
- [Django]-How can I pass additional args in as_view in Django REST framework
- [Django]-Cant get AngularJS's $http.post data in Django
- [Django]-ImportError: cannot import name connections