---
title: "Host a React and Vite static site on a VPS with Nginx | StreetHosting"
description: "Publish a React or Vite site on your VPS: npm run build, the dist folder, Nginx with try_files for SPA routes, asset caching, gzip, HTTPS and automatic deploys."
url: "https://streethosting.com.br/en/guides/vps/host-react-vite-static-site-nginx"
type: "page"
language: "en-US"
---

VPS · 9 min · Beginner

Published on Nov 13, 2026 · Updated on Nov 13, 2026

# How to host a React site built with Vite on a VPS: dist, Nginx, caching and deploys

A Vite site turns into a folder of files, and Nginx serves that folder very well. Here is the build, the server block with try\_files for routes, the right cache for each file, HTTPS and an automatic deploy.

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

[Network, DNS and domains](https://streethosting.com.br/en/guides/topics/networking) [Deploying and running apps](https://streethosting.com.br/en/guides/topics/deploy)

Summarize with:

[](https://chat.openai.com/?q=Summarize%20the%20key%20points%20of%20this%20StreetHosting%20guide%3A%20https%3A%2F%2Fstreethosting.com.br%2Fen%2Fguides%2Fvps%2Fhost-react-vite-static-site-nginx.%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%2Fvps%2Fhost-react-vite-static-site-nginx.%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%2Fvps%2Fhost-react-vite-static-site-nginx.%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%2Fvps%2Fhost-react-vite-static-site-nginx.%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%2Fvps%2Fhost-react-vite-static-site-nginx.%20Highlight%20the%20step-by-step%20instructions%2C%20the%20prerequisites%20and%20the%20most%20common%20mistakes. "Perplexity")

Share:

[](https://x.com/intent/tweet?text=Host%20a%20React%20and%20Vite%20static%20site%20on%20a%20VPS%20with%20Nginx&url=https%3A%2F%2Fstreethosting.com.br%2Fen%2Fguides%2Fvps%2Fhost-react-vite-static-site-nginx "Share on X") [](https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fstreethosting.com.br%2Fen%2Fguides%2Fvps%2Fhost-react-vite-static-site-nginx "Share on Facebook") [](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fstreethosting.com.br%2Fen%2Fguides%2Fvps%2Fhost-react-vite-static-site-nginx "Share on LinkedIn") [](https://wa.me/?text=Host%20a%20React%20and%20Vite%20static%20site%20on%20a%20VPS%20with%20Nginx%20https%3A%2F%2Fstreethosting.com.br%2Fen%2Fguides%2Fvps%2Fhost-react-vite-static-site-nginx "Share on WhatsApp")

For agents: Copy as Markdown [.md](https://streethosting.com.br/en/guides/vps/host-react-vite-static-site-nginx.md)

In this guide 8 sections

* [What the build produces](https://streethosting.com.br/en/guides/vps/host-react-vite-static-site-nginx#como-funciona)
* [Build and upload to the VPS](https://streethosting.com.br/en/guides/vps/host-react-vite-static-site-nginx#enviar)
* [The Nginx server block](https://streethosting.com.br/en/guides/vps/host-react-vite-static-site-nginx#nginx)
* [Caching and gzip](https://streethosting.com.br/en/guides/vps/host-react-vite-static-site-nginx#cache)
* [HTTPS](https://streethosting.com.br/en/guides/vps/host-react-vite-static-site-nginx#https)
* [Automatic deploy](https://streethosting.com.br/en/guides/vps/host-react-vite-static-site-nginx#deploy-automatico)
* [When you do not even need a VPS](https://streethosting.com.br/en/guides/vps/host-react-vite-static-site-nginx#precisa-vps)
* [Where to run this](https://streethosting.com.br/en/guides/vps/host-react-vite-static-site-nginx#onde-rodar)

Quick answer

Run `npm run build` to generate the `dist` folder, upload its contents to `/var/www/site` on the VPS and point an Nginx server block at that folder with `root`. For React routes to work when the page is reloaded, use `try_files $uri $uri/ /index.html`. Give the files under `/assets/`, which have a hash in their names, long caching, and give `index.html` no caching. There is no need to install Node on the VPS.

## What the build produces[](https://streethosting.com.br/en/guides/vps/host-react-vite-static-site-nginx#como-funciona)

A React project created with Vite only runs as development code while you use `npm run dev`. To publish, `npm run build` compiles everything and writes the `dist` folder:

`dist/ index.html favicon.svg assets/ index-DiwrgTda.js index-B3kQ91xe.css`

This is an ordinary static site: HTML, CSS, JavaScript and images. There is no process to keep running, no port to listen on and no language to install on the VPS. Nginx reads the files from disk and serves them, a fast job that uses very little memory. Also notice the names of the files in `assets`: the random part is a hash of the content, and it changes whenever the file changes. That property is what allows the aggressive caching further down.

Vite variables that start with `VITE_` are copied into the JavaScript at build time, and any visitor can read them. Use them only for public values, like your API URL. Private keys, tokens and passwords stay in a backend.

## Build and upload to the VPS[](https://streethosting.com.br/en/guides/vps/host-react-vite-static-site-nginx#enviar)

On your computer, in the project folder:

`npm ci npm run build`

On the VPS, install Nginx and prepare the site folder. Give ownership of the folder to the user who will upload the files and keep the Nginx group as the group, so it can read them:

`sudo apt update sudo apt install -y nginx sudo mkdir -p /var/www/site sudo chown -R $USER:www-data /var/www/site sudo chmod -R 755 /var/www/site`

Now upload the contents of the `dist` folder. There are three ways, from the simplest to the most repeatable:

1. **Graphical program:** with WinSCP or FileZilla, drag the contents of `dist` into `/var/www/site`. The step by step is in the guide on [WinSCP and FileZilla with SFTP](https://streethosting.com.br/en/guides/vps/winscp-filezilla-sftp-vps-windows).
2. **scp:** `scp -r dist/* usuario@IP_DA_VPS:/var/www/site/`, in the Linux or Mac terminal. On Windows, the simplest route is the graphical program from the previous item.
3. **rsync:** `rsync -avz --delete dist/ usuario@IP_DA_VPS:/var/www/site/`. It sends only what changed and, with `--delete`, removes from the VPS the files that are no longer in the build. Windows does not ship rsync, so use WSL or the GitHub Actions workflow in the automatic deploy section.

The trailing slash in `dist/` matters in rsync: with it, the contents of the folder go inside `/var/www/site`. Without it, it would create `/var/www/site/dist`. The guide on [transferring files with scp and rsync](https://streethosting.com.br/en/guides/vps/transfer-files-to-vps-scp-rsync) explains each option.

## The Nginx server block[](https://streethosting.com.br/en/guides/vps/host-react-vite-static-site-nginx#nginx)

First, point the domain DNS at the VPS IP, as in the guide on [pointing a domain at your VPS](https://streethosting.com.br/en/guides/vps/point-domain-to-vps). Then create the file `/etc/nginx/sites-available/site`:

`server { listen 80; server_name meusite.com.br www.meusite.com.br; root /var/www/site; index index.html; location / { try_files $uri $uri/ /index.html; } }`

`sudo ln -s /etc/nginx/sites-available/site /etc/nginx/sites-enabled/ sudo nginx -t sudo systemctl reload nginx`

`root` says where the files are. `try_files` tries, in this order, a file with the requested path, a folder with that name and, last of all, `/index.html`. That last step is what makes an SPA work.

Without it, someone who opens the site at the root and navigates through the React links notices nothing, because JavaScript swaps the screen without asking the server for anything. The problem shows up when the person reloads on `/sobre` or opens a direct link to it: Nginx looks for a `/var/www/site/sobre` file, does not find it and returns 404. With the fallback, it serves index.html, React loads and resolves the route on its own.

If your router uses the hash in the URL (the address has a # before the path), the server never sees the route and try\_files is not needed. If the site lives in a subfolder, like `/app/`, also set the `base` option in `vite.config`, and the Nginx `location` has to follow.

## Caching and gzip[](https://streethosting.com.br/en/guides/vps/host-react-vite-static-site-nginx#cache)

Each kind of file calls for a different cache. The files in `assets` have the hash in the name, so a file with that name never changes: you can ask the browser to keep it for a year. `index.html` always has the same name and points to the files of the current version, so it has to be checked on every visit.

| File                                                 | Cache                     | Reason                                                                 |
| ---------------------------------------------------- | ------------------------- | ---------------------------------------------------------------------- |
| /assets/ (JS, CSS, fonts with hash)                  | 1 year, immutable         | The name changes when the content changes, so it never goes stale      |
| index.html                                           | Revalidate on every visit | It points to the assets of the current version and must be revalidated |
| Images and icons without a hash in the public folder | Short cache, a few days   | The name stays the same when the file changes                          |

The complete server block, with caching and gzip:

`server { listen 80; server_name meusite.com.br www.meusite.com.br; root /var/www/site; index index.html; gzip on; gzip_vary on; gzip_min_length 1024; gzip_types text/css text/javascript application/javascript application/json image/svg+xml text/plain; location /assets/ { add_header Cache-Control "public, max-age=31536000, immutable"; try_files $uri =404; } location = /index.html { add_header Cache-Control "no-cache"; } location / { try_files $uri $uri/ /index.html; } }`

* **location /assets/ with =404:** an assets file that does not exist should return 404, not receive index.html. If the fallback applied here, the browser would get HTML in place of JavaScript and show a confusing error.
* **location = /index.html:** the try\_files fallback redirects internally to index.html, so this block covers the site root and every React route with the no caching header.
* **gzip:** Nginx already compresses HTML by default when gzip is on. The type list includes CSS, JavaScript, JSON and SVG, which are text and shrink a lot. Images like PNG and JPG are already compressed and are left out.

Test with `curl -I https://meusite.com.br/assets/ARQUIVO.js` and check the `cache-control` in the response. To see gzip, use `curl -sI -H "Accept-Encoding: gzip" URL` and look for `content-encoding: gzip`.

If you delete the old folder on every deploy, someone with the page already open may request an old file that no longer exists and get a 404 until they reload. It is rare and a refresh fixes it. If you would rather avoid it, upload without `--delete` and clean up old assets from time to time.

## HTTPS[](https://streethosting.com.br/en/guides/vps/host-react-vite-static-site-nginx#https)

With the domain pointing at the VPS and the site opening over HTTP, install the free Let's Encrypt certificate. With certbot:

`sudo apt install -y certbot python3-certbot-nginx sudo certbot --nginx -d meusite.com.br -d www.meusite.com.br`

certbot edits the site file, adds the port 443 block and the redirect from HTTP to HTTPS, and schedules automatic renewal. The details and how to verify renewal are in the guide on [an SSL certificate with Let's Encrypt on Nginx](https://streethosting.com.br/en/guides/vps/lets-encrypt-ssl-certificate-vps). After certbot, check that your caching and gzip are still in the 443 block and that `sudo nginx -t` passes. If the site also talks to an API of yours, the same server block can pass a path like `/api/` on to the backend, as shown in the guide on [Nginx as a reverse proxy](https://streethosting.com.br/en/guides/vps/nginx-reverse-proxy-vps), which saves you from configuring CORS.

## Automatic deploy[](https://streethosting.com.br/en/guides/vps/host-react-vite-static-site-nginx#deploy-automatico)

Uploading by hand works, but it pays off more when every push to the main branch publishes the site on its own. GitHub Actions does the build in the cloud and sends the folder to the VPS with rsync. First, create an SSH key just for this, with no passphrase, put the public half in the VPS user's `~/.ssh/authorized_keys` and store the private half under **Settings, Secrets and variables, Actions** in the repository, with the names below.

* `VPS_HOST`: the VPS IP or domain.
* `VPS_USER`: the SSH user.
* `VPS_SSH_KEY`: the contents of the private key.

Then create the file `.github/workflows/deploy.yml` in the project:

`name: Deploy do site on: push: branches: [main] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 - uses: actions/setup-node@v7 with: node-version: 24 cache: npm - run: npm ci - run: npm run build - name: Enviar para a VPS env: VPS_HOST: ${{ secrets.VPS_HOST }} VPS_USER: ${{ secrets.VPS_USER }} VPS_SSH_KEY: ${{ secrets.VPS_SSH_KEY }} run: | mkdir -p ~/.ssh echo "$VPS_SSH_KEY" > ~/.ssh/id_ed25519 chmod 600 ~/.ssh/id_ed25519 ssh-keyscan -H "$VPS_HOST" >> ~/.ssh/known_hosts rsync -az --delete dist/ "$VPS_USER@$VPS_HOST:/var/www/site/"`

On every push to main, Actions installs the dependencies, builds and syncs the folder. The SSH user needs write permission on `/var/www/site`, which is what the `chown` in the upload section took care of. For variations, like restricting the key to a single command, see the guide on [deploying with GitHub Actions to your VPS](https://streethosting.com.br/en/guides/vps/github-actions-deploy-to-vps).

If your project uses public `VITE_` variables, pass the values in the build step with the `env` key, because they are read at the moment `npm run build` runs.

## When you do not even need a VPS[](https://streethosting.com.br/en/guides/vps/host-react-vite-static-site-nginx#precisa-vps)

Let us be straightforward: a purely static site, with no backend, does not need a VPS. There are free static hosting services that publish this folder with HTTPS and a CDN ready to go, and deploy on every push without you configuring a server. For a portfolio page, a landing page or a study project, those services are the shortest path.

A VPS starts to make sense when:

* **You already have a VPS** with other things running, and one more Nginx server block costs nothing extra.
* **The site talks to a backend of yours** on the same domain, like an API in Node, Python or Go, and you want everything behind the same Nginx, with no CORS.
* **You want full control**of headers, redirects, logs and rules, without a platform's plan limits.
* **You host several sites and projects** and prefer a single server with a fixed cost.

One honest limit of the format: an SPA delivers an almost empty HTML and builds the screen in the browser. For a site that depends on Google search, the content may be harder to index than on a page rendered on the server. If that matters to you, consider a framework with server rendering or prerendering, such as [Next.js on a VPS](https://streethosting.com.br/en/guides/vps/host-nextjs-on-vps).

## Where to run this[](https://streethosting.com.br/en/guides/vps/host-react-vite-static-site-nginx#onde-rodar)

For Nginx to serve files, any Linux VPS will do, and a static site uses very few resources. On [StreetHosting VPS](https://streethosting.com.br/en/vps) you get root access to install Nginx and certbot, and the Xeon VPS from R$ 26.00 per month, with 2 vCPU, 2 GB DDR4 and 20 GB NVMe, holds several static sites alongside a small API.

All VPS are in São Paulo, which helps response time for visitors in Brazil, with AntiDDoS included, up to 5 TB of traffic per month and activation in about 60 seconds after Pix or card approval.

In this guide

* [What the build produces](https://streethosting.com.br/en/guides/vps/host-react-vite-static-site-nginx#como-funciona)
* [Build and upload to the VPS](https://streethosting.com.br/en/guides/vps/host-react-vite-static-site-nginx#enviar)
* [The Nginx server block](https://streethosting.com.br/en/guides/vps/host-react-vite-static-site-nginx#nginx)
* [Caching and gzip](https://streethosting.com.br/en/guides/vps/host-react-vite-static-site-nginx#cache)
* [HTTPS](https://streethosting.com.br/en/guides/vps/host-react-vite-static-site-nginx#https)
* [Automatic deploy](https://streethosting.com.br/en/guides/vps/host-react-vite-static-site-nginx#deploy-automatico)
* [When you do not even need a VPS](https://streethosting.com.br/en/guides/vps/host-react-vite-static-site-nginx#precisa-vps)
* [Where to run this](https://streethosting.com.br/en/guides/vps/host-react-vite-static-site-nginx#onde-rodar)

## Frequently asked questions

Why do my routes return 404 when I refresh the page?

On a React site with browser routes, like /about, that path does not exist as a file on the server. Nginx has to return index.html for any path that is not a real file, and React resolves the route. You do that with try\_files $uri $uri/ /index.html.

Do I need to install Node on the VPS to host a Vite site?

No. The build produces plain HTML, CSS and JavaScript files, and Nginx only serves them. Node is needed on the machine where you run npm run build, which can be your computer or GitHub Actions.

Why can I not cache index.html for a long time?

index.html points to the files with a hash in the name, like index-Ab12Cd.js. If it stays stored in the browser, the visitor keeps loading the old version after a deploy. The files in the assets folder can have long caching because the name changes on every build, but index.html must always be revalidated.

Can I put secret values in the Vite .env file?

No. Everything that starts with VITE\_ is copied into the JavaScript during the build and any visitor can read it. A private API key has to live in a backend, never in the static site.

Does a static site really need a VPS?

No. Free static hosting services serve a site like this just fine. A VPS is worth it when you already have one, want a backend on the same domain, need control over headers and redirects or want to put several projects on one server.

Next step

See VPS plans

Root VPS in Brazil with NVMe and Anti-DDoS.

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

## Related guides

[VPS Intermediate How to set up Nginx as a reverse proxy on a VPS Your app runs on an internal port and you want to serve it on a domain with HTTPS. Nginx as a reverse proxy solves that and also brings several apps together in one place. 3 min Read guide](https://streethosting.com.br/en/guides/vps/nginx-reverse-proxy-vps) [VPS Beginner SSL certificate on a VPS with Let's Encrypt and Nginx A site without the padlock loses trust and rankings. This guide shows how to issue, renew and audit a free SSL certificate on your VPS with Nginx and Certbot. 4 min Read guide](https://streethosting.com.br/en/guides/vps/lets-encrypt-ssl-certificate-vps) [VPS Intermediate GitHub Actions deploy to VPS: step-by-step pipeline Every push to the main branch can build, upload and restart your application on the VPS without anyone opening a terminal. Here is how to set up that flow with a non-root deploy user, well-guarded secrets and protection against simultaneous deploys. 10 min Read guide](https://streethosting.com.br/en/guides/vps/github-actions-deploy-to-vps)

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