merge @mjsisley #576

This commit is contained in:
Daniel Roy Greenfeld 2016-06-04 10:21:44 -07:00
commit 94cb04b389
11 changed files with 313 additions and 21 deletions

View File

@ -97,6 +97,7 @@ Listed in alphabetical order.
Matt Linares
Matt Menzenski `@menzenski`_
Matt Warren `@mfwarren`_
Matthew Sisley `@mjsisley`_
Meghan Heintz `@dot2dotseurat`_
mjsisley `@mjsisley`_
mozillazg `@mozillazg`_
@ -183,6 +184,7 @@ Listed in alphabetical order.
.. _@yunti: https://github.com/yunti
.. _@zcho: https://github.com/zcho
.. _@noisy: https://github.com/noisy
.. _@mjsisley: https://github.com/mjsisley
Special Thanks
~~~~~~~~~~~~~~

View File

@ -21,5 +21,6 @@
"use_docker": "y",
"use_heroku": "n",
"js_task_runner": ["Gulp", "Grunt", "None"],
"use_certbot": "n",
"open_source_license": ["MIT", "BSD", "Apache Software License 2.0", "Not open source"]
}

View File

@ -110,3 +110,47 @@ To get the status, run::
If you have errors, you can always check your stack with `docker-compose`. Switch to your projects root directory and run::
docker-compose ps
If you are using certbot for https, you must do the following before running anything with docker-compose:
Replace dhparam.pem.example with a generated dhparams.pem file before running anything with docker-compose. You can generate this on ubuntu or OS X by running the following in the project root:
::
$ openssl dhparam -out /path/to/project/compose/nginx/dhparams.pem 2048
If you would like to add additional subdomains to your certificate, you must add additional parameters to the certbot command in the `docker-compose.yml` file:
Replace:
::
command: bash -c "sleep 6 && certbot certonly -n --standalone -d {{ cookiecutter.domain_name }} --text --agree-tos --email mjsisley@relawgo.com --server https://acme-v01.api.letsencrypt.org/directory --rsa-key-size 4096 --verbose --keep-until-expiring --standalone-supported-challenges http-01"
With:
::
command: bash -c "sleep 6 && certbot certonly -n --standalone -d {{ cookiecutter.domain_name }} -d www.{{ cookiecutter.domain_name }} -d etc.{{ cookiecutter.domain_name }} --text --agree-tos --email {{ cookiecutter.email }} --server https://acme-v01.api.letsencrypt.org/directory --rsa-key-size 4096 --verbose --keep-until-expiring --standalone-supported-challenges http-01"
Please be cognizant of Certbot/Letsencrypt certificate requests limits when getting this set up. The provide a test server that does not count against the limit while you are getting set up.
The certbot certificates expire after 3 months.
If you would like to set up autorenewal of your certificates, the following commands can be put into a bash script:
::
#!/bin/bash
cd <project directory>
docker-compose run certbot bash -c "sleep 6 && certbot certonly --standalone -d {{ cookiecutter.domain_name }} --text --agree-tos --email {{ cookiecutter.email }} --server https://acme-v01.api.letsencrypt.org/directory --rsa-key-size 4096 --verbose --keep-until-expiring --standalone-supported-challenges http-01"
docker exec pearl_nginx_1 nginx -s reload
And then set a cronjob by running `crontab -e` and placing in it (period can be adjusted as desired):
0 4 * * 1 /path/to/bashscript/renew_certbot.sh

View File

@ -160,6 +160,7 @@ Then you may need to run the following for it to work as desired:
$ docker-compose run -f dev.yml --service-ports django
django-debug-toolbar
""""""""""""""""""""

View File

@ -157,6 +157,16 @@ def remove_packageJSON_file():
PROJECT_DIRECTORY, filename
))
def remove_certbot_files():
"""
Removes files needed for certbot if it isn't going to be used
"""
nginx_dir_location = os.path.join(PROJECT_DIRECTORY, 'compose/nginx')
for filename in ["nginx-secure.conf", "start.sh", "dhparams.example.pem"]:
os.remove(os.path.join(
nginx_dir_location, filename
))
# IN PROGRESS
# def copy_doc_files(project_directory):
# cookiecutters_dir = DEFAULT_CONFIG['cookiecutters_dir']
@ -204,9 +214,12 @@ else:
remove_grunt_files()
remove_packageJSON_file()
# 7. Removes all certbot/letsencrypt files if it isn't going to be used
if '{{ cookiecutter.use_certbot }}'.lower() != 'y':
remove_certbot_files()
# 7. Display a warning if use_docker and js task runner are selected. Grunt isn't supported by our
# docker config atm.
# 8. Display a warning if use_docker and use_grunt are selected. Grunt isn't
# supported by our docker config atm.
if '{{ cookiecutter.js_task_runner }}'.lower() in ['grunt', 'gulp'] and '{{ cookiecutter.use_docker }}'.lower() == 'y':
print(
"You selected to use docker and a JS task runner. This is NOT supported out of the box for now. You "
@ -214,13 +227,19 @@ if '{{ cookiecutter.js_task_runner }}'.lower() in ['grunt', 'gulp'] and '{{ cook
"js task runner service to your docker configuration manually."
)
# 7. Display a warning if use_docker and use_mailhog are selected. Mailhog isn't supported by our
# docker config atm.
if '{{ cookiecutter.use_mailhog }}'.lower() == 'y' and '{{ cookiecutter.use_docker }}'.lower() == 'y':
# 9. Removes the certbot/letsencrypt files and display a warning if use_certbot is selected and use_docker isn't.
if '{{ cookiecutter.use_certbot }}'.lower() == 'y' and '{{ cookiecutter.use_docker }}'.lower() != 'y':
remove_certbot_files()
print(
"You selected to use docker and mailhog. This is NOT supported out of the box for now. You"
" can continue to use the project like you normally would, but you will need to add a "
" mailhog service to your docker configuration manually."
"You selected to use certbot(letsencrypt) and didn't select to use docker. This is NOT supported out of the box for now. You "
"can continue to use the project like you normally would, but you will no certbot files have been included"
)
# 10. Directs the user to the documentation if certbot and docker are selected.
if '{{ cookiecutter.use_certbot }}'.lower() == 'y' and '{{ cookiecutter.use_docker }}'.lower() == 'y':
print(
"You selected to use certbot(letsencrypt), please see the documentation for instructions on how to use this in production. "
"You must generate a dhparams.pem file before running docker-compose in a production environment."
)
# 4. Copy files from /docs/ to {{ cookiecutter.project_slug }}/docs/

