---
title: "Protect a web application from attacks: defense in layers | StreetHosting"
description: "Firewall, proxy with rate limiting, WAF, strong login, updates and logs: how to protect a site or API on a VPS, layer by layer, with Nginx examples."
url: "https://streethosting.com.br/en/guides/infrastructure/protect-web-application-from-attacks"
type: "page"
language: "en-US"
---

Infrastructure · 10 min · Intermediate

Published on Sep 28, 2026 · Updated on Sep 28, 2026

# How to protect a website or API on a VPS, layer by layer

No single tool protects a web application on its own. This guide organizes the defenses in layers, from the network port to the log, and shows what to configure first on a VPS running Nginx.

By [Equipe StreetHosting](https://streethosting.com.br/en/autores#equipe-streethosting) · StreetHosting infrastructure and support team

[Security and hardening](https://streethosting.com.br/en/guides/topics/security) [Network, DNS and domains](https://streethosting.com.br/en/guides/topics/networking)

Summarize with:

[](https://chat.openai.com/?q=Summarize%20the%20key%20points%20of%20this%20StreetHosting%20guide%3A%20https%3A%2F%2Fstreethosting.com.br%2Fen%2Fguides%2Finfrastructure%2Fprotect-web-application-from-attacks.%20Highlight%20the%20step-by-step%20instructions%2C%20the%20prerequisites%20and%20the%20most%20common%20mistakes. "ChatGPT") [](https://claude.ai/new?q=Summarize%20the%20key%20points%20of%20this%20StreetHosting%20guide%3A%20https%3A%2F%2Fstreethosting.com.br%2Fen%2Fguides%2Finfrastructure%2Fprotect-web-application-from-attacks.%20Highlight%20the%20step-by-step%20instructions%2C%20the%20prerequisites%20and%20the%20most%20common%20mistakes. "Claude") [](https://www.google.com/search?udm=50&aep=11&q=Summarize%20the%20key%20points%20of%20this%20StreetHosting%20guide%3A%20https%3A%2F%2Fstreethosting.com.br%2Fen%2Fguides%2Finfrastructure%2Fprotect-web-application-from-attacks.%20Highlight%20the%20step-by-step%20instructions%2C%20the%20prerequisites%20and%20the%20most%20common%20mistakes. "Google AI Mode") [](https://x.com/i/grok?text=Summarize%20the%20key%20points%20of%20this%20StreetHosting%20guide%3A%20https%3A%2F%2Fstreethosting.com.br%2Fen%2Fguides%2Finfrastructure%2Fprotect-web-application-from-attacks.%20Highlight%20the%20step-by-step%20instructions%2C%20the%20prerequisites%20and%20the%20most%20common%20mistakes. "Grok") [](https://www.perplexity.ai/search/new?q=Summarize%20the%20key%20points%20of%20this%20StreetHosting%20guide%3A%20https%3A%2F%2Fstreethosting.com.br%2Fen%2Fguides%2Finfrastructure%2Fprotect-web-application-from-attacks.%20Highlight%20the%20step-by-step%20instructions%2C%20the%20prerequisites%20and%20the%20most%20common%20mistakes. "Perplexity")

Share:

[](https://x.com/intent/tweet?text=Protect%20a%20web%20application%20from%20attacks%3A%20defense%20in%20layers&url=https%3A%2F%2Fstreethosting.com.br%2Fen%2Fguides%2Finfrastructure%2Fprotect-web-application-from-attacks "Share on X") [](https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fstreethosting.com.br%2Fen%2Fguides%2Finfrastructure%2Fprotect-web-application-from-attacks "Share on Facebook") [](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fstreethosting.com.br%2Fen%2Fguides%2Finfrastructure%2Fprotect-web-application-from-attacks "Share on LinkedIn") [](https://wa.me/?text=Protect%20a%20web%20application%20from%20attacks%3A%20defense%20in%20layers%20https%3A%2F%2Fstreethosting.com.br%2Fen%2Fguides%2Finfrastructure%2Fprotect-web-application-from-attacks "Share on WhatsApp")

For agents: Copy as Markdown [.md](https://streethosting.com.br/en/guides/infrastructure/protect-web-application-from-attacks.md)

In this guide 8 sections

* [The layers and what each one blocks](https://streethosting.com.br/en/guides/infrastructure/protect-web-application-from-attacks#camadas)
* [Network: expose only what is needed](https://streethosting.com.br/en/guides/infrastructure/protect-web-application-from-attacks#rede)
* [Reverse proxy: TLS, limits and headers](https://streethosting.com.br/en/guides/infrastructure/protect-web-application-from-attacks#proxy)
* [WAF: filtering the content](https://streethosting.com.br/en/guides/infrastructure/protect-web-application-from-attacks#waf)
* [Authentication, sessions and admin panel](https://streethosting.com.br/en/guides/infrastructure/protect-web-application-from-attacks#autenticacao)
* [Updates, dependencies and secrets](https://streethosting.com.br/en/guides/infrastructure/protect-web-application-from-attacks#atualizacoes)
* [Logs, alerts and response](https://streethosting.com.br/en/guides/infrastructure/protect-web-application-from-attacks#logs)
* [Where to host with these layers](https://streethosting.com.br/en/guides/infrastructure/protect-web-application-from-attacks#onde-hospedar)

Quick answer

To **protect a web application from attacks**, stack defenses that cover for each other: a firewall exposing only 80, 443 and SSH; a reverse proxy with TLS, rate limiting and security headers; a WAF to filter injections; authentication with 2FA and secure sessions; an up-to-date OS, runtime and dependencies; and logs with alerts to notice what got through. Each layer assumes the previous one can fail.

## The layers and what each one blocks[](https://streethosting.com.br/en/guides/infrastructure/protect-web-application-from-attacks#camadas)

Most attacks against sites on a VPS are not personal. Bots sweep entire IP ranges looking for a forgotten .env file in the public folder, a WordPress login page, phpMyAdmin, an outdated plugin and an open database. A smaller share is targeted: leaked passwords tried against your login, API abuse, a flood of requests to knock the service down. No single tool covers all of that, which is why the defense is built in layers.

| Layer                 | What it blocks                                          | Typical tool on a VPS                       |
| --------------------- | ------------------------------------------------------- | ------------------------------------------- |
| Network               | Forgotten open port, exposed database, scanning         | UFW and the provider's Anti-DDoS            |
| Edge and proxy        | Request floods, giant uploads, exposed version          | Nginx with TLS, limits and headers          |
| Content filter        | SQL injection, XSS, exploitation of known flaws         | WAF with OWASP CRS or a CDN WAF             |
| Identity              | Leaked password, session hijacking, exposed admin panel | 2FA, secure cookies, VPN for administration |
| Code and dependencies | Known flaw in a library, theme or plugin                | Updates and package audits                  |
| Observation           | Attack that got past the other layers                   | Logs, Fail2Ban and alerts                   |

For a small team, the order of priority follows cost against impact: close ports, turn on TLS and update, harden the login, limit requests, organize logs and, last of all, tune a WAF. The first three take an afternoon and remove most of the risk.

## Network: expose only what is needed[](https://streethosting.com.br/en/guides/infrastructure/protect-web-application-from-attacks#rede)

A web application needs ports 80 and 443 open to the public and the SSH port open for you. Everything else, such as PostgreSQL on 5432, MySQL on 3306, Redis on 6379 and the application's internal port (3000, 8000, 8080), should listen only on 127.0.0.1 or on a private network. Find out what is listening externally with:

`sudo ss -tlnp`

Any internal service bound to 0.0.0.0 or to an asterisk is accepting connections from anywhere. Fix it in two places: in the service itself, by changing the listen address, and in the firewall, by denying the port. If one layer fails, the other holds. The step-by-step rules are in the guide on [the UFW firewall on an Ubuntu VPS](https://streethosting.com.br/en/guides/vps/ufw-firewall-ubuntu-vps), including the Docker trap, which publishes ports around UFW.

Admin panels (phpMyAdmin, Portainer, the n8n editor, metrics dashboards) do not need to be on the internet. Reach them through an SSH tunnel, such as `ssh -L 8080:127.0.0.1:8080 usuario@IP_DA_VPS`, or through a [WireGuard VPN](https://streethosting.com.br/en/guides/vps/wireguard-vpn-vps). A panel that shows up in no scan receives no login attempts.

Two situations fall outside what the VPS firewall can solve. Volumetric DDoS has to be filtered before it reaches the server, on the provider's network. And if the site sits behind a CDN, the origin should accept 80 and 443 only from the CDN's IP ranges; otherwise, anyone who discovers the real IP of the VPS bypasses all the edge protection. In that scenario, configure Nginx to recover the visitor's real IP with `set_real_ip_from` and `real_ip_header`, or the per-IP limits will treat every visitor as if they were the CDN itself.

## Reverse proxy: TLS, limits and headers[](https://streethosting.com.br/en/guides/infrastructure/protect-web-application-from-attacks#proxy)

Put Nginx in front of the application, whether it is Node.js, Python or PHP, and keep the application listening only locally. Nginx terminates TLS, as shown in the guide on [SSL certificates with Let's Encrypt and Nginx](https://streethosting.com.br/en/guides/vps/lets-encrypt-ssl-certificate-vps), and becomes the right place to enforce size, time and frequency limits. A file in `/etc/nginx/conf.d/` is read inside the http block on Ubuntu:

`# /etc/nginx/conf.d/seguranca.conf server_tokens off; client_max_body_size 10m; client_body_timeout 15s; client_header_timeout 15s; limit_req_zone $binary_remote_addr zone=login:10m rate=10r/m; limit_req_zone $binary_remote_addr zone=api:10m rate=20r/s; limit_conn_zone $binary_remote_addr zone=porip:10m; limit_req_status 429; limit_conn_status 429;`

And inside the site's server block:

`location = /login { limit_req zone=login burst=5 nodelay; proxy_pass http://127.0.0.1:3000; } location /api/ { limit_req zone=api burst=40 nodelay; limit_conn porip 20; proxy_pass http://127.0.0.1:3000; } location ~ /\.(?!well-known) { deny all; } add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; add_header X-Content-Type-Options "nosniff" always; add_header X-Frame-Options "SAMEORIGIN" always; add_header Referrer-Policy "strict-origin-when-cross-origin" always;`

* **Login at 10 per minute:** one request every six seconds per IP, with a burst of five for someone who gets the password wrong once. A bot testing passwords drops to a few hundred attempts a day.
* **Status 429:** the Nginx default is 503, which is easy to mistake for a server that is down. 429 tells the client and your monitoring that it is a rate limit.
* **Hidden files:** the deny all rule blocks .env, .git and the like, but lets the `.well-known`folder through, which Let's Encrypt uses to validate the domain.
* **Headers:** HSTS forces HTTPS in the browser, nosniff stops a file from being interpreted as another type, and `X-Frame-Options` keeps the site from being embedded in a third-party page to trick clicks.

In Nginx, an add\_header inside a location replaces every one that came from the server block. If any location has a header of its own, repeat the security headers there. And only turn on HSTS with includeSubDomains after confirming that every subdomain answers over HTTPS. Always validate with `sudo nginx -t` before reloading.

The strongest header against XSS is Content Security Policy, but it depends on each application. Start with the report-only version, which warns without blocking, and tighten it gradually.

## WAF: filtering the content[](https://streethosting.com.br/en/guides/infrastructure/protect-web-application-from-attacks#waf)

The firewall looks at ports and the proxy looks at volume. The WAF reads the content: URL, parameters, headers and request body, looking for patterns of SQL injection, XSS, file inclusion and exploitation of known flaws. On a VPS, the common path is ModSecurity with the OWASP Core Rule Set inside Nginx; at the edge, a CDN's WAF does the same before the traffic reaches your machine.

The biggest value of a WAF is buying time: when a serious flaw comes out in a plugin, the rules block mass exploitation while you apply the update. It does not fix logic errors, does not stop one user from opening another user's order if the application does not check permissions, and produces false positives if switched straight into blocking mode. How to choose, install and tune one is covered in [what a WAF is and when to use one](https://streethosting.com.br/en/guides/infrastructure/what-is-a-waf). For request floods that mimic real users, also read about [layer 7 DDoS](https://streethosting.com.br/en/guides/infrastructure/layer-7-ddos-attack).

## Authentication, sessions and admin panel[](https://streethosting.com.br/en/guides/infrastructure/protect-web-application-from-attacks#autenticacao)

Login is the most attacked point of any application, and a good share of break-ins do not break anything: they walk in with a password leaked from another site. The measures below apply to custom systems and to CMS admin panels alike.

* **Passwords stored with a slow hash:** Argon2id or bcrypt, never MD5 or plain SHA. Frameworks like Laravel and Django already do this by default; the mistake usually shows up in systems written from scratch.
* **2FA for administrators:** a time-based code app on the accounts that can delete data, at a minimum.
* **A per-account limit on top of the per-IP limit:** leaked-password testing comes from thousands of different IPs. Delaying or locking the account after several failures closes what the per-IP limit lets through. The error message must be the same for a nonexistent user and a wrong password.
* **A well-configured session:** cookies with Secure, HttpOnly and SameSite, a session identifier renewed at login, and expiration on inactivity. Forms with CSRF protection.
* **Admin panel out of public reach:** restrict the admin path by IP in Nginx, with `allow 203.0.113.10; deny all;` inside the location, or make the panel reachable only through the VPN.
* **Permission checked on the server:** every request has to confirm that this user may see this resource. Broken access control sits at the top of the OWASP Top 10 precisely because no WAF can see that mistake.
* **API tokens with scope and expiry:** never in the query string, where they end up written to logs, and with CORS allowed only for the origins you control.

## Updates, dependencies and secrets[](https://streethosting.com.br/en/guides/infrastructure/protect-web-application-from-attacks#atualizacoes)

Most mass compromises exploit flaws that already had a published fix. There are three levels of updates, and each has its own rhythm. The operating system can run on its own with [Ubuntu's automatic security updates](https://streethosting.com.br/en/guides/vps/ubuntu-automatic-security-updates). The runtime (Node.js, PHP, Python) needs to be on a version that is still supported. And the application's dependencies call for a periodic audit:

`npm audit --omit=dev composer audit pip-audit docker compose pull && docker compose up -d`

The `pip-audit` tool is installed separately, with pip, inside the project's virtual environment. The last line is for those running in containers: the image only receives a fix when you pull the new version and recreate the container.

* The .env file outside the public folder, with 600 permissions and out of Git
* A database user with access to the application database only
* Parameterized queries or an ORM, never user text pasted into SQL
* Uploads validated by content, with a size limit and outside any executable folder
* Debug mode turned off in production
* Unused plugins, themes and test routes removed

A quick test shows whether the server is serving what it should not. The two commands below should return 403 or 404:

`curl -s -o /dev/null -w "%{http_code}\n" https://seu-dominio.com.br/.env curl -s -o /dev/null -w "%{http_code}\n" https://seu-dominio.com.br/.git/config`

## Logs, alerts and response[](https://streethosting.com.br/en/guides/infrastructure/protect-web-application-from-attacks#logs)

Without logs, you find out about the attack from a customer. Record login attempts with the IP, administrative actions, 4xx and 5xx responses, rate-limit blocks and WAF blocks. Nginx writes to `/var/log/nginx/` and the application, if it runs as a systemd service, shows up in `journalctl -u nome-do-servico`. Two queries answer a lot of questions in the default Nginx log format:

`# IPs with the most requests sudo awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head # how many 401, 403 and 429 responses sudo awk '$9 ~ /^(401|403|429)$/' /var/log/nginx/access.log | wc -l`

The next step is to automate the reaction. [Fail2Ban on the VPS](https://streethosting.com.br/en/guides/vps/fail2ban-ssh-vps-setup) reads the Nginx error log and bans IPs that repeatedly blow through the request limit or sweep typical bot paths. Alerts for error spikes and for the service going down close the loop.

If something gets through, follow an order: preserve the logs before cleaning anything, rotate passwords, API keys and the secrets in .env, fix the flaw and, if in doubt about integrity, restore from a clean backup. When personal data is involved, the LGPD requires notifying the ANPD and the data subjects if the incident could cause relevant risk or harm.

## Where to host with these layers[](https://streethosting.com.br/en/guides/infrastructure/protect-web-application-from-attacks#onde-hospedar)

Shared hosting does not let you touch the firewall, the Nginx limits, a WAF module or Fail2Ban. A VPS with root does, and in exchange the configuration becomes yours. The layer you cannot build on your own is volumetric DDoS, because it has to act before the traffic reaches the machine.

The [StreetHosting VPS plans](https://streethosting.com.br/en/vps) are KVM with root access, a datacenter in São Paulo and Anti-DDoS included in the network, which covers that layer. For a small API with Nginx and a database, the 4 vCPU, 6 GB Xeon VPS costs R$ 60.00 per month. A site with WAF, application and database on the same machine fits comfortably on the 4 vCPU, 8 GB DDR5, 80 GB NVMe Ryzen 9 9950X VPS, at R$ 118.00, since WAF rules consume CPU on every request. Entry plans start at R$ 26.00 on the Xeon line and R$ 40.00 on the Ryzen line.

In this guide

* [The layers and what each one blocks](https://streethosting.com.br/en/guides/infrastructure/protect-web-application-from-attacks#camadas)
* [Network: expose only what is needed](https://streethosting.com.br/en/guides/infrastructure/protect-web-application-from-attacks#rede)
* [Reverse proxy: TLS, limits and headers](https://streethosting.com.br/en/guides/infrastructure/protect-web-application-from-attacks#proxy)
* [WAF: filtering the content](https://streethosting.com.br/en/guides/infrastructure/protect-web-application-from-attacks#waf)
* [Authentication, sessions and admin panel](https://streethosting.com.br/en/guides/infrastructure/protect-web-application-from-attacks#autenticacao)
* [Updates, dependencies and secrets](https://streethosting.com.br/en/guides/infrastructure/protect-web-application-from-attacks#atualizacoes)
* [Logs, alerts and response](https://streethosting.com.br/en/guides/infrastructure/protect-web-application-from-attacks#logs)
* [Where to host with these layers](https://streethosting.com.br/en/guides/infrastructure/protect-web-application-from-attacks#onde-hospedar)

## Frequently asked questions

What is the first thing to do to protect a web application?

Close what does not need to be exposed and update what is. Leave only ports 80, 443 and the SSH port open, make databases and admin panels listen only locally, and apply the pending updates. Those two measures cut out most automated attacks.

Does rate limiting get in the way of legitimate users?

It can if the limit is too tight, especially when many people share the same outgoing IP, as in companies, schools and mobile networks behind CGNAT. Use strict limits only on sensitive endpoints, such as login and password recovery, and loose limits on the rest of the site.

Do I need a WAF if I already have a firewall?

They are different things. The firewall decides which ports accept connections, and port 443 has to stay open for the site to work. The WAF inspects the content that passes through it and blocks attack patterns. For sites with forms, login and plugins, it is worth having both.

Does HTTPS protect the site against attacks?

It protects the path, not the destination. TLS stops anyone from reading or altering the data between the visitor and the server, but a SQL injection arrives encrypted all the same. It is mandatory, but it only covers one layer.

How do I know if my site has already been attacked?

Look at the Nginx and application logs for spikes in 401, 403 and 500 errors, requests for paths that do not exist on your site, and logins from unusual IPs or at unusual hours. Files changed without a deploy and unknown processes consuming CPU are strong signs of compromise.

Next step

See VPS plans

Root VPS in Brazil with NVMe and Anti-DDoS.

[See VPS plans](https://streethosting.com.br/en/vps)

[See Ryzen VPS Ryzen 9 9950X VPS in São Paulo with root access, NVMe and gamer Anti-DDoS.](https://streethosting.com.br/en/vps/ryzen) [See Xeon VPS Xeon VPS for steady workloads, automation and long-running projects.](https://streethosting.com.br/en/vps/xeon)

## Related guides

[Infrastructure Intermediate What is a WAF and when to use one on sites and APIs A WAF inspects the content of every request and blocks injections, XSS and exploitation of known vulnerabilities. See the deployment models, how to install ModSecurity with the OWASP CRS on Nginx, and how to tune it without breaking your site. 11 min Read guide](https://streethosting.com.br/en/guides/infrastructure/what-is-a-waf) [Infrastructure Intermediate Network firewall vs. application firewall: what is the difference A network firewall decides which ports and IPs get through. An application firewall understands the content of web requests. They are different layers that together make a solid defense. 3 min Read guide](https://streethosting.com.br/en/guides/infrastructure/network-firewall-vs-application-firewall) [VPS Beginner UFW on Ubuntu VPS: firewall rules without losing SSH UFW makes the Ubuntu firewall simpler, but one rule in the wrong order locks you out of your VPS. Learn how to enable it without losing SSH, open only what you need, deal with Docker, and get back in through the console if something goes wrong. 10 min Read guide](https://streethosting.com.br/en/guides/vps/ufw-firewall-ubuntu-vps)

[← Back to the Guide Center](https://streethosting.com.br/en/guides)
