stage config, and contact form setup to send email

This commit is contained in:
Oliver Marks 2017-02-05 12:59:20 +00:00
parent 60030f14cd
commit 3d8c6a24a2
14 changed files with 365 additions and 70 deletions

View File

@ -1,6 +1,4 @@
#!/bin/sh #!/bin/sh
python /app/manage.py collectstatic --noinput python /app/manage.py collectstatic --noinput
chmod 777 -R /data/sockets/ python /app/manage.py compilescss
touch /data/sockets/gunicron.sock
ls -la /data/sockets/
/usr/local/bin/gunicorn config.wsgi -w 4 -b unix:/data/sockets/gunicorn.sock --chdir=/app /usr/local/bin/gunicorn config.wsgi -w 4 -b unix:/data/sockets/gunicorn.sock --chdir=/app

View File

@ -3,7 +3,7 @@ ADD nginx.conf /etc/nginx/nginx.conf
ADD start.sh /start.sh ADD start.sh /start.sh
ADD nginx-secure.conf /etc/nginx/nginx-secure.conf #ADD nginx-secure.conf /etc/nginx/nginx-secure.conf
#ADD dhparams.pem /etc/ssl/private/dhparams.pem #ADD dhparams.pem /etc/ssl/private/dhparams.pem
CMD /start.sh CMD /start.sh

View File