View File

@ -1,2 +1,8 @@
FROM nginx:latest
ADD nginx.conf /etc/nginx/nginx.conf
{% if cookiecutter.use_certbot == 'y' and cookiecutter.use_docker == 'y' %}
ADD start.sh /start.sh
ADD nginx-secure.conf /etc/nginx/nginx-secure.conf
ADD dhparams.pem /etc/ssl/private/dhparams.pem
{% endif %}

View File

@ -0,0 +1,3 @@
-----BEGIN DH PARAMETERS-----
EXAMPLE_FILE
-----END DH PARAMETERS-----

View File

@ -0,0 +1,92 @@
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
proxy_headers_hash_bucket_size 52;
gzip on;
upstream app {
server django:5000;
}
server {
listen 80;
server_name ___my.example.com___ www.___my.example.com___;
location /.well-known/acme-challenge {
proxy_pass http://___LETSENCRYPT_IP___:___LETSENCRYPT_PORT___;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Proto $scheme;
}
location / {
return 301 https://$server_name$request_uri;
}
}
server {
listen 443;
server_name ___my.example.com___ www.___my.example.com___;
ssl on;
ssl_certificate /etc/letsencrypt/live/___my.example.com___/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/___my.example.com___/privkey.pem;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_dhparam /etc/ssl/private/dhparams.pem;
location /.well-known/acme-challenge {
proxy_pass http://___LETSENCRYPT_HTTPS_IP___:___LETSENCRYPT_HTTPS_PORT___;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto https;
}
location / {
# checks for static file, if not found proxy to app
try_files $uri @proxy_to_app;
}
# cookiecutter-django app
location @proxy_to_app {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://app;
}
}
}

View File

@ -9,9 +9,9 @@ events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
@ -31,23 +31,40 @@ http {
server django:5000;
}
server {
listen 80;
charset utf-8;
server {
listen 80;
charset utf-8;
{% if cookiecutter.use_certbot == 'y' and cookiecutter.use_docker == 'y' %}
server_name ___my.example.com___ ;
location / {
location /.well-known/acme-challenge {
proxy_pass http://___LETSENCRYPT_IP___:___LETSENCRYPT_PORT___;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto https;
}
{% endif %}
location / {
# checks for static file, if not found proxy to app
try_files $uri @proxy_to_app;
}
location @proxy_to_app {
# cookiecutter-django app
location @proxy_to_app {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://app;
}
}
}
}
}

View File

