Introduction
A website not loading on a cloud VM usually fails because one layer in the request path is broken: DNS, network access, firewall rules, web server status, application process, or logs. For beginners, the mistake is often checking those layers randomly instead of following a repeatable order.
Raff Technologies users often deploy websites, APIs, dashboards, and self-hosted tools on Linux VMs. When something does not load in the browser, the VM itself may still be healthy. The problem may be outside the server, inside the server, or between the web server and the application.
A website request is a chain: domain name → DNS record → public IP → open port → firewall → web server → application → response. This guide gives you a practical checklist for debugging that chain on a Linux cloud VM. The examples assume Ubuntu 24.04 and Nginx, but the same thinking applies to Apache, Caddy, Node.js, Python, PHP, Docker, and most self-hosted applications.
The Debugging Order That Saves Time
The fastest way to debug a website that will not load is to move from the outside toward the application. Start with what the user's browser sees, then move into DNS, ports, firewall rules, web server status, app processes, and logs.
This order matters because website failures can look similar from the browser. "This site can't be reached," "connection refused," "connection timed out," "502 Bad Gateway," and "404 Not Found" all point to different layers.
When I test beginner web-server setups for Raff Learn Hub content, I use this order because it separates public-internet problems from server-side problems before changing configuration files. Guessing too early often creates a second problem on top of the first one.
Use this checklist before reinstalling Nginx, changing DNS again, or resizing the VM.
| Symptom | Most likely layer |
|---|---|
| Domain does not resolve | DNS |
| IP works but domain does not | DNS record or propagation |
| Connection timed out | Firewall, closed port, or service not listening |
| Connection refused | Port reachable, but no service is accepting traffic |
| 404 Not Found | Web server reached, wrong site block or document root |
| 502 Bad Gateway | Reverse proxy reached, backend app failed |
| 403 Forbidden | Permissions, index file, or access rule |
| SSL warning | Certificate, domain mismatch, or HTTPS config |
| Slow loading | App performance, database, disk, memory, or network |
Start With the Exact Error Message
The browser error message gives the first clue. Do not skip it.
Open the site in a browser and write down the exact error. Then test both the domain and the public IP address.
bashcurl -I http://your-domain.com
curl -I http://YOUR_SERVER_IP
The -I flag asks for only the HTTP headers. This is useful because you can quickly see whether the server replies at all.
Expected output for a working HTTP site may look like this: HTTP/1.1 200 OK Server: nginx Content-Type: text/html
A redirect to HTTPS is also normal: HTTP/1.1 301 Moved Permanently Location: https://your-domain.com/
If the IP works but the domain fails, the server is probably not the problem. Start with DNS.
If both the IP and the domain fail, continue down the checklist.
Check DNS Before Editing the Server
DNS tells the internet which IP address your domain should use. If DNS points to the wrong IP, the browser never reaches your Raff VM.
Check the domain's A record:
bashdig +short your-domain.com
You should see your VM's public IPv4 address: 203.0.113.10
You can also check the full DNS response:
bashdig your-domain.com
Look for the ANSWER SECTION. If the IP is missing, wrong, or still points to an old server, update the A record at your DNS provider.
For www, check it separately:
bashdig +short www.your-domain.com
A common beginner mistake is setting the root domain but forgetting www, or setting www but forgetting the root domain.
A basic DNS setup usually looks like this:
| Host | Type | Value |
|---|---|---|
| @ | A | Your VM public IP |
| www | CNAME | your-domain.com |
| api | A | Your VM public IP, if needed |
Tip: DNS changes can take time to propagate. If you recently changed records, test with dig and wait before making unrelated server changes.
Confirm the VM Is Reachable
Before debugging the website stack, confirm that your VM is online and reachable.
From your local machine, test the IP:
bashping YOUR_SERVER_IP
Some servers block ICMP ping, so a failed ping is not always proof that the VM is down. A better test is to check whether SSH responds:
bashssh your-user@YOUR_SERVER_IP
If SSH works, the VM is online.
If SSH does not work, the website issue may be part of a broader access problem. Check whether the VM is running, whether the IP is correct, and whether your firewall allows SSH.
For recovery access, browser-based console access can help when SSH is unavailable. Raff's VNC console article explains how to access a VM from the browser when normal remote access is not working:
Access Your VM Anywhere With Our New VNC Console
Check Whether Ports 80 and 443 Are Open
A website usually needs port 80 for HTTP and port 443 for HTTPS. If those ports are closed, the server may be healthy but unreachable from the browser.
From your local machine, test HTTP:
bashcurl -I http://YOUR_SERVER_IP
Then test HTTPS:
bashcurl -I https://your-domain.com
You can also test ports with nc:
bashnc -vz YOUR_SERVER_IP 80
nc -vz YOUR_SERVER_IP 443
A successful connection looks like this: Connection to YOUR_SERVER_IP 80 port [tcp/http] succeeded!
A failed connection may show: Connection timed out
or: Connection refused
These errors mean different things.
| Error | Meaning |
|---|---|
| Connection timed out | Traffic is likely blocked by a firewall or network rule |
| Connection refused | Server is reachable, but no service is listening on that port |
| SSL certificate error | HTTPS is reachable, but the certificate or hostname is wrong |
This is why port testing is useful. It tells you whether the request reaches the server before you start editing application files.
Check the Server Firewall
On Ubuntu, many beginners use UFW. A firewall can block HTTP and HTTPS even when Nginx is configured correctly.
Check UFW status:
bashsudo ufw status verbose
A web server should usually allow SSH, HTTP, and HTTPS: Status: active To Action From
22/tcp ALLOW Anywhere 80/tcp ALLOW Anywhere 443/tcp ALLOW Anywhere
If port 80 or 443 is missing, allow them:
bashsudo ufw allow 80/tcp
sudo ufw allow 443/tcp
Then reload UFW:
bashsudo ufw reload
Verify again:
bashsudo ufw status verbose
Warning: Do not reset firewall rules blindly on a remote server. Always keep SSH access allowed before reloading firewall rules, or you may lock yourself out.
For broader security planning, read:
Cloud Security Fundamentals
Check Whether the Web Server Is Running
If the firewall allows traffic but the website still does not load, check whether the web server is running.
For Nginx:
bashsudo systemctl status nginx
A healthy service shows: Active: active (running)
If Nginx is stopped, start it:
bashsudo systemctl start nginx
Enable it to start after reboot:
bashsudo systemctl enable nginx
For Apache:
bashsudo systemctl status apache2
For Caddy:
bashsudo systemctl status caddy
If the service fails to start, do not guess. Check the logs:
bashsudo journalctl -u nginx --no-pager -n 50
For Apache:
bashsudo journalctl -u apache2 --no-pager -n 50
For Caddy:
bashsudo journalctl -u caddy --no-pager -n 50
A common mistake is editing a configuration file, restarting the service, and then missing the exact error message. journalctl usually tells you which line or file caused the failure.
Confirm the Service Is Listening on the Right Port
A running web server still needs to listen on the correct port.
Use ss to check listening ports:
bashsudo ss -tulpn
Look for lines like this: tcp LISTEN 0 511 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=1234,fd=6)) tcp LISTEN 0 511 0.0.0.0:443 0.0.0.0:* users:(("nginx",pid=1234,fd=7))
If nothing is listening on port 80 or 443, your browser cannot reach a website on those ports.
If another process is already using port 80, Nginx may fail to start. Find the process:
bashsudo lsof -i :80
or:
bashsudo ss -tulpn | grep ':80'
Only one service can listen on the same IP and port combination. For example, Apache and Nginx cannot both listen on port 80 unless you configure them carefully with different addresses or ports.
Test the Web Server Configuration
Configuration syntax errors are common after editing Nginx site files.
Test Nginx:
bashsudo nginx -t
A successful test looks like this: nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
If there is an error, Nginx prints the file and line number. Fix that exact issue before restarting.
After a successful test, reload Nginx:
bashsudo systemctl reload nginx
For Apache, test the configuration with:
bashsudo apache2ctl configtest
A successful Apache result looks like this: Syntax OK
Do not restart repeatedly before testing syntax. A config test is faster, safer, and tells you where the problem is.
Check the Nginx Server Block
If the server responds but shows the wrong site, a default page, or a 404, check the Nginx server block.
List enabled sites:
bashls -l /etc/nginx/sites-enabled/
Open your site configuration:
bashsudo nano /etc/nginx/sites-available/your-site
A simple static site server block may look like this:
nginxserver {
listen 80;
server_name your-domain.com www.your-domain.com;
root /var/www/your-site;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
Check these fields carefully:
| Field | What to verify |
|---|---|
| listen | Uses port 80 or 443 as expected |
| server_name | Matches your domain and www version |
| root | Points to the correct document directory |
| index | Matches the actual index file |
| try_files | Does not route requests incorrectly |
If you change the file, test and reload:
bashsudo nginx -t
sudo systemctl reload nginx
A common beginner mistake is editing a file in sites-available but forgetting to link it into sites-enabled.
Create the symlink if needed:
bashsudo ln -s /etc/nginx/sites-available/your-site /etc/nginx/sites-enabled/
Then test and reload Nginx.
Check File Paths and Permissions
A 403 error often means the web server reached the site but cannot read the files.
Check the document root:
bashls -la /var/www/your-site
Make sure the index file exists:
bashls -la /var/www/your-site/index.html
Check directory permissions:
bashsudo find /var/www/your-site -type d -exec chmod 755 {} \;
sudo find /var/www/your-site -type f -exec chmod 644 {} \;
Set ownership to the web user if appropriate:
bashsudo chown -R www-data:www-data /var/www/your-site
Warning: Do not use chmod 777 to "fix" permission problems. It may make the error disappear, but it creates an unsafe setup.
For application deployments, the correct owner may differ. A static site can often be owned by www-data, while a Node.js or Python app may run under its own service user.
Check the Application Process
If Nginx works but returns 502 Bad Gateway, the web server probably cannot reach the backend application.
For example, a Node.js, Python, FastAPI, Django, or Rails app may run behind Nginx on a local port such as 3000, 5000, or 8000.
Check whether the app is running:
bashsudo ss -tulpn | grep -E '3000|5000|8000'
If your app is managed by systemd:
bashsudo systemctl status your-app
Check the app logs:
bashsudo journalctl -u your-app --no-pager -n 100
Common causes of 502 Bad Gateway include:
- the app process is stopped
- the app listens on a different port
- the app listens on 127.0.0.1 but Nginx points elsewhere
- environment variables are missing
- the app crashed during startup
- file permissions prevent the app from reading required files
- the database connection failed
A simple reverse proxy block may look like this:
nginxlocation / {
proxy_pass http://127.0.0.1:8000;
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;
}
Make sure the proxy_pass port matches the actual application port.
Check Web Server Logs
Logs usually reveal the real cause faster than changing settings randomly.
For Nginx access logs:
bashsudo tail -n 50 /var/log/nginx/access.log
For Nginx error logs:
bashsudo tail -n 100 /var/log/nginx/error.log
Watch logs live while refreshing the browser:
bashsudo tail -f /var/log/nginx/error.log
If you see requests in access.log, traffic is reaching Nginx. If you do not see requests, the issue may still be DNS, firewall, or networking.
Common log clues:
| Log message | Likely meaning |
|---|---|
| connect() failed (111: Connection refused) | Backend app is not running or wrong port |
| permission denied | File or socket permission problem |
| no such file or directory | Wrong file path or missing document root |
| host not found in upstream | Bad upstream name or DNS issue |
| directory index is forbidden | Missing index file or disabled directory listing |
Do not read only the last line. Look at the error just before the failure.
Check HTTPS and Certificates
If HTTP works but HTTPS fails, the problem is likely SSL/TLS configuration.
Test HTTPS:
bashcurl -Iv https://your-domain.com
Common HTTPS problems include:
- certificate issued for the wrong domain
- certificate expired
- Nginx not listening on port 443
- firewall blocking port 443
- missing certificate files
- redirect loop between HTTP and HTTPS
- app forcing HTTPS behind a proxy without correct headers
If you use Let's Encrypt with Certbot, check certificates:
bashsudo certbot certificates
Test renewal:
bashsudo certbot renew --dry-run
If the certificate is missing, confirm DNS works before requesting a new one. Let's Encrypt must be able to verify the domain.
Tip: Do not debug HTTPS before HTTP works. First make sure http://your-domain.com reaches the correct server, then add HTTPS.
Check DNS Caching and Local Browser Issues
Sometimes the server is fixed but your browser, DNS resolver, or local network still has old information.
Test from another network or device.
You can also use public DNS resolvers:
bashdig @1.1.1.1 your-domain.com +short
dig @8.8.8.8 your-domain.com +short
If public resolvers show the correct IP but your computer does not, clear local DNS cache or wait for the old record to expire.
Also test with curl:
bashcurl -I http://your-domain.com
Browser extensions, cached redirects, and old HTTPS/HSTS behavior can create confusing results. Command-line tests usually give cleaner signals.
Check Resource Limits
If the site loads sometimes but fails under traffic, check CPU, RAM, disk, and service restarts.
Check memory:
bashfree -h
Check disk usage:
bashdf -h
Check the largest directories:
bashsudo du -h --max-depth=1 /var | sort -h
Check active processes:
bashtop
or install htop:
bashsudo apt update
sudo apt install htop
htop
A full disk can break web servers, databases, SSL renewal, deployments, and log writing. Low memory can cause application processes or databases to be killed.
If the workload has outgrown the VM, review the current plan and decide whether to resize. You can compare VM options on the Raff Linux VM page and review costs on Raff pricing.
Use a Short Decision Tree
When a website does not load, use this order:
| Check | Command | What success looks like |
|---|---|---|
| DNS | dig +short your-domain.com | Returns your VM IP |
| HTTP response | curl -I http://your-domain.com | Returns HTTP headers |
| Open ports | nc -vz IP 80 | Connection succeeds |
| Firewall | sudo ufw status verbose | 80 and 443 allowed |
| Web server | sudo systemctl status nginx | Active running |
| Listening ports | sudo ss -tulpn | Nginx listens on 80/443 |
| Config syntax | sudo nginx -t | Syntax OK |
| App process | sudo systemctl status your-app | Active running |
| Logs | tail -f /var/log/nginx/error.log | Shows real errors |
| Resources | df -h, free -h, top | Disk/RAM/CPU not exhausted |
The point is not to memorize commands. The point is to remove uncertainty one layer at a time.
Common Mistakes Beginners Make
The most common website debugging mistake is changing several things at once. If you change DNS, firewall rules, Nginx config, app ports, and SSL settings in one session, you may fix one problem while creating another.
Avoid these mistakes:
- changing DNS before confirming the current IP
- opening firewall ports without checking the service
- restarting Nginx without running nginx -t
- debugging HTTPS before HTTP works
- ignoring logs
- assuming a 502 is an Nginx problem
- using chmod 777 to fix permissions
- forgetting the www DNS record
- pointing Nginx to the wrong app port
- not checking disk space
A good debugging session should leave notes. Record what you tested, what changed, and what result you saw.
Raff-Specific Context
On Raff, most beginner website deployments start with a Linux VM. That gives you a clean environment for Nginx, Apache, Caddy, Docker, Node.js, Python, PHP, databases, and self-hosted tools.
Raff Linux VMs include root access, NVMe SSD storage, DDoS protection, firewall management, snapshots, automated backups, private networking, and web console access. These features do not replace application debugging, but they give you the infrastructure tools needed to investigate safely.
For a simple public website, a General Purpose VM starting at $4.99/month can be enough. For workloads that need more consistent compute, CPU-Optimized plans start at $3.99/month and scale up by CPU, RAM, and NVMe storage.
Before making risky changes, create a snapshot or backup. If you break Nginx, delete the wrong site file, or change the wrong firewall rule, a recovery point can save time.
For broader server setup, read:
Your First Cloud Server: What to Do After You Provision It
For command reference while debugging, read:
Linux Commands for Cloud Servers
Conclusion
A website that will not load is easier to debug when you treat it as a chain instead of a mystery. Start with DNS, then test public ports, firewall rules, web server status, listening services, configuration syntax, app processes, logs, HTTPS, and system resources.
The most useful habit is moving from the outside in. If the domain points to the wrong IP, Nginx does not matter yet. If port 80 is blocked, the app is not the first problem. If Nginx returns 502, the backend app deserves attention before you edit DNS again.
On a Raff Linux VM, you have the tools to debug each layer: SSH access, web console recovery, firewall controls, snapshots, backups, and enough flexibility to run the stack your project needs.
Start with one failing layer, verify it, fix it, and move to the next one. That is how debugging becomes manageable.