@ -30,51 +30,33 @@ http {
gzip on; gzip on;
upstream app { upstream app {
server django:5000; server unix:/data/sockets/gunicorn.sock;
# server django:5000;
} }
server { server {
listen 80; listen 80;
server_name ___my.example.com___ www.___my.example.com___; server_name ___my.example.com___ www.___my.example.com___;
location /.well-known/acme-challenge { # ssl on;
# Since the certbot container isn't up constantly, need to resolve ip dynamically using docker's dns # ssl_certificate /etc/letsencrypt/live/___my.example.com___/fullchain.pem;
resolver ___NAMESERVER___; # ssl_certificate_key /etc/letsencrypt/live/___my.example.com___/privkey.pem;
set $certbot_addr_port certbot:80; # ssl_session_timeout 5m;
proxy_pass http://$certbot_addr_port; # ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
proxy_set_header Host $host; # ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
proxy_set_header X-Forwarded-For $remote_addr; # ssl_prefer_server_ciphers on;
proxy_set_header X-Forwarded-Proto $scheme;
}
location / { # ssl_session_cache shared:SSL:10m;
return 301 https://$server_name$request_uri; # ssl_dhparam /etc/ssl/private/dhparams.pem;
}
} # location /.well-known/acme-challenge {
# resolver ___NAMESERVER___;
server { # set $certbot_addr_port certbot:443;
listen 443; # proxy_pass http://$certbot_addr_port;
server_name ___my.example.com___ www.___my.example.com___; # proxy_set_header Host $host;
# proxy_set_header X-Forwarded-For $remote_addr;
ssl on; # proxy_set_header X-Forwarded-Proto https;
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 {
resolver ___NAMESERVER___;
set $certbot_addr_port certbot:443;
proxy_pass http://$certbot_addr_port;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto https;
}
location / { location / {
# checks for static file, if not found proxy to app # checks for static file, if not found proxy to app

View File

@ -22,26 +22,26 @@ fi
# This bit waits until the letsencrypt container has done its thing. # This bit waits until the letsencrypt container has done its thing.
# We see the changes here bceause there's a docker volume mapped. # We see the changes here bceause there's a docker volume mapped.
echo Waiting for folder /etc/letsencrypt/live/$MY_DOMAIN_NAME to exist #echo Waiting for folder /etc/letsencrypt/live/$MY_DOMAIN_NAME to exist
while [ ! -d /etc/letsencrypt/live/$MY_DOMAIN_NAME ] ; #while [ ! -d /etc/letsencrypt/live/$MY_DOMAIN_NAME ] ;
do #do
sleep 2 # sleep 2
done #done
while [ ! -f /etc/letsencrypt/live/$MY_DOMAIN_NAME/fullchain.pem ] ; #while [ ! -f /etc/letsencrypt/live/$MY_DOMAIN_NAME/fullchain.pem ] ;
do #do
echo Waiting for file fullchain.pem to exist # echo Waiting for file fullchain.pem to exist
sleep 2 # sleep 2
done #done
while [ ! -f /etc/letsencrypt/live/$MY_DOMAIN_NAME/privkey.pem ] ; #while [ ! -f /etc/letsencrypt/live/$MY_DOMAIN_NAME/privkey.pem ] ;
do #do
echo Waiting for file privkey.pem to exist # echo Waiting for file privkey.pem to exist
sleep 2 # sleep 2
done #done
# This is added so that when the certificate is being renewed or is already in place, nginx waits for everything to be good. # 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 #sleep 15
echo replacing ___my.example.com___/$MY_DOMAIN_NAME echo replacing ___my.example.com___/$MY_DOMAIN_NAME

View File

@ -25,7 +25,7 @@ SECRET_KEY = env('DJANGO_SECRET_KEY')
# This ensures that Django will be able to detect a secure connection # This ensures that Django will be able to detect a secure connection
# properly on Heroku. # properly on Heroku.
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') # SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
# Use Whitenoise to serve static files # Use Whitenoise to serve static files
# See: https://whitenoise.readthedocs.io/ # See: https://whitenoise.readthedocs.io/
WHITENOISE_MIDDLEWARE = ('whitenoise.middleware.WhiteNoiseMiddleware', ) WHITENOISE_MIDDLEWARE = ('whitenoise.middleware.WhiteNoiseMiddleware', )
@ -46,7 +46,7 @@ SECURE_CONTENT_TYPE_NOSNIFF = env.bool(
SECURE_BROWSER_XSS_FILTER = True SECURE_BROWSER_XSS_FILTER = True
SESSION_COOKIE_SECURE = True SESSION_COOKIE_SECURE = True
SESSION_COOKIE_HTTPONLY = True SESSION_COOKIE_HTTPONLY = True
SECURE_SSL_REDIRECT = env.bool('DJANGO_SECURE_SSL_REDIRECT', default=True) #SECURE_SSL_REDIRECT = env.bool('DJANGO_SECURE_SSL_REDIRECT', default=True)
CSRF_COOKIE_SECURE = True CSRF_COOKIE_SECURE = True
CSRF_COOKIE_HTTPONLY = True CSRF_COOKIE_HTTPONLY = True
X_FRAME_OPTIONS = 'DENY' X_FRAME_OPTIONS = 'DENY'
@ -56,7 +56,7 @@ X_FRAME_OPTIONS = 'DENY'
# Hosts/domain names that are valid for this site # Hosts/domain names that are valid for this site
# See https://docs.djangoproject.com/en/1.6/ref/settings/#allowed-hosts # See https://docs.djangoproject.com/en/1.6/ref/settings/#allowed-hosts
ALLOWED_HOSTS = env.list('DJANGO_ALLOWED_HOSTS', default=['maidstone-hackspace.org.uk']) ALLOWED_HOSTS = env.list('DJANGO_ALLOWED_HOSTS', default=['maidstone-hackspace.org.uk'])
ALLOWED_HOSTS.append('172.*') ALLOWED_HOSTS.append('127.0.0.1')
ALLOWED_HOSTS.append('172.18.0.5') ALLOWED_HOSTS.append('172.18.0.5')
# END SITE CONFIGURATION # END SITE CONFIGURATION

217
config/settings/stage.py Normal file
View File

@ -0,0 +1,217 @@
# -*- coding: utf-8 -*-
"""
Production Configurations
- Use Amazon's S3 for storing static files and uploaded media
- Use mailgun to send emails
- Use Redis for cache
"""
from __future__ import absolute_import, unicode_literals
from boto.s3.connection import OrdinaryCallingFormat
from django.utils import six
from .common import * # noqa
# SECRET CONFIGURATION
# ------------------------------------------------------------------------------
# See: https://docs.djangoproject.com/en/dev/ref/settings/#secret-key
# Raises ImproperlyConfigured exception if DJANGO_SECRET_KEY not in os.environ
SECRET_KEY = env('DJANGO_SECRET_KEY')
# This ensures that Django will be able to detect a secure connection
# properly on Heroku.
# SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
# Use Whitenoise to serve static files
# See: https://whitenoise.readthedocs.io/
WHITENOISE_MIDDLEWARE = ('whitenoise.middleware.WhiteNoiseMiddleware', )
MIDDLEWARE = WHITENOISE_MIDDLEWARE + MIDDLEWARE
# SECURITY CONFIGURATION
# ------------------------------------------------------------------------------
# See https://docs.djangoproject.com/en/1.9/ref/middleware/#module-django.middleware.security
# and https://docs.djangoproject.com/ja/1.9/howto/deployment/checklist/#run-manage-py-check-deploy
# set this to 60 seconds and then to 518400 when you can prove it works
SECURE_HSTS_SECONDS = 60
SECURE_HSTS_INCLUDE_SUBDOMAINS = env.bool(
'DJANGO_SECURE_HSTS_INCLUDE_SUBDOMAINS', default=True)
SECURE_CONTENT_TYPE_NOSNIFF = env.bool(
'DJANGO_SECURE_CONTENT_TYPE_NOSNIFF', default=True)
SECURE_BROWSER_XSS_FILTER = True
SESSION_COOKIE_SECURE = True
SESSION_COOKIE_HTTPONLY = True
#SECURE_SSL_REDIRECT = env.bool('DJANGO_SECURE_SSL_REDIRECT', default=True)
CSRF_COOKIE_SECURE = True
CSRF_COOKIE_HTTPONLY = True
X_FRAME_OPTIONS = 'DENY'
# SITE CONFIGURATION
# ------------------------------------------------------------------------------
# Hosts/domain names that are valid for this site
# See https://docs.djangoproject.com/en/1.6/ref/settings/#allowed-hosts
ALLOWED_HOSTS = env.list('DJANGO_ALLOWED_HOSTS', default=['test.maidstone-hackspace.org.uk'])
ALLOWED_HOSTS.append('127.0.0.1')
ALLOWED_HOSTS.append('172.18.0.5')
# END SITE CONFIGURATION
INSTALLED_APPS += ('gunicorn', )
# STORAGE CONFIGURATION
# ------------------------------------------------------------------------------
# Uploaded Media Files
# ------------------------
# See: http://django-storages.readthedocs.io/en/latest/index.html
INSTALLED_APPS += (
'storages',
)
AWS_ACCESS_KEY_ID = env('DJANGO_AWS_ACCESS_KEY_ID')
AWS_SECRET_ACCESS_KEY = env('DJANGO_AWS_SECRET_ACCESS_KEY')
AWS_STORAGE_BUCKET_NAME = env('DJANGO_AWS_STORAGE_BUCKET_NAME')
AWS_AUTO_CREATE_BUCKET = True
AWS_QUERYSTRING_AUTH = False
AWS_S3_CALLING_FORMAT = OrdinaryCallingFormat()
# AWS cache settings, don't change unless you know what you're doing:
AWS_EXPIRY = 60 * 60 * 24 * 7
# TODO See: https://github.com/jschneier/django-storages/issues/47
# Revert the following and use str after the above-mentioned bug is fixed in
# either django-storage-redux or boto
AWS_HEADERS = {
'Cache-Control': six.b('max-age=%d, s-maxage=%d, must-revalidate' % (
AWS_EXPIRY, AWS_EXPIRY))
}
# URL that handles the media served from MEDIA_ROOT, used for managing
# stored files.
MEDIA_URL = 'https://s3.amazonaws.com/%s/' % AWS_STORAGE_BUCKET_NAME
# Static Assets
# ------------------------
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
# COMPRESSOR
# ------------------------------------------------------------------------------
COMPRESS_STORAGE = 'storages.backends.s3boto.S3BotoStorage'
COMPRESS_URL = STATIC_URL
COMPRESS_ENABLED = env.bool('COMPRESS_ENABLED', default=True)
# EMAIL
# ------------------------------------------------------------------------------
DEFAULT_FROM_EMAIL = env('DJANGO_DEFAULT_FROM_EMAIL',
default='Maidstone Hackspace <noreply@test.maidstone-hackspace.org.uk>')
EMAIL_SUBJECT_PREFIX = env('DJANGO_EMAIL_SUBJECT_PREFIX', default='[Maidstone Hackspace] ')
SERVER_EMAIL = env('DJANGO_SERVER_EMAIL', default=DEFAULT_FROM_EMAIL)
SERVER_EMAIL_PORT = '465'
EMAIL_USE_TLS = False
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_HOST_PASSWORD = env('EMAIL_PASSWORD')
EMAIL_HOST_USER = env('EMAIL_USER')
EMAIL_PORT = 465
# Anymail with Mailgun
#INSTALLED_APPS += ("anymail", )
#ANYMAIL = {
# "MAILGUN_API_KEY": env('DJANGO_MAILGUN_API_KEY'),
# "MAILGUN_SENDER_DOMAIN": env('MAILGUN_SENDER_DOMAIN')
#}
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
# TEMPLATE CONFIGURATION
# ------------------------------------------------------------------------------
# See:
# https://docs.djangoproject.com/en/dev/ref/templates/api/#django.template.loaders.cached.Loader
TEMPLATES[0]['OPTIONS']['loaders'] = [
('django.template.loaders.cached.Loader', [
'django.template.loaders.filesystem.Loader', 'django.template.loaders.app_directories.Loader', ]),
]
# DATABASE CONFIGURATION
# ------------------------------------------------------------------------------
# Use the Heroku-style specification
# Raises ImproperlyConfigured exception if DATABASE_URL not in os.environ
DATABASES['default'] = env.db('DATABASE_URL')
# CACHING
# ------------------------------------------------------------------------------
REDIS_LOCATION = '{0}/{1}'.format(env('REDIS_URL', default='redis://127.0.0.1:6379'), 0)
# Heroku URL does not pass the DB number, so we parse it in
CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': REDIS_LOCATION,
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
'IGNORE_EXCEPTIONS': True, # mimics memcache behavior.
# http://niwinz.github.io/django-redis/latest/#_memcached_exceptions_behavior
}
}
}
# LOGGING CONFIGURATION
# ------------------------------------------------------------------------------
# See: https://docs.djangoproject.com/en/dev/ref/settings/#logging
# A sample logging configuration. The only tangible logging
# performed by this configuration is to send an email to
# the site admins on every HTTP 500 error when DEBUG=False.
# See http://docs.djangoproject.com/en/dev/topics/logging for
# more details on how to customize your logging configuration.
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'filters': {
'require_debug_false': {
'()': 'django.utils.log.RequireDebugFalse'
}
},
'formatters': {
'verbose': {
'format': '%(levelname)s %(asctime)s %(module)s '
'%(process)d %(thread)d %(message)s'
},
},
'handlers': {
'mail_admins': {
'level': 'ERROR',
'filters': ['require_debug_false'],
'class': 'django.utils.log.AdminEmailHandler'
},
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'verbose',
},
},
'loggers': {
'django.request': {
'handlers': ['mail_admins'],
'level': 'ERROR',
'propagate': True
},
'django.security.DisallowedHost': {
'level': 'ERROR',
'handlers': ['console', 'mail_admins'],
'propagate': True
}
}
}
# Custom Admin URL, use {% url 'admin:index' %}
ADMIN_URL = env('DJANGO_ADMIN_URL')
# Your production stuff: Below this line define 3rd party library settings
# ------------------------------------------------------------------------------

View File

@ -48,7 +48,7 @@ services:
environment: environment:
- MY_DOMAIN_NAME=maidstone-hackspace.org.uk - MY_DOMAIN_NAME=maidstone-hackspace.org.uk
ports: ports:
- "0.0.0.0:80:80" - "0.0.0.0:8080:80"
volumes: volumes:
- .:/app - .:/app
- gunicorn_socket:/data/sockets - gunicorn_socket:/data/sockets

View File

@ -14,7 +14,7 @@ class ContactForm(forms.Form):
required=True, required=True,
widget=forms.Textarea widget=forms.Textarea
) )
type = forms.MultipleChoiceField( enquiry_type = forms.ChoiceField(
required=True, required=True,
widget=forms.Select, widget=forms.Select,
choices=TYPES) choices=TYPES)

