What #
Nginx is an HTTP web server, reverse proxy, content cache, load balancer, TCP/UDP proxy server, and mail proxy server.
Why #
- Serving static content
- Reverse proxy: Sends incoming requests to the appropriate backend server
- SSL/TLS termination: relieves backend server of dealing with encryption and decoding
- Load balancing
- Caching
How #
Folder layout:
nginx
├── conf
│ ├── certs
│ │ ├── create_certs.sh
│ │ ├── dhparam.pem
│ │ ├── nginx-selfsigned.crt
│ │ ├── nginx-selfsigned.key
│ │ ├── self-signed.conf
│ │ └── ssl-params.conf
│ ├── conf.d
│ │ ├── api-proxy.conf
│ │ └── default.conf
│ ├── streams
│ │ └── reverse-ssh.conf
│ └── nginx.conf
├── test-app
| ├── www
| │ ├── test
| │ │ └── test.html
| │ ├── app.js
| │ └── index.html
| ├── app
| │ ├── index.js
| │ ├── package.json
| │ └── package-lock.json
└── docker-compose-nginx.yaml
docker-compose-nginx.yaml
: docker compose fileconf/nginx.conf
: general configurationconf/certs/
: certificates folderconf/conf.d/
: server configurationsconf/streams/
: streams configurationstest-app/
: application example
docker-compose-nginx.yaml #
Base image: nginx
services:
nginx:
image: nginx:1.27.3-alpine
container_name: nginx
ports:
- 80:80
- 443:443
- 9122:9122
volumes:
- ./conf/nginx.conf:/etc/nginx/nginx.conf
- ./conf/conf.d:/etc/nginx/conf.d
- ./conf/streams:/etc/nginx/streams
- ./conf/certs:/etc/nginx/certs
- ./test-app/www:/etc/nginx/www
extra_hosts:
- "host.docker.internal:host-gateway"
restart: always
extra-hosts
allows the container to access localhost ashost.docker.internal
./conf/nginx.conf #
General nginx configuration file:
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
stream {
include /etc/nginx/streams/*.conf; # streams configuration here
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf; # servers configuration here
}
Specific include
folders for streams
and http
configurations
./conf/certs #
SSL/TLS configuration and setup
Generate (self-signed) certificates #
to generate certificates with
certbot
see this certbot
Create key and certificate and store them in ./conf/certs
folder
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout ./conf/certs/nginx-selfsigned.key -out ./conf/certs/nginx-selfsigned.crt
This command will generate the following files:
./conf/certs/nginx-selfsigned.key
./conf/certs/nginx-selfsigned.crt
Generate DH params to increase SSL/TLS security on the server:
openssl dhparam -out ./conf/certs/dhparam.pem 2048
Generate self-signed certificates #
Create key and certificate and store them in ./conf/certs
folder
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout ./conf/certs/nginx-selfsigned.key -out ./conf/certs/nginx-selfsigned.crt
Generate DH params to increase SSL/TLS security on the server:
openssl dhparam -out ./conf/certs/dhparam.pem 2048
Nginx configuration files #
- Certificates configuration: `./conf/self-signed.conf
ssl_certificate /etc/nginx/certs/nginx-selfsigned.crt;
ssl_certificate_key /etc/nginx/certs/nginx-selfsigned.key;
- Configuration for SSL options in nginx:
./conf/ssl-params.conf
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
ssl_ecdh_curve secp384r1;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
# Disable preloading HSTS for now. You can use the commented out header line that includes
# the "preload" directive if you understand the implications.
#add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
ssl_dhparam /etc/nginx/certs/dhparam.pem;
./conf/conf.d #
This folder hold specific servers configuration files.
Services diagram
Automatic redirection to SSL port: ./conf/conf.d/default.conf
server {
listen 80;
server_name localhost;
return 301 https://$host$request_uri;
}
http://nginx-server -> https:/nginx-server
Example file: ./conf/conf.d/api-proxy.conf
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name localhost; #your server name here
include /etc/nginx/certs/self-signed.conf;
include /etc/nginx/certs/ssl-params.conf;
location / {
proxy_pass http://host.docker.internal:1313;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /app {
alias /etc/nginx/www; # your public folder
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
location ^~ /api {
rewrite /api/(.*) /$1 break;
proxy_pass http://host.docker.internal:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
location /
: https://nginx-server -> http://localhost:1313location /app
: https://nginx-server/app -> file://test-app/wwwlocation ^~ /api
: https://nginx-server/api -> http://locahost:5000
./conf/streams #
This folder hold specific streams configuration files.
Example file: ./conf/streams/reverse-ssh.conf
listen 9122;
proxy_pass host.docker.internal:22;
./test-app #
Quick setup for test application.
test-app
├── www
│ ├── test
│ │ └── test.html
│ ├── app.js
│ └── index.html
├── app
│ ├── index.js
│ ├── package.json
│ └── package-lock.json
./www/
: Frontend static resources./app/
: REST API Server
Rest Api
./app/index.js
const express = require("express"); //require express
const app = express(); //create the app
app.get("/v1/products", (req, res) => {
let products = [
{
name: "prod1",
price: 10
},
{
name: "prod2",
price: 20
},
{
name: "prod3",
price: 30
},
]
res.send(JSON.stringify(products)); //responding to the request
});// send a response to the client
app.listen(5000, () => {
console.log("App has started and running ");
}); // listen for connection to the app
Run server:
npm install
node index.js
Frontend
www/index.html
<html>
<body>
<h1 class="description">Main App UI</h1>
<div id="template"></div>
<div id="container">
<button id="fetch">Invoke API</button>
</div>
<script src="app.js"></script>
</body>
</html>
www/app.js
const myButton = document.getElementById('fetch');
myButton.addEventListener('click', fetchInfo);
function fetchInfo () {
fetch('https://localhost/api/v1/products')
.then(response => response.json())
.then(jsonObj => displayUi(jsonObj))
.catch(() => alert('API Could not be reached at this time'))
}
function displayUi (products) {
let template = ""
for (const p of products){
template += `<div><b> ${p.name}</b>: ${p.price}</div>`
}
document.getElementById('template').innerHTML = template
}
Run frontend through nginx:
https://nginx-server/app
Run fronted from express.js
:
http://localhost:5000