Swapping out Caddy for Nginx in CookieCutter-Django


The cokkiecutter django community is moving away from caddy because of it's licensing which evaluates to "Free for personal use". They are contemplating picking up Traefic and it is still in the works as of this moment.

I, while am interested in trying out Caddy and Traefic, do not wish to bring in new tech into my production code unless it is crucial for the product's success. Though with NginX, I need to wrangle with Certificate verification, it's a beast I have wrangled before. I have done custom compilations with extensions that were not in the core NginX and it had gone extremely well and still serving files for my past projects without any issues.

So I would prefer to stick with the tried and tested NginX. This post details my Operation NginX.

So these are the steps as I see it.

  • Pick a reliable source of docker nginx image.
  • Ensure modules that I need are there, pagespeed, gzip etc
  • Setup let's encrypt certificate
  • Setup renewal.
  • Setup the config to serve the files.

I zeroed in on OpenBridge's NginX "https://github.com/openbridge/nginx" as the base.

I am going to use this article "cookiecutter-django with Nginx, Route 53 and ELB" by Martin Saizar as reference

Let use the Nginx Docker image as provided by the nginx team. Here we are mounting some folders and files for docroot, logs, default site conf etc. The default site conf is located at /etc/nginx/conf.d/default

Add the following to your production.yml

 nginx:
   image: nginx
   restart: always
   ulimits:
     nproc: 65535
     nofile:
         soft: 49999
         hard: 65535
   volumes:
           - /some/path/www/html:/usr/share/nginx/html
           - /some/path/log:/var/log/nginx
           - /some/path/compose/production/nginx/sites-enabled/sitefitnesshq.conf:/etc/nginx/conf.d/default.conf
           - /etc/letsencrypt/live/yourdomain.com/fullchain.pem:/etc/letsencrypt/live/yourdomain.com/fullchain.pem
           - /etc/letsencrypt/live/yourdomain.com/privkey.pem:/etc/letsencrypt/live/yourdomain.com/privkey.pem
           - /etc/letsencrypt/live/yourdomain.com/chain.pem:/etc/letsencrypt/live/yourdomain.com/chain.pem
   ports:
     - "80:80"
     - "443:443"
   depends_on:
     - django
   deploy:
     restart_policy:
       condition: on-failure
       delay: 5s
       window: 60s

Now we need to obtain ssl certificates from Lets Encrypt to be used with Nginx. There are plenty of tutorials on line. One good resource is https://medium.com/@IgorYanovskiy/installing-the-letsencrypt-ssl-certificate-and-arranging-an-automatic-renewal-b770dafb72e7

At the end, you should have your certificates should be installed and accessible at /etc/letsencrypt/live/yourdomain.com

We also need to create the nginx conf file for your site. Besides setting up the conf, I am also setting up redirects from non-secure to secure and www to non-www.

in compose/production/nginx/yourdomain.conf

server {
listen 443 ssl;
server_name yourdomain.com;
charset utf-8;
ssl_stapling on;
ssl_stapling_verify on;

ssl_certificate           /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key       /etc/letsencrypt/live/yourdomain.com/privkey.pem;
ssl_trusted_certificate   /etc/letsencrypt/live/yourdomain.com/chain.pem;


set $my_host $http_host;
if ($http_host = "staging.yourdomain.com") {
      set $my_host "yourdomain.com";
}

location / {
    proxy_pass http://django:5000;
    proxy_set_header Host $my_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

} server { listen 80 ; server_name yourdomain.com; return 301 https://yourdomain.com$request_uri; } server { listen 80 ; server_name www.yourdomain.com; return 301 https://yourdomain.com$request_uri; } server { listen 443 ; server_name www.yourdomain.com; return 301 https://yourdomain.com$request_uri; ssl_stapling on; ssl_stapling_verify on;

    ssl_certificate           /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
    ssl_certificate_key       /etc/letsencrypt/live/yourdomain.com/privkey.pem;
    ssl_trusted_certificate   /etc/letsencrypt/live/yourdomain.com/chain.pem;

}

Now just build and run docker compose.

sudo docker-compose -f production.yml build && sudo docker-compose -f production.yml run

Another resource to help with ssl certificates: https://absolutecommerce.co.uk/auto-renew-letsencrypt-nginx-certbot
https://tmn.io/lets-encrypt-with-nginx-auto-renewal/