9.7 KiB
Static Server with NGINX
NGINX is a very powerful web server. You can do a ton of things with it, such as setting up reverse proxies or load balancing. It can also be used to host your static website.
Installation
Install the NGINX package
sudo apt update
sudo apt install nginx
Install from source
sudo apt install build-essential libpcre3 libpcre3-dev zlib1g zlib1g-dev libssl-dev libgd-dev libxml2 libxml2-dev uuid-dev -y
wget http://nginx.org/download/nginx-1.21.4.tar.gz
tar -zxvf nginx-1.21.4.tar.gz
sudo rm -r nginx-1.21.4.tar.gz
git clone https://github.com/GetPageSpeed/ngx_security_headers.git
cd nginx-1.21.4
./configure --prefix=/var/www/html \
--sbin-path=/usr/sbin/nginx \
--conf-path=/etc/nginx/nginx.conf \
--http-log-path=/var/log/nginx/access.log \
--error-log-path=/var/log/nginx/error.log \
--with-pcre \
--lock-path=/var/lock/nginx.lock \
--pid-path=/var/run/nginx.pid \
--with-http_ssl_module \
--with-http_image_filter_module=dynamic \
--modules-path=/etc/nginx/modules \
--with-http_v2_module \
--with-stream=dynamic \
--with-http_addition_module \
--with-http_mp4_module \
--add-module=../ngx_security_headers
make
make install
Move your website’s static files to the server
By default, NGINX expects your static files to be in a specific directory. You can override this in the configuration. Defaults assume that you’ll be putting your website’s static files in the /var/www/
directory.
Hint: consists of the domain name and domain extension, e.g. example.com
Create a directory in /var/www/
names as you like. This is where your static website’s files will go.
sudo mkdir /var/www/<websitename>
Copy or create your website’s static files into that folder. cd into your website’s directory and run:
# creating files
touch /var/www/<mywebsite>/index.html
sudo nano /var/www/<mywebsite>/index.html
# copy/move files
cp ./index.html /var/www/<mywebsite>/
mv ./index.html /var/www/<mywebsite>/
# safe copy to network destination
scp -r * <username>@<ip>:/var/www/<mywebsite>
Configure NGINX to serve your website
The NGINX configuration files are located at /etc/nginx/
. We need to tell NGINX about the website and how to serve it.
The two directories we are interested in are sites-available and sites-enabled.
sites-available
contains individual configuration files for all possible static websitessites-enabled
contains links to the configuration files that NGINX will actually read and run
To enable a website, we create a configuration file in sites-available
and create a symbolic link of that file in sites-enabled
to tell NGINX to run it.
sudo nano /etc/nginx/sites-available/<mywebsite>
Add the following text to it
server {
listen 80 default_server;
listen [::]:80 default_server;
root /var/www/<mywebsite>;
index index.html;
server_name <mywebsite> www.<mywebsite>;
location / {
try_files $uri $uri/ =404;
}
}
This file tells NGINX several things:
- Deliver files from the folder
/var/www/<mywebsite>
- The main index page is called
index.html
- Requests that are requesting
<mywebsite>
should be served by this server block - Note the www is also listed separately. This tells nginx to also route requests starting with www to the site. There’s actually nothing special about the www — it’s treated like any other subdomain
Now that the file is created, we’ll add it to the sites-enabled folder to tell NGINX to enable it.
# use like: ln -s <SOURCE_FILE> <DESTINATION_FILE>
ln -s /etc/nginx/sites-available/<mywebsite> /etc/nginx/sites-enabled/<mywebsite>
Now restart NGINX and you should see your site at your localhost port
sudo systemctl restart nginx
If it gives you an error, there’s likely a syntax error.
Enable HTTPS
With free SSL certs from LetsEncrypt, you can enable HTTPS for your website. In addition to the improved security, there’s significant performance opportunities it allows via HTTP/2, you’ll increase user confidence and you’ll even rank higher in SEO.
Acquire an SSL cert
There’s multiple ways to do this. You can buy a single-domain certification or a wildcard certification if you plan on securing subdomains.
You can also go the free route via LetsEncrypt:
sudo apt-get install software-properties-common
sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install python-certbot-nginx
sudo certbot --nginx certonly
Follow the instructions. This will install certs in /etc/letsencrypt/live/<mywebsite>/
To enable auto-renewal for certificates, edit the crontab and create a CRON job to run the renewal command:
sudo crontab -e
And add the following line:
17 7 * * * certbot renew --post-hook "systemctl reload nginx"
Tell NGINX to use the SSL cert
Modify the configuration file created before. Add the following text, changing the paths to point to the certificate file and the key file (usually stored in/etc/nginx/certs/
):
server {
# ...previous content
ssl on;
ssl_certificate /etc/letsencrypt/live/<mywebsite>/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/<mywebsite>/privkey.pem;
A problem now occurs as port 80 was used for HTTP no longer of use as HTTPS uses port 443. Change that in the configuration
server {
listen 443 default_server;
listen [::]:443 default_server;
#... all other content
}
As this will prevent people to access your page over HTTP we need to redirect HTTP requests to HTTPS. Add the following code after the HTTPS server code into your configuration file of the webpage
server {
listen 0.0.0.0:80;
server_name <mywebsite> www.<mywebsite>;
rewrite ^ https://$host$request_uri? permanent;
}
This will redirect all requests to and www. on port 80 to the HTTPS URL on port 443.
Restart NGINX to make the changes happen: sudo systemctl restart nginx
Test the configuration by going to the four variations of the URL, eg.:
- http://
- https://
- http://www.
- https://www.
They should all work and be secured via HTTPS.
Improve performance
Enable HTTP/2
HTTP/2 allows browsers to request files in parallel, greatly improving the speed of delivery. We need HTTPS enabled. Edit the browser configuration file, adding http2 to the listen directive, then restart NGINX:
server {
listen 443 http2 default_server;
listen [::]:443 http2 default_server;
#... all other content
}
Enable client-side caching
Some files never change or change rarely, so users can prevent re-download too often. Set the cache control headers to provide hints to browsers to let those know what files they shouldn’t request again.
server {
#...after the location / block
location ~* \.(jpg|jpeg|png|gif|ico)$ {
expires 30d;
}
location ~* \.(css|js)$ {
expires 7d;
}
}
Set the times after own experience.
Dynamically route subdomains
In the case of subdomains, you may not want to route every subdomain to the correct folder. Create a wildcard server to route matching names. Edit your website configuration therefore:
server {
server_name ~^(www\.)(?<subdomain>.+).<mywebsite>$ ;
root /var/www/<mywebsite>/$subdomain;
}
server {
server_name ~^(?<subdomain>.+).<mywebsite>$ ;
root /var/www/<mywebsite>/$subdomain;
}
Restart NGINX and route subdomains automatically to the same-named subfolder.
remove the Server header
Security through obscurity isn’t the holy grail that will make any website secure completely. But as a complementary security measure, it can be used.
NGINX, by default, sends information about its use in the Server HTTP header as well as error pages, e.g.: nginx/1.16.1.
To confirm the currently emitted header, run curl -IsL https://example.com/ | grep -i server
hide version information
The standard security solution is hiding NGINX version information. In the /etc/nginx/nginx.conf
:
http {
...
server_tokens off;
...
}
This only hides the specific version of NGINX from the Server header and error pages.
The header becomes: Server: nginx
hide server header
using ngx_security_headers module
Easiest method is using the package made to extend NGINX:
sudo apt install nginx-module-security-headers
Edit the nginx.conf
like:
load_module modules/ngx_http_security_headers_module.so;
http {
...
hide_server_tokens on;
...
}
Now the Server header is completely eliminated from the responses.
using Headers More module
Another module to use is:
sudo apt install nginx-module-headers-more
Edit the nginx.conf
like:
load_module modules/ngx_http_headers_more_filter_module.so;
http {
...
more_clear_headers Server;
...
}
Likewise, the Server header will be completely gone from the responses.
hide the use of NGINX
Hiding the Server header is good but the default error pages by NGINX still output the "nginx" word in them.
An easy way to complete hiding of NGINX presence on the server is using NGINX-MOD.
Simply specify the following in the configuration: server_tokens none;
Alternatively hide the NGINX presence by recompiling it from the source (highly discouraged, see common pitfalls). Adjust NGINX sources to prevent the information disclosure of NGINX software.
sed -i 's@"nginx/"@"-/"@g' src/core/nginx.h
sed -i 's@r->headers_out.server == NULL@0@g' src/http/ngx_http_header_filter_module.c
sed -i 's@r->headers_out.server == NULL@0@g' src/http/v2/ngx_http_v2_filter_module.c
sed -i 's@<hr><center>nginx</center>@@g' src/http/ngx_http_special_response.c
Then recompile NGINX.