Skip to content

Public Nginx Server on Ubuntu

Purpose

This guide describes installing and configuring Nginx on an Ubuntu 22.04 or 24.04 server to host static websites on the public Internet.

The sites are secured using SSL/TLS with LetsEncrypt as the Certificate Authority.

GoAccess will be used to produce utilization statistics for each hosted site.


Requirements

To complete this guide, you'll need:

  • an Ubuntu 22.04 or 24.04 instance running on the public Internet
  • a static IP address for each hosted site. each site can have multiple DNS names
  • control over the DNS resource records for the names your site(s) will use
  • ssh access to the system
  • root or sudo access

Procedure

DNS Configuration

This guide will show how to set up a website that is available at mysite.com and www.mysite.com.

Log into your DNS provider and set up A record for your domain name that points to the IP address on which you will be hosting your site.

mydomain.com. A --> 42.33.8.62

Create a second record of type CNAME that maps the 'www' hostname to your domain name.

www.mydomain.com. CNAME --> mydomain.com.

You should be able to resolve the domain name and the hostname from your local machine and get the correct IP address.

> host mydomain.com
mydomain.com has address 42.33.8.62

> host www.mydomain.com
www.mydomain.com is an alias for mydomain.com.
mydomain.com has address 42.33.8.62

Configure Firewall

If you are using Ubuntu's UFW as a firewall, allow ingress connections on ports tcp/80 (HTTP) and tcp/443 (HTTPS).

Determine if UFW is active:

root@www:~ # ufw status
Status: active

If it's active, allow traffic to the system on HTTP and HTTPS ports:

ufw allow http
ufw allow https

View the UFW ruleset to ensure your rules were applied:

root@www:~ # ufw status
Status: active

To                         Action      From
--                         ------      ----
22/tcp                     ALLOW       Anywhere
Nginx Full                 ALLOW       Anywhere
443                        ALLOW       Anywhere
22/tcp (v6)                ALLOW       Anywhere (v6)
Nginx Full (v6)            ALLOW       Anywhere (v6)
443 (v6)                   ALLOW       Anywhere (v6)

Install Nginx

The operating system's repositories include Nginx. Install it by running apt:

apt -y install nginx

The Nginx configuration file is /etc/nginx/nginx.conf. Don't edit this file, or when apt upgrade is run, differences will be complained about when Nginx is upgraded. Instead of editing the file directly, add new configuration options and overrides to /etc/nginx/conf.d/myconfig.conf. Usually, leaving all of the defaults is fine.

Website configuration files for Nginx on Ubuntu are in /etc/nginx/sites-available/. To enable a site, create a symlink to it in /etc/nginx/sites-enabled/. For example:

ln -s /etc/nginx/sites-available/www.mysite.com /etc/nginx/sites-enabled/www.mysite.com

Restart Nginx after changing configuration parameters to pick up the changes:

systemctl restart nginx

Disable Log Rotation

Ubuntu's Nginx package installs a log rotation script that rolls and compresses logs daily. Disable this by backing up the file that rotates the Nginx logs:

mkdir /etc/logrotate.d/_disabled
mv /etc/logrotate.d/nginx /etc/logrotate.d/_disabled/

Disable Default Site

Nginx ships with a default "Hello World!" site. Disable this by deleting the symlink in /etc/nginx/sites-enabled/ and restart Nginx to pick up the changes:

# disable the default site
rm -f /etc/nginx/sites-enabled/default

# restart nginx
systemctl restart nginx

Install Site Data

Nginx expects each hosted site maps to a directory on the filesystem. Multiple names can map to a site.

In this example, mysite.com and www.mysite.com will both serve the same website. Both names will be served from a single directory on the filesystem.


Create Webroot

Do not put websites in directories like /home/ or under them. Create a directory under the root of the filesystem named 'webroot' to store the site data in:

mkdir /webroot

Create Website Directories and Users

Each hosted site's data will be contained in a sub-directory under /webroot/.

Create the directory that will hold the website data for the hosted site:

mkdir /webroot/www.mysite.com

Upload Data and Set Ownership

Change the ownership of the website container directory if a non-root user should be able to update the website data:

chown -R someuser:somegroup /webroot/www.mysite.com

Upload the website data to the server's directory using rsync over ssh or whatever method you are comfortable with:

# on local system
cd path/to/website-data

