How I deployed this Website
I will describe the step-by-step process I followed to make this static website accessible on the Internet.
DNS
I bought this domain on NameCheap and am using their DNS for now, where I created these records:
Record Type | Host | Value |
---|---|---|
A | sergiocipriano.com | 201.54.0.17 |
CNAME | www | sergiocipriano.com |
Virtual Machine
I am using Magalu Cloud for hosting my VM, since employees have free credits.
Besides creating a VM with a public IP, I only needed to set up a Security Group with the following rules:
Type | Protocol | Port | Direction | CIDR |
---|---|---|---|---|
IPv4 / IPv6 | TCP | 80 | IN | Any IP |
IPv4 / IPv6 | TCP | 443 | IN | Any IP |
Firewall
The first thing I did in the VM was enabling ufw
(Uncomplicated Firewall).
Enabling ufw without pre-allowing SSH is a common pitfall and can lock you out of your VM. I did this once :)
A safe way to enable ufw:
$ sudo ufw allow OpenSSH # or: sudo ufw allow 22/tcp
$ sudo ufw allow 'Nginx Full' # or: sudo ufw allow 80,443/tcp
$ sudo ufw enable
To check if everything is ok, run:
$ sudo ufw status verbose
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip
To Action From
-- ------ ----
22/tcp (OpenSSH) ALLOW IN Anywhere
80,443/tcp (Nginx Full) ALLOW IN Anywhere
22/tcp (OpenSSH (v6)) ALLOW IN Anywhere (v6)
80,443/tcp (Nginx Full (v6)) ALLOW IN Anywhere (v6)
Reverse Proxy
I'm using Nginx as the reverse proxy. Since I use the Debian package, I just needed to add this file:
/etc/nginx/sites-enabled/sergiocipriano.com
with this content:
server {
listen 443 ssl; # IPv4
listen [::]:443 ssl; # IPv6
server_name sergiocipriano.com www.sergiocipriano.com;
root /path/to/website/sergiocipriano.com;
index index.html;
location / {
try_files $uri /index.html;
}
}
server {
listen 80;
listen [::]:80;
server_name sergiocipriano.com www.sergiocipriano.com;
# Redirect all HTTP traffic to HTTPS
return 301 https://$host$request_uri;
}
TLS
It's really easy to setup TLS thanks to Let's Encrypt:
$ sudo apt-get install certbot python3-certbot-nginx
$ sudo certbot install --cert-name sergiocipriano.com
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Deploying certificate
Successfully deployed certificate for sergiocipriano.com to /etc/nginx/sites-enabled/sergiocipriano.com
Successfully deployed certificate for www.sergiocipriano.com to /etc/nginx/sites-enabled/sergiocipriano.com
Certbot will edit the nginx configuration with the path to the certificate.
HTTP Security Headers
I decided to use wapiti, which is a web application vulnerability scanner, and the report found this problems:
- CSP is not set
- X-Frame-Options is not set
- X-XSS-Protection is not set
- X-Content-Type-Options is not set
- Strict-Transport-Security is not set
I'll explain one by one:
- The Content-Security-Policy header prevents XSS and data injection by restricting sources of scripts, images, styles, etc.
- The X-Frame-Options header prevents a website from being embedded in iframes (clickjacking).
- The X-XSS-Protection header is deprecated. It is recommended that CSP is used instead of XSS filtering.
- The X-Content-Type-Options header stops MIME-type sniffing to prevent certain attacks.
- The Strict-Transport-Security header informs browsers that the host should only be accessed using HTTPS, and that any future attempts to access it using HTTP should automatically be upgraded to HTTPS. Additionally, on future connections to the host, the browser will not allow the user to bypass secure connection errors, such as an invalid certificate. HSTS identifies a host by its domain name only.
I added this security headers inside the HTTPS and HTTP server block, outside the location block, so they apply globally to all responses. Here's how the Nginx config look like:
add_header Content-Security-Policy "default-src 'self'; style-src 'self';" always;
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
I added always
to ensure that nginx sends the header
regardless of the response code.
To add Content-Security-Policy header I had to move the css to a separate file, because browsers block inline styles under strict CSP unless you allow them explicitly. They're considered unsafe inline unless you move to a separate file and link it like this:
<link rel="stylesheet" href="./assets/header.css">
Written on 2025-06-29.