View File

@ -1,10 +1,25 @@
from django.shortcuts import render from django.shortcuts import render
from django.core.mail import EmailMessage
from django.contrib import messages
from mhackspace.contact.forms import ContactForm from mhackspace.contact.forms import ContactForm
# add to your views # add to your views
def contact(request): def contact(request):
form_class = ContactForm form_class = ContactForm
form = form_class(data=request.POST)
if request.method == 'POST':
form = form_class(data=request.POST)
if form.is_valid():
data = form.cleaned_data
email = EmailMessage(
'[%s] - %s' % (data['enquiry_type'], data['subject']),
data['message'],
to=['no-reply@maidstone-hackspace..org.uk'])
email.send()
messages.add_message(request, messages.INFO, 'E-Mail sent')
return render(request, 'pages/contact.html', { return render(request, 'pages/contact.html', {
'form': form_class, 'form': form,
}) })

View File

@ -1,4 +1,5 @@
{% load staticfiles i18n compress %} {% load i18n compress %}
{% load static from staticfiles %}
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
@ -99,14 +100,14 @@
<a class="nav-link" href="/members">Members</a> <a class="nav-link" href="/members">Members</a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="#">Mailing List</a> <a class="nav-link" href="/mailing-list">Mailing List</a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link disabled" href="/equipment">Equipment</a> <a class="nav-link disabled" href="/equipment">Equipment</a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link disabled" href="/accounts/signout">Sign out</a> <a class="nav-link disabled" href="/accounts/signout">Sign out make these reversed</a>
</li> </li>
</ul> </ul>
<div class="container"> <div class="container">