# upload data to webroot
rsync -e ssh -avP --delete .  [email protected]:/webroot/www.mysite.com/

Write Nginx Configs

Configure Nginx to host the website.

If you are adding a new website to an existing Nginx server, ensure your site's IP address is unique and not being used to host other sites on the server.

Create a new file named /etc/nginx/sites-available/www.mysite.com with the contents:

server {
    server_name  mysite.com www.mysite.com;
    root         /webroot/www.mysite.com;
    listen       42.33.8.62:80;
    access_log   /var/log/nginx/www.mysite.com_access.log;
    error_log    /var/log/nginx/www.mysite.com_error.log;
    error_page   500 502 503 504  /50x.html;
}

Enable the site's configuration by creating a symlink in /etc/nginx/sites-enabled/:

ln -s /etc/nginx/sites-available/www.mysite.com /etc/nginx/sites-enabled/www.mysite.com

Restart Nginx to pick up the configuration changes:

systemctl restart nginx

Testing with No SSL/TLS

You should now be able to reach your site using HTTP.

Tail your website's Nginx logs to verify Nginx is serving your requests and that there are no errors:

tail -f /var/log/nginx/www.mysite.com_*

Secure Site(s) with SSL/TLS

Install Certbot

Certbot is the EFF's tool to interact with the free SSL/TLS provider LetsEncrypt.

LetsEncrypt provides free SSL certificates to publicly accessible websites.

Install Certbot from Ubuntu's repositories:

apt update && \
apt install certbot

Secure a Site with LetsEncrypt

Run Certbot in a shell as the root user to request an SSL certificate from LetsEncrypt:

certbot --nginx -d mysite.com -d www.mysite.com

Answer any questions the script asks you. Note the expiration date of the newly signed certificate for your site.

Re-run the command to request an updated certificate within a month of its expiration.

Once complete, your Nginx configuration file for your site in /etc/nginx/sites-enabled/www.mysite.com will have modifications that enables HTTPS and rewrites HTTP requests to HTTPS.

Restart Nginx to pick up the changes:

systemctl restart nginx

Testing with SSL/TLS

Your site should be available via HTTPS. Accessing your site via HTTP should rewrite the request to HTTPS. If Nginx doesn't rewrite HTTP to HTTPS requests for your site, ensure these lines exist in your site's configuration file in /etc/nginx/sites-available/www.mysite.com:

server {
    if ($host = www.mysite.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot

    if ($host = mysite.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot

Website Statistics

Install GoAccess

GoAccess is a nice and clean website statistics generator.

Install it by running:

apt -y install goaccess

Configure GoAccess

GoAccess's configuration file is /etc/goaccess/goaccess.conf, but this can be left alone. The default values work well enough.

GoAccess is run for each hosted site. It reads in the website's logfile and produces a static HTML report. The report will be written to _report/ in the website's webroot. Go to www.mysite.com/_report/ to access it.

To run GoAccess on a single site, run:

# make sure the report dir exists
mkdir /webroot/www.mysite.com/_report

# run goaccess on the site's log file
goaccess /var/log/www.mysite.com --log-format=COMBINED \
 -o /webroot/www.mysite.com/_report/index.html

If multiple sites are being hosted, loop through each one in a bash script:

#!/usr/bin/env bash

DATE=$(date '+%Y%m%d')
LOGDIR=/var/log/nginx

# a list of dirs in /webroot
SITES='www.mysite.com www.otherhostedsite.com'

for SITE in ${SITES[@]}; do
    OUTDIR=/webroot/${SITE}/_reports
    goaccess ${LOGDIR}/${SITE}_access.log --log-format=COMBINED -o ${OUTDIR}/${SITE}.html;
done

Reports will be written to the hosted site's base URL with /_report added to it. Adjust as needed.


Cron Jobs for GoAccess

Make cron run the report script at the top of every hour.

If there is only a single hosted site, add a file named /etc/cron.d/update-webstats with the contents:

# run webstats for www.mysite.com
0 * * * * root /usr/sbin/goaccess /var/log/nginx/www.mysite.com --log-format=COMBINED -o /webroot/www.mysite.com/_report/index.html

If there are multiple hosted sites, save the script above into /root/bin/update-webstats.sh, set it executable with chmod +x /root/bin/update-webstats.sh, and add a file named /etc/cron.d/update-webstats with the contents:

# run webstats for all hosted sites
0 * * * * root /root/bin/update-webstats.sh