Technology

Why Put the SPA and API on One Domain?

{
“title”: “Hosting React, Vue and Angular SPAs with One API Domain on Nginx”,
“content”: “

Modern front‑end stacks like React, Vue and Angular make it very easy to build fast, interactive single page applications (SPAs). The tricky part often comes later: deciding how to host the built SPA and its backend API cleanly on one domain, with correct Nginx routing and a solid SSL/TLS architecture. Developers frequently start with separate ports or domains during development, then run into CORS problems, SEO concerns, cookie issues and complex SSL setups when moving to production. In this article, we will walk through a practical, production‑ready way to host your SPA and API behind Nginx on a single domain, using clear URL routing and modern HTTPS. We will focus on static builds of React, Vue and Angular apps, a backend API (Node.js, PHP, Python, etc.), and Nginx acting as a reverse proxy and static file server. The goal is to help you ship a simple, predictable architecture that scales from a small VPS to larger dedicated or colocation setups at dchost.com without surprising you six months later.

nnnn

Separating the frontend (for example on app.example.com) and the API (for example on api.example.com) is a common pattern, but for many projects, using a single domain like example.com for everything is simpler and more robust. In our own projects and in customer environments we host at dchost.com, we see several recurring advantages when everything is served from one origin.

nn

1. No CORS Headaches

n

When the SPA HTML, JavaScript and API endpoints all live under the same scheme/domain/port (for example https://example.com), the browser treats them as the same origin. That means:

n

    n

  • No need to configure Access-Control-Allow-Origin for your own frontend.
  • n

  • Fewer preflight OPTIONS requests and less room for subtle misconfigurations.
  • n

  • Clean cookie handling (session or auth cookies stay first‑party).
  • n

n

This alone removes an entire class of support tickets we see: ‘the API works in Postman, but not from the frontend.’

nn

2. Simpler SSL/TLS and Certificates

n

With one domain, you usually need a single certificate covering example.com (optionally also www.example.com). You can terminate TLS on Nginx, then route plain HTTP internally to the SPA files and API service. This works especially well with automated SSL such as Let’s Encrypt, where you can use a single ACME flow. If you want to dive deeper into certificate choices and automation, you can also check our article why free SSL with Let’s Encrypt and auto‑renewal matters on modern hosting stacks.

nn

3. Cleaner SEO and Analytics

n

Search engines and analytics tools tend to be simpler to configure when everything lives under one domain. Even though SPAs need some care for rendering and meta tags, at least your canonical URLs live in one place and you do not split authority across multiple subdomains. If you are still planning your domain and DNS side, our guide on how domain, DNS, server and SSL fit together on a typical hosting setup is a good background read.

nn

4. Fewer Moving Parts for Small Teams

n

For smaller teams and early‑stage projects, operating fewer domains and certificates simply reduces operational overhead. You have one Nginx virtual host to reason about, one deployment path and one SSL renewal process.

nn

High‑Level Architecture: How the Pieces Fit Together

nn

Let’s start with a minimal but realistic diagram for a single‑domain SPA + API stack:

n

    n

  • Nginx listening on ports 80 and 443 on example.com.
  • n

  • Static SPA build (React, Vue, Angular) located in a directory such as /var/www/spa.
  • n

  • API backend running on an internal port, for example 127.0.0.1:3000 (Node.js) or 127.0.0.1:9000 (PHP‑FPM behind FastCGI), or a separate internal container.
  • n

  • Nginx routing:
      n

    • / and SPA routes like /dashboard, /users/42 → served from SPA index.html with try_files.
    • n

    • /assets/ or /static/ → served as static files.
    • n

    • /api/ → proxied to backend API.
    • n

    n

  • n

  • Single TLS termination in Nginx with HTTP/2 or HTTP/3 enabled.
  • n

nn

You can host this stack on a Linux VPS, a dedicated server or your own hardware in colocation at dchost.com. The configuration itself looks almost identical across these environments; the main difference is how many CPU/RAM/IOPS you allocate and how you handle scaling, which we help many customers plan.

nn

Preparing Your React, Vue or Angular App for Nginx

nn

On the frontend side, the key is to produce a static production build and ensure that client‑side routing plays nicely with Nginx. Let’s briefly look at what each framework typically outputs and what Nginx expects.

nn

1. React (Create React App, Vite, Next.js SPA mode)

n

For a classic SPA (not server‑side rendered):

n

    n

  • Create React App: npm run build outputs a build/ directory with index.html, static/ assets, hashed JS/CSS.
  • n

  • Vite React template: npm run build outputs a dist/ directory with a similar structure.
  • n

n

In both cases, you will copy the resulting directory to your server (for example /var/www/spa) and configure Nginx to serve index.html for unknown paths. That’s what enables URLs like /dashboard to work with React Router in browserHistory mode.

nn

2. Vue (Vue CLI, Vite)

n

Vue behaves similarly:

n

    n

  • Vue CLI: npm run builddist/
  • n

  • Vite Vue: npm run builddist/
  • n

n

Again, deploy the dist/ folder to Nginx and route SPA paths with try_files. If you use Vue Router in history mode, you must ensure that Nginx rewrites all non‑API, non‑asset requests back to index.html.

nn

3. Angular

n

For Angular:

n

    n

  • Run ng build --configuration production (or --prod on older versions).
  • n

  • This outputs a dist/<project-name>/ directory.
  • n

n

Angular uses its own router for SPA navigation; the Nginx side is essentially the same: serve the built index.html and static assets, and let the framework handle routing in the browser.

nn

Folder Layout on the Server

n

A simple layout we often use on VPS and dedicated servers at dchost.com looks like this:

n

/var/www/example.com/n  spa/           # React/Vue/Angular build outputn  api/           # Optional API code (if not containerized)n  logs/n  releases/      # If you use a symlink-based deployment flown

n

You can deploy new SPA versions by building locally or in CI, uploading to a new directory under releases/ and then atomically switching a symlink spa -> releases/2025-12-07T10-30-00. We describe this flow in detail in our guide on zero‑downtime CI/CD to a VPS using rsync and symlinked releases.

nn

Nginx Routing for SPAs: HTML5 History, Assets and Multiple Apps

nn

Nginx’s job is to map different URL patterns to the right target: the SPA, static assets, or the backend API. The central directive is try_files, which checks whether a file exists on disk and, if not, falls back to your index.html.

nn

Basic Nginx Server Block for a Single SPA

n

Here is a simplified HTTPS server block (we will add SSL details later) for a React/Vue/Angular SPA at example.com with an /api backend:

nn

server {n    listen 80;n    server_name example.com www.example.com;nn    # Redirect all HTTP to HTTPSn    return 301 https://$host$request_uri;n}nnserver {n    listen 443 ssl http2;n    server_name example.com www.example.com;nn    root /var/www/example.com/spa;n    index index.html;nn    # SSL configuration will go here (certificates, protocols, ciphers)nn    # Serve static files directlyn    location /assets/ {n        try_files $uri =404;n    }nn    location /static/ {n        try_files $uri =404;n    }nn    # API requests are proxied to the backendn    location /api/ {n        proxy_pass http://127.0.0.1:3000/;n        proxy_http_version 1.1;n        proxy_set_header Host $host;n        proxy_set_header X-Real-IP $remote_addr;n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;n        proxy_set_header X-Forwarded-Proto $scheme;n    }nn    # Everything else is handled by the SPAn    location / {n        try_files $uri $uri/ /index.html;n    }n}n

nn

Key points:

n

    n

  • location /api/ catches all API calls and forwards them to the backend server on 127.0.0.1:3000.
  • n

  • location / uses try_files to:
      n

    • Serve real files ($uri) when they exist (CSS, JS, images).
    • n

    • Otherwise fall back to /index.html, letting the SPA router handle the path.
    • n

    n

  • n

  • HTTP is redirected to HTTPS in a separate server block to enforce secure access.
  • n

nn

Handling HTML5 History Mode Routes

n

For SPAs using HTML5 history mode (React Router BrowserRouter, Vue Router history mode, Angular default), direct navigation to /dashboard or /users/42 should load the same index.html file. The try_files line above handles exactly that scenario. If you forget this, Nginx will return 404 for every deep link.

nn

Multiple SPAs Under One Domain

n

Sometimes you want multiple frontends under one domain, for example:

n

    n

  • https://example.com/ → marketing site (static or CMS).
  • n

  • https://example.com/app/ → main React app.
  • n

  • https://example.com/admin/ → separate Vue admin panel.
  • n

n

You can isolate them by using different location blocks and alias roots:

nn

root /var/www/example.com/public;  # Marketing site rootnnlocation /app/ {n    alias /var/www/example.com/spa-main/;n    index index.html;n    try_files $uri $uri/ /app/index.html;n}nnlocation /admin/ {n    alias /var/www/example.com/spa-admin/;n    index index.html;n    try_files $uri $uri/ /admin/index.html;n}n

nn

Notes:

n

    n

  • Use alias rather than root inside nested locations so that /app/ maps cleanly to your SPA directory.
  • n

  • Ensure the built apps are configured with proper base paths (for Angular) or publicPath/base options (for React/Vue) so that asset URLs are correct under subdirectories.
  • n

nn

Proxying the API Through Nginx and Avoiding CORS

nn

With the SPA and API under one domain, your frontend can call /api/... directly. Nginx will then forward the request to the backend service, which may run on the same server or another internal host.

nn

Basic Reverse Proxy Setup

n

The earlier example already showed a minimal location /api/ block. Let’s expand it slightly for better resilience:

nn

upstream api_backend {n    server 127.0.0.1:3000;  # Could be multiple servers for load balancingn    keepalive 32;n}nnserver {n    # ... SSL, root, etc.nn    location /api/ {n        proxy_pass http://api_backend/;n        proxy_http_version 1.1;nn        proxy_set_header Host $host;n        proxy_set_header X-Real-IP $remote_addr;n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;n        proxy_set_header X-Forwarded-Proto $scheme;nn        proxy_read_timeout 60s;n        proxy_connect_timeout 5s;nn        # Optional: limit upload sizen        client_max_body_size 10m;n    }n}n

nn

Using an upstream block lets you add more API servers later without changing the SPA. Nginx will handle simple load balancing for you.

nn

When Do You Still Need CORS?

n

Even with one domain, there are a few cases where CORS still matters:

n

    n

  • Your SPA consumes a third‑party API on a different domain.
  • n

  • You host multiple products under different domains but share one API.
  • n

  • Some internal tools run from a different origin (for example, internal dashboards).
  • n

n

In that case, you can configure CORS either in your backend application or directly in Nginx using add_header directives. For many internal or B2B apps, however, keeping your main SPA and main API on the same domain is the cleanest approach and saves you from a lot of complexity.

nn

Authentication, Cookies and SameSite

n

When everything is on one domain, you can safely use first‑party cookies for authentication. You should still set modern flags such as Secure, HttpOnly and an appropriate SameSite value. If you want to dive deeper into security headers and cookies, our guide on HTTP security headers like HSTS and CSP and our article about configuring SameSite, Secure and HttpOnly cookies correctly on Nginx and Apache are both good companions to this setup.

nn

SSL/TLS Architecture for a SPA + API on Nginx

nn

Now let’s look at the HTTPS side. A clean TLS configuration improves security, browser compatibility and performance. Getting it right once saves you a lot of future work.

nn

1. Certificate Strategy

n

For a single domain SPA + API stack, you typically need:

n

    n

  • A certificate for example.com (CN and/or SAN).
  • n

  • Optionally also www.example.com in the same certificate.
  • n

n

You can use a DV certificate from a commercial CA or a Let’s Encrypt certificate obtained via ACME HTTP‑01 or DNS‑01 challenge. The important part is that Nginx has ssl_certificate and ssl_certificate_key paths pointing to the live certificate files and that you have automation in place to renew them. At dchost.com we help many customers configure automated ACME flows both on shared hosting panels and on VPS/dedicated servers.

nn

2. A Practical Modern TLS Config

n

Here is a condensed but realistic TLS setup for Nginx:

nn

server {n    listen 443 ssl http2;n    server_name example.com www.example.com;nn    root /var/www/example.com/spa;n    index index.html;nn    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;n    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;nn    ssl_protocols TLSv1.2 TLSv1.3;n    ssl_prefer_server_ciphers on;nn    ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:n                 ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:n                 ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305';nn    ssl_session_timeout 1d;n    ssl_session_cache shared:SSL:10m;nn    ssl_stapling on;n    ssl_stapling_verify on;nn    add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains' always;nn    # ... locations for /, /api, /assets etc.n}n

nn

This setup:

n

    n

  • Enables TLS 1.2 and 1.3, which is the practical minimum in 2025.
  • n

  • Enables OCSP stapling for better TLS performance and reliability.
  • n

  • Adds HSTS to enforce HTTPS for future visits.
  • n

n

For a deeper dive into what to change when TLS standards evolve, see our article on SSL/TLS protocol updates and what to change on your servers and when.

nn

3. HTTP to HTTPS Redirect

n

You almost always want to redirect all HTTP traffic to HTTPS to avoid serving mixed content or leaking sensitive data. The minimal server block for port 80 is:

nn

server {n    listen 80;n    server_name example.com www.example.com;n    return 301 https://$host$request_uri;n}n

nn

If you use Let’s Encrypt with HTTP‑01 challenges, you may additionally need to allow access to /.well-known/acme-challenge/ before redirecting, or you can terminate ACME on another path or use DNS‑01 challenges. Plan that at the beginning so you do not accidentally block certificate renewal later.

nn

4. Internal HTTP Only Between Nginx and API

n

Inside the same server, it is perfectly fine to use plain HTTP between Nginx and the backend API (for example 127.0.0.1:3000). The public traffic is fully encrypted up to Nginx; internal localhost traffic is not exposed to the internet. If you communicate with an API running on another machine or in another data center, consider mTLS or at least HTTPS between nodes, especially for sensitive data.

nn

Deployment Workflow and Environments

nn

A clean deployment flow is just as important as the initial architecture. You want to be able to update your SPA bundle or API code without downtime and without half‑deployed states where some users see the old frontend and others hit a new API version.

nn

1. SPA Deployment Flow

n

A simple, robust flow we use often looks like this:

n

    n

  1. Build the SPA in CI (for example a pipeline that runs npm ci && npm run build).
  2. n

  3. Upload the build directory to the server under a timestamped path (releases/2025-12-07T10-30-00/).
  4. n

  5. Update a symlink spa -> releases/2025-12-07T10-30-00.
  6. n

  7. Optionally reload Nginx (not strictly required if only static files changed).
  8. n

n

This gives you an instant rollback option: repoint the symlink to the previous release and you are back to a known state.

nn

2. API Deployment Flow

n

For the API, you typically have a long‑running process or pool:

n

    n

  • Node.js with a process manager (like systemd or PM2).
  • n

  • PHP‑FPM pools for PHP frameworks like Laravel or Symfony.
  • n

  • Python (Gunicorn/Uvicorn) behind systemd.
  • n

n

On a VPS or dedicated server, you can run your API as a systemd service listening on an internal port and let Nginx proxy to it. If you are deciding where to host your Node.js or similar backend code, our guide on hosting Node.js apps on shared hosting, cPanel or VPS walks through realistic scenarios and trade‑offs.

nn

3. Keeping Frontend and Backend in Sync

n

One common concern is: what happens if the SPA and API versions do not match? Some practical tips:

n

    n

  • Design your API to be backward compatible for at least one SPA release.
  • n

  • Deploy the API first, then switch the SPA symlink to the new build.
  • n

  • Use feature flags and environment variables rather than hard‑coding URLs.
  • n

  • Version your API endpoints if you need to make breaking changes (/api/v1/, /api/v2/), and route them separately in Nginx.
  • n

nn

4. Staging and Production

n

It is often worth having a staging environment like staging.example.com that mirrors your production Nginx config and TLS settings but uses a separate API database. This lets you test routing rules, new SPA builds and API updates against real‑looking infrastructure without affecting users. DNS and SSL for staging follow the same logic as production; if you are planning a new domain or subdomain for staging, our checklist for connecting a new domain to hosting with DNS and SSL is a handy reference.

nn

When You Might Still Separate Domains or Subdomains

nn

While one domain is a great default, there are scenarios where splitting makes sense:

n

    n

  • Multi‑tenant SaaS where each customer brings their own domain for the frontend but APIs stay on a vendor domain.
  • n

  • Very large organisations with separate teams, lifecycles and compliance requirements for frontend and backend.
  • n

  • Specialised CDN usage where you want to cache the SPA on a separate hostname with aggressive policies while the API remains more dynamic and constrained.
  • n

n

Even then, Nginx reverse proxy patterns, TLS best practices and deployment workflows remain largely the same. You just add more server blocks and possibly more certificates.

nn

Putting It All Together

nn

Hosting React, Vue and Angular SPAs with an API on one domain is less about magic Nginx tricks and more about a clean, predictable structure: a static build served by Nginx, a well‑scoped /api/ reverse proxy, and a modern TLS configuration that terminates HTTPS in one place. Once you decide that https://example.com is your single origin, the rest is mostly about mapping URL paths carefully and keeping your SSL/TLS setup healthy and automated. From there, you can grow: move the API to a separate internal server, add a CDN in front of Nginx, or scale out with more VPS or dedicated nodes at dchost.com as traffic grows.

nn

If you are planning a new SPA or refactoring an existing stack, this is a good moment to also revisit your backup, monitoring and security posture. Our articles on automating 3‑2‑1 backups on cPanel, Plesk and VPS and on practical VPS hardening against real‑world threats complement the routing and SSL topics we covered here.

nn

At dchost.com we work with teams that range from a single developer on their first VPS to seasoned DevOps teams managing multiple dedicated or colocated servers. If you would like help designing or migrating your SPA + API architecture, or you simply want a stable home for your Nginx, TLS and database stack, our domain, hosting, VPS, dedicated and colocation services are built exactly for that. Start with one clean domain, one solid Nginx config and safe HTTPS – and grow from there without rewriting everything six months down the line.

“,
“focus_keyword”: “Hosting React Vue Angular SPA with Nginx routing and SSL”,
“meta_description”: “Learn how to host React, Vue and Angular SPAs with an API on one domain using Nginx. Routing, proxying, SSL/TLS and deployment architecture explained in depth.”,
“faqs”: [
{
“question”: “Why is it better to host my React, Vue or Angular SPA and API on one domain?”,
“answer”: “Putting your SPA and API on one domain keeps everything under a single browser origin (same scheme, domain and port). That means you avoid most CORS configuration, reduce preflight OPTIONS requests and simplify cookie‑based authentication because cookies remain first‑party. SSL/TLS is also easier: you only need one certificate and one Nginx termination point. This reduces operational overhead, especially for small teams, and makes SEO and analytics configuration more straightforward because all URLs live under the same domain.”
},
{
“question”: “How should I configure Nginx for a SPA using React Router, Vue Router or Angular routing?”,
“answer”: “You should serve the built SPA as static files but use a fallback to index.html for unknown paths. In Nginx this usually means a server block with a root pointing to your build directory and a location like: “location / { try_files $uri $uri/ /index.html; }”. This allows deep links such as /dashboard or /users/42 to work with HTML5 history mode. For APIs, create a separate location like /api/ that uses proxy_pass to forward requests to your backend service running on an internal port.”
},
{
“question”: “How do I terminate SSL/TLS for my SPA and API on Nginx?”,
“answer”: “Terminate SSL/TLS once at Nginx on port 443, then route traffic internally over HTTP to your SPA files and API backend. In the HTTPS server block, configure ssl_certificate and ssl_certificate_key to point to your certificate files (Let’s Encrypt or commercial). Enable modern protocols (TLS 1.2 and 1.3) and features like OCSP stapling, and add HSTS for stricter HTTPS. A separate port 80 server block should simply redirect all traffic to HTTPS. The API itself does not need to handle TLS if it only accepts connections from Nginx on localhost or a private network.”
},
{
“question”: “Can I host multiple SPAs (for example, app and admin) on the same domain behind Nginx?”,
“answer”: “Yes. You can host multiple SPAs under different paths, such as /app/ and /admin/, by using dedicated Nginx location blocks with alias. For example, “location /app/ { alias /var/www/example.com/spa-main/; try_files $uri $uri/ /app/index.html; }”. Make sure your build configuration (publicPath or base href) matches the subdirectory so assets are loaded correctly. The API can still live under /api/, shared by both SPAs, keeping your TLS and backend infrastructure simple.”
},
{
“question”: “What kind of server do I need to run this Nginx SPA + API setup?”,
“answer”: “Technically you can run this architecture on anything from a small VPS to a powerful dedicated server or even your own colocated hardware, depending on traffic and resource needs. The key components are a Linux environment, Nginx, your chosen runtime for the API (for example Node.js, PHP‑FPM or Python) and enough CPU, RAM and disk IO to handle your workload. At dchost.com we usually recommend starting with a modest VPS for early projects and scaling up or out as your metrics grow, reusing the same Nginx routing and SSL patterns described in this article.”
}
]
}