View File

@ -6,7 +6,13 @@
{% block content %} {% block content %}
<h2>Contact us</h2> <h2>Contact us</h2>
<form method="POST" action="{% url 'account_change_password' %}" class="password_change"> Please fill in details below, and we will get back to you when possible, alternatively try our live chat.</br>
<a href="https://hangouts.google.com/group/oDcAL0nDfQYfO3qq1">
Click here to chat with us
</a>
<form method="POST" action="{% url 'contact' %}" class="contact_us_form">
{% csrf_token %} {% csrf_token %}
{{ form|crispy }} {{ form|crispy }}
{{ google_capture }} {{ google_capture }}

View File

@ -5,6 +5,5 @@
<h2>Introduction</h2> <h2>Introduction</h2>
Hackspaces are a shared space where artists, designers, makers, hackers, programmers, tinkerers, professionals and hobbyists can work on their projects, share knowledge and collaborate.We are in the process of developing Maidstone Hackspace. We're previous members of (ICMP) and looking to form a new space in the future. At the moment, communication is via google groups, email, and the website. If you're at all intrested please join our mailing list and make yourself known! Hackspaces are a shared space where artists, designers, makers, hackers, programmers, tinkerers, professionals and hobbyists can work on their projects, share knowledge and collaborate.We are in the process of developing Maidstone Hackspace. We're previous members of (ICMP) and looking to form a new space in the future. At the moment, communication is via google groups, email, and the website. If you're at all intrested please join our mailing list and make yourself known!
Click here to chat with us https://hangouts.google.com/group/oDcAL0nDfQYfO3qq1
{% show_feeds %} {% show_feeds %}
{% endblock content %} {% endblock content %}

77
stage.yml Normal file
View File

@ -0,0 +1,77 @@
version: '2'
volumes:
sockets:
driver: local
external: true
postgres_data:
driver: local
postgres_backup:
driver: local
# volumes:
# sockets:
# driver: local
# data:
# driver: local
services:
postgres:
build: ./compose/postgres
volumes:
- postgres_data:/var/lib/postgresql/data
- postgres_backup:/backups
env_file: .env
django:
build:
context: .
dockerfile: ./compose/django/Dockerfile
user: django
depends_on:
- postgres
- redis
command: /gunicorn.sh
env_file: .env
volumes:
- .:/app
- sockets:/data/sockets
# nginx:
# build: ./compose/nginx
# env_file: .env
# depends_on:
# - django
# - certbot
#
# environment:
# - MY_DOMAIN_NAME=test.maidstone-hackspace.org.uk
# ports:
# - "0.0.0.0:8080:80"
# volumes:
# - .:/app
# - sockets:/data/sockets
# - "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 maidstone-hackspace.org.uk --text --agree-tos --email support@maidstone-hackspace.org.uk --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
redis:
image: redis:latest

0
staticfiles/staticfiles Normal file → Executable file
View File