Nginx Letsencrypt, Django and Minio

To create the secure and low cost prototype in order to do PoC(Proof of Concept) I got an order from my boss(Sivabudh U.) to install and setup

  1. Get certificate from letsencrypt
  2. Nginx with https
  3. Minio under Nginx

Get certificate from Letsencrypt is somewhat complicated.

The mechanic under the hood is Letsencrypt server will come to your server with specific DNS and URL. Your server will response with generated token. Then the verification is done.

user www-data;
worker_processes auto;
pid /run/;
events {
worker_connections 768;
# multi_accept on;
http {
# Basic Settings
client_max_body_size 15M;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# server_tokens off;
# server_names_hash_bucket_size 64;
# server_name_in_redirect off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
# SSL Settings
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on;
# Logging Settings
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
# Gzip Settings
gzip on;
gzip_disable "msie6";
# gzip_vary on;
# gzip_proxied any;
# gzip_comp_level 6;
# gzip_buffers 16 8k;
# gzip_http_version 1.1;
# gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
# Virtual Host Configs
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;

This is conventional setup on basic server. You will have to fine tune to fit for your need.

Next configure our connection channel for Letsencrypt server request

server {
listen 80;
root /var/www/html/
location ~ /.well-known {
allow all;

Next is preparing the ./well-known directory. Create it with mkdir and chmod 777 to it.

This step I will install the certbot

apt-get install software-properties-common
add-apt-repository ppa:certbot/certbot
apt-get update
apt-get install python-certbot-nginx
cd /var/www/html/.well-known/
certbot —-nginx
certbot certonly —-webroot —-webroot-path=/var/www/html -d

At this step I assume you have no problem with firewall. Then certificates are in server now.

ls -alh /etc/letsencrypt/live/
total 12K
drwxr-xr-x 2 root root 4.0K Jun 8 14:17 .
drwx------ 3 root root 4.0K Jun 8 14:17 ..
-rw-r--r-- 1 root root 543 Jun 8 14:17 README
lrwxrwxrwx 1 root root 41 Jun 8 14:17 cert.pem -> ../../archive/
lrwxrwxrwx 1 root root 42 Jun 8 14:17 chain.pem -> ../../archive/
lrwxrwxrwx 1 root root 46 Jun 8 14:17 fullchain.pem -> ../../archive/
lrwxrwxrwx 1 root root 44 Jun 8 14:17 privkey.pem -> ../../archive/

The certificates are ready. Change the nginx to ssl version

upstream app {
server localhost:8000;
upstream minio {
server localhost:9000;

server {
listen 80;
return 301 https://$server_name$request_uri;

server {
listen 443 ssl;

add_header Strict-Transport-Security "max-age=31536000";
ssl_certificate /etc/letsencrypt/live/;
ssl_certificate_key /etc/letsencrypt/live/;

location / {
proxy_pass_request_headers on;
proxy_set_header Host $host;
proxy_pass http://app;

location /static {
proxy_buffering off;
proxy_set_header Host $http_host;
proxy_pass http://minio;

location /media {
proxy_buffering off;
proxy_set_header Host $http_host;
proxy_pass http://minio;

location ~ /.well-known {
allow all;

Whew…. It is not done yet!

Because when you put Reverse Proxy in front of your internal servers. You need to change inbound Headers too

Running minio server on http port 9000

minio server /media

Django server on http port 8000. I use `django-minio-storage` as a minio driver. I will skip installation step of this driver.

If you have experience with minio before you will realize that MINIO_STORAGE_ENPOINT on http normally has scheme then my value supposed to be .Right, but we have reverse proxy in front of us already

If you use Django Form You will have a difficulties with CSRF token too!



Thanks to Sivabudh U that support on getting `certificates`

One month passed Letsencrypt and Nginx-ssl also gone from my head, and on part of minio inbound header will cause me an hour on it.

If you found unclear or outdated on my article please raise.