A lightweight, pre-configured nginx container with HTTP 2.0, TLS1.3 and SSL Labs A rating
- Built on the lightweight and secure Alpine Linux distribution
- Very small Docker image size (+/- 8MB)
- Optimized for rapid delivery of static content and proxied content from downstream web applications.
- Secure configuration with pre-configured, optimized TLS settings
- Pre-defined DSGVO-compliant log rotation settings with 7-day retention of access logs.
Nginx is a web server which can also be used as a reverse proxy, load balancer, mail proxy and HTTP cache. (Wikipedia)
With this image you get a preconfigured nginx image. This image provides support for TLS 1.3 and HTTP 2.0.
A secure TLS protected server is started without having to change the configuration. A self-signed certificate is created for this purpose. SSL Labs rates the configuration with an A.
The easiest way to start the server is the following command.
docker run -d -p 80:80 -p 443:443 jschnabel/nginx
You can also use docker-compose.
services:
nginx:
image: jschnabel/nginx
container_name: nginx
ports:
- 80:80
- 443:443
If now the IP address or domain is accessed with the browser, the test page should be visible.
To be able to host your own content, just mount a directory under /media/data/webroot
.
services:
nginx:
image: jschnabel/nginx
container_name: nginx
ports:
- 80:80
- 443:443
volumes:
- /media/docker/volumes/nginx/webroot:/media/data/webroot
In this example all data from the host directory /media/docker/volumes/nginx/webroot
will be published as content.
The configuration shown above will cause a warning window in all browsers. This is due to the self-signed certificate. To get a free certificate from Let's Encrypt you have to do the following. First the certbot must be installed on the host. Then a certificate can be created using the command below. Please make sure that a directory is mounted by the host as webroot.
acme.sh --issue -d <your.domain> --cert-file /media/docker/volumes/nginx/webroot/cert.pem --key-file /media/docker/volumes/nginx/webroot/key.pem --fullchain-file /media/docker/volumes/nginx/webroot/fullchain.pem --reloadcmd "docker restart nginx"
The program will create the following files.
/media/docker/volumes/nginx/webroot/cert.pem
/media/docker/volumes/nginx/webroot/key.pem
/media/docker/volumes/nginx/webroot/fullchain.pem
Now the certificate and the private key have to be mounted.
services:
nginx:
image: jschnabel/nginx
container_name: nginx
ports:
- 80:80
- 443:443
volumes:
- /media/docker/volumes/nginx/webroot:/media/data/webroot
- /etc/letsencrypt/live/<your.domain>/fullchain.pem:/media/data/certs/default_cert.pem:ro
- /etc/letsencrypt/live/<your.domain>/privkey.pem:/media/data/certs/default_key.pem:ro
certbot certonly --webroot --webroot-path /media/docker/volumes/nginx/webroot --rsa-key-size 4096 --renew-by-default -d <your.domain>
The program will create the following files.
/etc/letsencrypt/live/<your.domain>/fullchain.pem
/etc/letsencrypt/live/<your.domain>/privkey.pem
Now the certificate and the private key have to be mounted.
services:
nginx:
image: jschnabel/nginx
container_name: nginx
ports:
- 80:80
- 443:443
volumes:
- /media/docker/volumes/nginx/webroot:/media/data/webroot
- /etc/letsencrypt/live/<your.domain>/fullchain.pem:/media/data/certs/default_cert.pem:ro
- /etc/letsencrypt/live/<your.domain>/privkey.pem:/media/data/certs/default_key.pem:ro
In order to provide own configurations, these must be simply mounted under the directory /media/data/sites-enabled
.
All configurations from this directory are activated. In this way several domains can be configured.
services:
nginx:
image: jschnabel/nginx
container_name: nginx
ports:
- 80:80
- 443:443
volumes:
- /media/docker/volumes/nginx/webroot:/media/data/webroot
- /etc/letsencrypt/live/<your.domain>/fullchain.pem:/media/data/certs/default_cert.pem:ro
- /etc/letsencrypt/live/<your.domain>/privkey.pem:/media/data/certs/default_key.pem:ro
- /media/docker/volumes/nginx/sites:/media/data/sites-enabled
- /media/docker/volumes/nginx/streams:/media/data/streams
A custom site configuration could look like this. It should be mounted to media/data/sites-enabled
.
server {
listen 80;
listen [::]:80;
server_name <your.domain>;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name <your.domain>;
ssl_certificate /media/data/certs/<your.domain>.pem;
ssl_certificate_key /media/data/certs/<your.domain>.pem;
include /media/data/snippets/gzip.conf;
include /media/data/snippets/header.conf;
include /media/data/snippets/tls.conf;
location / {
root /media/data/webroot/<your.domain>;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /media/data/webroot/<your.domain>;
}
}
A custom stream configuration could look like this. It should be mounted to media/data/streams
.
stream {
upstream mqtt {
server mosquitto:1883;
}
server {
listen 8883 ssl;
proxy_pass mqtt;
ssl_certificate /media/data/certs/default_cert.pem;
ssl_certificate_key /media/data/certs/default_key.pem;
include /media/data/snippets/tls_stream.conf;
}
server {
listen 1883;
proxy_pass mqtt;
}
}
This image also includes a configuration for Basic-Auth authentication. This can be added as follows.
location / {
include /media/data/snippets/basic_auth.conf;
root /media/data/webroot/<your.domain>;
index index.html index.htm;
}
To add a user, the following command can be used.
docker exec -it nginx_proxy /media/data/scripts/addUser.sh /media/data/passwords/htpasswd
There is also a configuration for a WebDav share. It is recommended that such a share is secured by authentication.
location / {
include /media/data/snippets/basic_auth.conf;
include /media/data/snippets/webdav.conf;
}
The log files (error and access log) are stored under /media/data/logs
by default. This directory can be mounted for external processing of the log files.
If you want a better grade at SSL Labs, the following things have to be done.
To get a 100% rating in the Key Exchange category it is necessary to use a 4096 bit RSA certificate or an ECDSA certificate with ECDSA P-384 or ECDSA P-521.
With acme.sh you can create such a certificate with 4096 bit RSA if you add the following parameter to the command.
acme.sh --issue --keylength 4096 ..."
To get an ECDSA P-384 certificate the command must be modified as follows.
acme.sh --issue --ecc --keylength ec-384 ..."
Certbot currently does not support ECDSA certificates. However a 4096 bit RSA can be created. Therefore the key length has to be provided.
certbot certonly --rsa-key-size 4096 ...
To get 100% in this discipline no cipher suites with 128bit are allowed in the list of cipher suites. A snippet is provided for this purpose. This snippet must be included as shown in the configuration below.
WARNING: This will prevent very old clients from accessing your website (e.g. Java <= 7 or Android <= 6). If you expect clients that fall into this category, I advise against using them.
A custom site configuration could look like this. It should be mounted to media/data/sites-enabled
.
server {
listen 80;
listen [::]:80;
server_name <your.domain>;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name <your.domain>;
ssl_certificate /media/data/certs/<your.domain>.pem;
ssl_certificate_key /media/data/certs/<your.domain>.pem;
include /media/data/snippets/gzip.conf;
include /media/data/snippets/header.conf;
include /media/data/snippets/tls_strong.conf;
location / {
root /media/data/webroot/<your.domain>;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /media/data/webroot/<your.domain>;
}
}
Simply add an environment variable named DISABLETLS
to the container. The value must be true
.
services:
nginx:
image: jschnabel/nginx
container_name: nginx
environment:
- DISABLETLS="true"
ports:
- 80:80
volumes:
- /media/docker/volumes/nginx/webroot:/media/data/webroot