@ -0,0 +1,81 @@
echo sleep 5
sleep 5
echo build starting nginx config
echo replacing ___my.example.com___/$MY_DOMAIN_NAME
echo replacing ___LETSENCRYPT_IP___/$LETSENCRYPT_PORT_80_TCP_ADDR
echo replacing ___LETSENCRYPT_PORT___/$LETSENCRYPT_PORT_80_TCP_PORT
echo replacing ___APPLICATION_IP___/$APP_PORT_80_TCP_ADDR
echo replacing ___APPLICATION_PORT___/$APP_PORT_80_TCP_PORT
# Put your domain name into the nginx reverse proxy config.
sed -i "s/___my.example.com___/$MY_DOMAIN_NAME/g" /etc/nginx/nginx.conf
# Add your app's container IP and port into config
sed -i "s/___APPLICATION_IP___/$APP_PORT_80_TCP_ADDR/g" /etc/nginx/nginx.conf
sed -i "s/___APPLICATION_PORT___/$APP_PORT_80_TCP_PORT/g" /etc/nginx/nginx.conf
sed -i "s/___LETSENCRYPT_IP___/$LETSENCRYPT_PORT_80_TCP_ADDR/g" /etc/nginx/nginx.conf
sed -i "s/___LETSENCRYPT_PORT___/$LETSENCRYPT_PORT_80_TCP_PORT/g" /etc/nginx/nginx.conf
cat /etc/nginx/nginx.conf
echo .
echo Firing up nginx in the background.
nginx
# # Check user has specified domain name
if [ -z "$MY_DOMAIN_NAME" ]; then
echo "Need to set MY_DOMAIN_NAME (to a letsencrypt-registered name)."
exit 1
fi
# This bit waits until the letsencrypt container has done its thing.
# We see the changes here bceause there's a docker volume mapped.
echo Waiting for folder /etc/letsencrypt/live/$MY_DOMAIN_NAME to exist
while [ ! -d /etc/letsencrypt/live/$MY_DOMAIN_NAME ] ;
do
sleep 2
done
while [ ! -f /etc/letsencrypt/live/$MY_DOMAIN_NAME/fullchain.pem ] ;
do
echo Waiting for file fullchain.pem to exist
sleep 2
done
while [ ! -f /etc/letsencrypt/live/$MY_DOMAIN_NAME/privkey.pem ] ;
do
echo Waiting for file privkey.pem to exist
sleep 2
done
# This is added so that when the certificate is being renewed or is already in place, nginx waits for everything to be good.
sleep 15
echo replacing ___my.example.com___/$MY_DOMAIN_NAME
echo replacing ___LETSENCRYPT_IP___/$LETSENCRYPT_PORT_80_TCP_ADDR
echo replacing ___LETSENCRYPT_PORT___/$LETSENCRYPT_PORT_80_TCP_PORT
echo replacing ___LETSENCRYPT_HTTPS_IP___/$LETSENCRYPT_PORT_443_TCP_ADDR
echo replacing ___LETSENCRYPT_HTTPS_PORT___/$LETSENCRYPT_PORT_443_TCP_PORT
echo replacing ___APPLICATION_IP___/$APP_PORT_80_TCP_ADDR
echo replacing ___APPLICATION_PORT___/$APP_PORT_80_TCP_PORT
# Put your domain name into the nginx reverse proxy config.
sed -i "s/___my.example.com___/$MY_DOMAIN_NAME/g" /etc/nginx/nginx-secure.conf
# Add LE container IP and port into config
sed -i "s/___LETSENCRYPT_IP___/$LETSENCRYPT_PORT_80_TCP_ADDR/g" /etc/nginx/nginx-secure.conf
sed -i "s/___LETSENCRYPT_PORT___/$LETSENCRYPT_PORT_80_TCP_PORT/g" /etc/nginx/nginx-secure.conf
sed -i "s/___LETSENCRYPT_HTTPS_IP___/$LETSENCRYPT_PORT_443_TCP_ADDR/g" /etc/nginx/nginx-secure.conf
sed -i "s/___LETSENCRYPT_HTTPS_PORT___/$LETSENCRYPT_PORT_443_TCP_PORT/g" /etc/nginx/nginx-secure.conf
# Add your app's container IP and port into config
sed -i "s/___APPLICATION_IP___/$APP_PORT_80_TCP_ADDR/g" /etc/nginx/nginx-secure.conf
sed -i "s/___APPLICATION_PORT___/$APP_PORT_80_TCP_PORT/g" /etc/nginx/nginx-secure.conf
#go!
kill $(ps aux | grep 'nginx' | awk '{print $2}')
cp /etc/nginx/nginx-secure.conf /etc/nginx/nginx.conf
nginx -g 'daemon off;'

View File

@ -27,12 +27,38 @@ services:
build: ./compose/nginx
depends_on:
- django
{% if cookiecutter.use_certbot == 'y' %}
- certbot
{% endif %}
ports:
- "0.0.0.0:80:80"
{% if cookiecutter.use_certbot == 'y' %}
environment:
- MY_DOMAIN_NAME={{ cookiecutter.domain_name }}
ports:
- "0.0.0.0:80:80"
- "0.0.0.0:443:443"
volumes:
- /etc/letsencrypt:/etc/letsencrypt
- /var/lib/letsencrypt:/var/lib/letsencrypt
certbot:
image: quay.io/letsencrypt/letsencrypt
command: bash -c "sleep 6 && certbot certonly -n --standalone -d {{ cookiecutter.domain_name }} --text --agree-tos --email {{ cookiecutter.email }} --server https://acme-v01.api.letsencrypt.org/directory --rsa-key-size 4096 --verbose --keep-until-expiring --standalone-supported-challenges http-01"
entrypoint: ""
volumes:
- /etc/letsencrypt:/etc/letsencrypt
- /var/lib/letsencrypt:/var/lib/letsencrypt
ports:
- "80"
- "443"
environment:
- TERM=xterm
{% endif %}
redis:
image: redis:3.0
{% if cookiecutter.use_celery == 'y' %}
{% if cookiecutter.use_celery == 'y' %}
celeryworker:
build:
context: .
@ -54,4 +80,4 @@ services:
- postgres
- redis
command: celery -A {{cookiecutter.project_slug}}.taskapp beat -l INFO
{% endif %}
{% endif %}