From 0b57ad32ac214d48da22b64b213993b9ea3c6353 Mon Sep 17 00:00:00 2001 From: chris48s Date: Thu, 6 Aug 2020 14:22:35 +0100 Subject: [PATCH] serve javascript and CSS from nginx --- Dockerfile | 19 ++++++--- deployment/gunicorn.conf | 7 ++++ deployment/gunicorn.config.py | 6 +++ deployment/nginx.conf | 24 +++++++++++ deployment/supervisord.conf | 10 +++++ foundation/settings.py | 75 ++++++++++++++++++----------------- lib/cached_storage.py | 17 -------- 7 files changed, 99 insertions(+), 59 deletions(-) create mode 100644 deployment/gunicorn.conf create mode 100644 deployment/gunicorn.config.py create mode 100644 deployment/nginx.conf create mode 100644 deployment/supervisord.conf delete mode 100644 lib/cached_storage.py diff --git a/Dockerfile b/Dockerfile index 20eafa28..6392209a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,17 @@ -FROM python:2.7 +FROM python:2.7-buster MAINTAINER Open Knowledge Foundation WORKDIR /app RUN apt-get update RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash +RUN apt-get install -y nginx +RUN apt-get install -y supervisor + +RUN echo "daemon off;" >> /etc/nginx/nginx.conf +RUN rm /etc/nginx/sites-enabled/default +COPY deployment/nginx.conf /etc/nginx/conf.d/default.conf +COPY deployment/supervisord.conf /etc/supervisor/conf.d/supervisord.conf +COPY deployment/gunicorn.conf /etc/supervisor/conf.d/gunicorn.conf COPY article_list_item ./article_list_item COPY contrib ./contrib @@ -18,6 +26,7 @@ COPY manage.py . COPY package-lock.json . COPY package.json . COPY requirements.txt . +COPY deployment/gunicorn.config.py . RUN pip install -r requirements.txt RUN . /root/.nvm/nvm.sh && nvm install 10 @@ -26,8 +35,6 @@ RUN . /root/.nvm/nvm.sh && nvm use 10 ENV PORT 80 EXPOSE $PORT -CMD python manage.py migrate && \ - python manage.py update_index && \ - gunicorn foundation.wsgi:application \ - --access-logfile '-' \ - --error-logfile '-' +RUN python manage.py collectstatic --noinput + +CMD python manage.py migrate && python manage.py update_index && /usr/bin/supervisord diff --git a/deployment/gunicorn.conf b/deployment/gunicorn.conf new file mode 100644 index 00000000..8190eb7a --- /dev/null +++ b/deployment/gunicorn.conf @@ -0,0 +1,7 @@ +[program:gunicorn] +command=gunicorn foundation.wsgi:application -c /app/gunicorn.config.py +directory=/app +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 diff --git a/deployment/gunicorn.config.py b/deployment/gunicorn.config.py new file mode 100644 index 00000000..dbd1b3b9 --- /dev/null +++ b/deployment/gunicorn.config.py @@ -0,0 +1,6 @@ +bind = '127.0.0.1:5000' + +workers = 2 +worker_class = 'sync' + +accesslog = '-' diff --git a/deployment/nginx.conf b/deployment/nginx.conf new file mode 100644 index 00000000..a0ad485d --- /dev/null +++ b/deployment/nginx.conf @@ -0,0 +1,24 @@ +server { + listen 80; + + access_log /dev/stderr; + error_log /dev/stdout; + + server_tokens off; + + location /assets { + autoindex on; + alias /app/staticfiles/; + expires 0; + add_header Cache-Control "no-cache, must-revalidate"; + access_log off; + } + + location / { + proxy_pass http://localhost:5000/; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_redirect off; + } +} diff --git a/deployment/supervisord.conf b/deployment/supervisord.conf new file mode 100644 index 00000000..3b2927ef --- /dev/null +++ b/deployment/supervisord.conf @@ -0,0 +1,10 @@ +[supervisord] +nodaemon=true +user=root + +[program:nginx] +command=/usr/sbin/nginx +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 diff --git a/foundation/settings.py b/foundation/settings.py index 16b9ac48..2ccb4953 100644 --- a/foundation/settings.py +++ b/foundation/settings.py @@ -289,6 +289,8 @@ def _parse_email_list(varname): CUSTOM_ASSETS_DOMAIN = env.get('DJANGO_CUSTOM_ASSETS_DOMAIN') +STATIC_URL = '/assets/' +STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') if env.get('DJANGO_USE_AWS_STORAGE') == 'true': AWS_ACCESS_KEY_ID = env['AWS_ACCESS_KEY_ID'] AWS_SECRET_ACCESS_KEY = env['AWS_SECRET_ACCESS_KEY'] @@ -298,27 +300,16 @@ def _parse_email_list(varname): 'Cache-Control': 'max-age=86400', } - STATICFILES_STORAGE = 'lib.cached_storage.CachedStaticStorage' - STATIC_S3_PATH = 'assets' - STATIC_ROOT = 'assets/' - DEFAULT_FILE_STORAGE = 's3_folder_storage.s3.DefaultStorage' DEFAULT_S3_PATH = 'media' MEDIA_ROOT = 'media/' if AWS_S3_CUSTOM_DOMAIN: - STATIC_URL = '//%s/%s/' % (AWS_S3_CUSTOM_DOMAIN, STATIC_S3_PATH) MEDIA_URL = '//%s/%s/' % (AWS_S3_CUSTOM_DOMAIN, DEFAULT_S3_PATH) else: - STATIC_URL = '//s3.amazonaws.com/%s/%s/' % (AWS_STORAGE_BUCKET_NAME, - STATIC_S3_PATH) MEDIA_URL = '//s3.amazonaws.com/%s/%s/' % (AWS_STORAGE_BUCKET_NAME, DEFAULT_S3_PATH) - else: - STATIC_URL = '/assets/' - STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') - MEDIA_URL = '/media/' MEDIA_ROOT = os.path.join(BASE_DIR, 'media') @@ -370,28 +361,43 @@ def _parse_email_list(varname): CSP_DEFAULT_SRC = ("'none'",) - CSP_SCRIPT_SRC = asset_hosts + ['https://js-agent.newrelic.com', - 'https://www.google-analytics.com', - 'https://use.typekit.net', - 'https://bam.nr-data.net', - 'https://downloads.mailchimp.com', - 'https://s3.amazonaws.com/downloads.mailchimp.com', - '*.list-manage.com', - "'unsafe-inline'", "'self'"] - CSP_STYLE_SRC = asset_hosts + ["'unsafe-inline'", - 'https://use.typekit.net'] - CSP_IMG_SRC = asset_hosts + ["data:", - 'https://gravatar.com', - 'https://1.gravatar.com', - 'https://2.gravatar.com', - 'https://secure.gravatar.com', - 'https://p.typekit.net', - 'https://ping.typekit.net', - 'https://www.google-analytics.com'] - CSP_FONT_SRC = asset_hosts + ['data:', - 'https://use.typekit.net', - 'https://themes.googleusercontent.com'] - CSP_FORM_ACTION = ["'self'", 'https://okfn.us9.list-manage.com'] + CSP_SCRIPT_SRC = asset_hosts + [ + "'self'", + "'unsafe-inline'", + 'https://js-agent.newrelic.com', + 'https://www.google-analytics.com', + 'https://use.typekit.net', + 'https://bam.nr-data.net', + 'https://downloads.mailchimp.com', + 'https://s3.amazonaws.com/downloads.mailchimp.com', + '*.list-manage.com', + ] + CSP_STYLE_SRC = asset_hosts + [ + "'self'", + "'unsafe-inline'", + 'https://use.typekit.net', + ] + CSP_IMG_SRC = asset_hosts + [ + "'self'", + "data:", + 'https://gravatar.com', + 'https://1.gravatar.com', + 'https://2.gravatar.com', + 'https://secure.gravatar.com', + 'https://p.typekit.net', + 'https://ping.typekit.net', + 'https://www.google-analytics.com', + ] + CSP_FONT_SRC = asset_hosts + [ + "'self'", + 'data:', + 'https://use.typekit.net', + 'https://themes.googleusercontent.com' + ] + CSP_FORM_ACTION = [ + "'self'", + 'https://okfn.us9.list-manage.com' + ] CSP_REPORT_URI = env.get('DJANGO_CSP_REPORT_URI') else: @@ -403,9 +409,6 @@ def _parse_email_list(varname): MAILCHIMP_URL = env.get('DJANGO_MAILCHIMP_URL', '') MAILCHIMP_TOKEN = env.get('DJANGO_MAILCHIMP_TOKEN', '') -if env.get('DJANGO_USE_AWS_STORAGE') == 'true': - COMPRESS_STORAGE = 'lib.cached_storage.CachedStaticStorage' - COMPRESS_OFFLINE = env.get('DJANGO_COMPRESS_OFFLINE') == 'true' COMPRESS_OFFLINE_CONTEXT = { 'STATIC_URL': STATIC_URL, diff --git a/lib/cached_storage.py b/lib/cached_storage.py deleted file mode 100644 index 080a42e5..00000000 --- a/lib/cached_storage.py +++ /dev/null @@ -1,17 +0,0 @@ -from django.core.files.storage import get_storage_class -from s3_folder_storage.s3 import StaticStorage - - -class CachedStaticStorage(StaticStorage): - """ - S3 storage backend that saves the files locally, too. - """ - def __init__(self, *args, **kwargs): - super(CachedStaticStorage, self).__init__(*args, **kwargs) - self.local_storage = get_storage_class( - "compressor.storage.CompressorFileStorage")() - - def save(self, name, content): - name = super(CachedStaticStorage, self).save(name, content) - self.local_storage._save(name, content) - return name