diff --git a/docker/tna-python/Dockerfile b/docker/tna-python/Dockerfile index c9b39d3..9f84d33 100644 --- a/docker/tna-python/Dockerfile +++ b/docker/tna-python/Dockerfile @@ -34,8 +34,6 @@ EXPOSE 443/tcp # live-ness of an application - this idea is # based on a GOV.UK proposal: # https://github.com/alphagov/govuk-rfcs/blob/main/rfc-141-application-healthchecks.md -# This goes directly to the app, rather than -# through nginx # ========================================== HEALTHCHECK CMD curl --fail http://localhost:8080/healthcheck/live/ || exit 1 @@ -97,10 +95,10 @@ SHELL ["/bin/bash", "-o", "pipefail", "-c"] # Update the package index files and install # specific versions of libcurl4, curl, build # essentials (which then enables us to later -# install Poetry), as well as both nginx and -# ufw - after this, clean and remove all the -# apt registries to avoid the possibility of -# additional installations later on +# install Poetry) after which go on to clean +# and remove all the apt registries to avoid +# the possibility of additional applications +# being installed later on # ========================================== RUN set -eux; \ \ @@ -108,7 +106,7 @@ RUN set -eux; \ \ apt-get update; \ apt-get -y upgrade; \ - apt-get install -y --no-install-recommends libcurl4=7.88.1-10+deb12u7 curl=7.88.1-10+deb12u7 build-essential=12.9 libmagic-dev=1:5.44-3 nginx=1.22.1-9 nginx-common=1.22.1-9 ufw=0.36.2-1 iptables=1.8.9-2; \ + apt-get install -y --no-install-recommends libcurl4=7.88.1-10+deb12u7 curl=7.88.1-10+deb12u7 build-essential=12.9 libmagic-dev=1:5.44-3; \ \ apt-get clean; \ apt-get autoremove -y --purge; \ @@ -144,29 +142,6 @@ ENV HOME=/home/app # ========================================== ENV NVM_DIR="$HOME/.nvm" -# ========================================== -# Update the firewall rule to allow only for -# HTTPS, then create an SSL certificate that -# we can use locally in nginx to secure this -# container -# ========================================== -RUN ufw allow 'Nginx HTTPS'; \ - mkdir /etc/nginx/ssl; \ - openssl req -x509 -noenc -newkey rsa:2048 -keyout /etc/nginx/ssl/key.pem -out /etc/nginx/ssl/req.pem -days 90 -subj "/C=GB/ST=London/L=Kew/O=The National Archives/OU=Digital/CN=localhost"; \ - chmod 644 /etc/nginx/ssl/key.pem - -# ========================================== -# Copy in the nginx configuration file which -# allows us to use a reverse proxy and serve -# the app securely through HTTPS -# ========================================== -COPY lib/nginx.conf /etc/nginx/nginx.conf - -# ========================================== -# Test the installed nginx configuration -# ========================================== -RUN nginx -t - # ========================================== # Install Poetry in the suggested manner and # nvm so we can build static assets like CSS @@ -211,15 +186,18 @@ FROM "$USER_IMAGE" # Install the latest LTS version of Node.js, # but keeping within the releases code-named # "jod" (v22.x) -# (Install the previous LTS release, just in -# case some applicaitons still use it) # ========================================== # hadolint ignore=SC1091 RUN . "$NVM_DIR/nvm.sh"; \ - nvm install lts/iron; \ nvm install lts/jod; \ nvm alias default lts/jod +# ========================================== +# Create a directory for our SSL certificate +# files +# ========================================== +RUN mkdir /home/app/ssl + # ========================================== # Into our .local/bin/ directory copy in the # bash scripts we need in order to build and diff --git a/docker/tna-python/bin/tna-run b/docker/tna-python/bin/tna-run index 03e3c80..61769b3 100755 --- a/docker/tna-python/bin/tna-run +++ b/docker/tna-python/bin/tna-run @@ -52,19 +52,7 @@ DEFAULT_THREADS=$((DEFAULT_WORKERS * 2)) [[ -z $WORKERS ]] && WORKERS=$DEFAULT_WORKERS [[ -z $THREADS ]] && THREADS=$DEFAULT_THREADS -if [ "$ENVIRONMENT" == 'production' ] -then - # Production environment - [[ -z $LOG_LEVEL ]] && LOG_LEVEL=warn - [[ -z $TIMEOUT ]] && TIMEOUT=30 - [[ -z $KEEP_ALIVE ]] && KEEP_ALIVE=30 -elif [ "$ENVIRONMENT" == 'staging' ] -then - # Staging environment - [[ -z $LOG_LEVEL ]] && LOG_LEVEL=debug - [[ -z $TIMEOUT ]] && TIMEOUT=30 - [[ -z $KEEP_ALIVE ]] && KEEP_ALIVE=30 -elif [ "$ENVIRONMENT" == 'develop' ] +if [ "$ENVIRONMENT" == 'develop' ] then # Development environment echo "ENVIRONMENT is develop" @@ -88,7 +76,7 @@ then if poetry show flask ; then echo "Flask found, starting server" - poetry run flask --app "$APPLICATION" run --debug --host 0.0.0.0 --port 8080 + poetry run flask --app "$APPLICATION" run --debug --host 0.0.0.0 --port 8080 --reload fi echo "Flask not found" @@ -104,6 +92,18 @@ then # Fall back to using Gunicorn echo "No framework found, using Gunicorn to serve development application" poetry run gunicorn "$APPLICATION" --workers "$WORKERS" --threads "$THREADS" --log-level "$LOG_LEVEL" --timeout "$TIMEOUT" --keep-alive "$KEEP_ALIVE" --bind 0.0.0.0:8080 --worker-class="$WORKER_CLASS" --reload +elif [ "$ENVIRONMENT" == 'production' ] +then + # Production environment + [[ -z $LOG_LEVEL ]] && LOG_LEVEL=warn + [[ -z $TIMEOUT ]] && TIMEOUT=30 + [[ -z $KEEP_ALIVE ]] && KEEP_ALIVE=30 +elif [ "$ENVIRONMENT" == 'staging' ] +then + # Staging environment + [[ -z $LOG_LEVEL ]] && LOG_LEVEL=debug + [[ -z $TIMEOUT ]] && TIMEOUT=30 + [[ -z $KEEP_ALIVE ]] && KEEP_ALIVE=30 else # All other environments [[ -z $LOG_LEVEL ]] && LOG_LEVEL=info @@ -111,6 +111,22 @@ else [[ -z $KEEP_ALIVE ]] && KEEP_ALIVE=5 fi +# Check for SSL certificates +if [ ! -f "/home/app/ssl/key.pem" ] +then + echo "/home/app/ssl/key.pem does not exist"; + exit 1 +fi + +if [ ! -f "/home/app/ssl/cert.pem" ] +then + echo "/home/app/ssl/cert.pem does not exist"; + exit 1 +fi + +# Ensure the SSL key file can be read +chmod 644 /home/app/ssl/key.pem + # Start the server echo "Starting $ENVIRONMENT server" -poetry run gunicorn "$APPLICATION" --workers "$WORKERS" --threads "$THREADS" --log-level "$LOG_LEVEL" --timeout "$TIMEOUT" --keep-alive "$KEEP_ALIVE" --access-logfile - --bind 0.0.0.0:8080 --worker-class="$WORKER_CLASS" +poetry run gunicorn "$APPLICATION" --workers "$WORKERS" --threads "$THREADS" --log-level "$LOG_LEVEL" --timeout "$TIMEOUT" --keep-alive "$KEEP_ALIVE" --access-logfile - --bind 0.0.0.0:8080 --worker-class="$WORKER_CLASS" --keyfile=/home/app/ssl/key.pem --certfile=/home/app/ssl/cert.pem diff --git a/docker/tna-python/lib/nginx.conf b/docker/tna-python/lib/nginx.conf deleted file mode 100644 index 08ed155..0000000 --- a/docker/tna-python/lib/nginx.conf +++ /dev/null @@ -1,49 +0,0 @@ -worker_processes auto; -# pid /run/nginx.pid; -error_log /var/log/nginx/error.log; - -events { - worker_connections 768; -} - -http { - sendfile on; - tcp_nopush on; - types_hash_max_size 2048; - - include /etc/nginx/mime.types; - default_type application/octet-stream; - - ssl_protocols TLSv1.3; - ssl_prefer_server_ciphers off; - - access_log /var/log/nginx/access.log; - - server { - listen 443 ssl; - listen [::]:443 ssl; - # http2 on; # Diabled until Debian has a version of nginx >=1.25.1 that supports this syntax - - ssl_certificate /etc/nginx/ssl/req.pem; - ssl_certificate_key /etc/nginx/ssl/key.pem; - ssl_session_timeout 1d; - ssl_session_cache shared:MozSSL:10m; # about 40000 sessions - - location / { - proxy_pass http://localhost:8080; - proxy_redirect off; - # proxy_redirect http://localhost:8080/ $scheme://$http_host/; - proxy_set_header Host $host; - # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-For $remote_addr; - # proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Real-IP $remote_addr; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - # proxy_set_header Connection $connection_upgrade; - proxy_read_timeout 20d; - proxy_buffering off; - } - } -} \ No newline at end of file