Demystifying CORS: A Practical Guide to Using Nginx Reverse Proxy
Cross-Origin Resource Sharing (CORS) can often become a stumbling block when developing and deploying applications with separate backends and frontends. This article aims to unravel the mystery behind this concept and present a solution using Nginx as a reverse proxy.
A Tale of Two Domains
Consider this scenario: you’re developing a web application with a ReactJS frontend and an ExpressJS backend. The codebase is organized in a monorepo, indicating both the frontend and backend code live in the same repository. For deployment, you decide to host your frontend at `domainA.com` and your backend at `domainB.com`.
However, this leads to an issue — your frontend can’t communicate with your backend due to CORS restrictions. Your browser sees `domainA.com` and `domainB.com` as separate origins and blocks any attempt from the frontend to fetch resources from the backend, treating it as a potential security risk.
So, how do you get around this without compromising security or resorting to “wildcard” CORS settings?
Enter Nginx: The Reverse Proxy Solution
Nginx, a popular open-source web server, provides a powerful feature known as reverse proxying. This means Nginx can accept client requests and, based on specific rules, forward these requests to appropriate servers (in our case, the frontend or backend server).
By utilizing Nginx as a reverse proxy, you can avoid CORS issues altogether. The solution involves configuring Nginx to serve both your frontend and backend from the same domain, eliminating the cross-origin problem.
Here’s how it works:
- The frontend (ReactJS): Configure Nginx to serve your frontend application directly to users who visit `domainA.com`. This involves storing the static files (HTML, CSS, JavaScript) built by React on the server where Nginx is running.
- The backend (ExpressJS): Set up Nginx to forward requests made to `domainA.com/api` to your backend server. Regardless of whether your backend server is on the same machine or a different one, Nginx will redirect all `/api` requests to it.
From the perspective of the user’s browser, all requests (both to the frontend and backend) are going to the same domain (`domainA.com`). This setup eliminates cross-origin requests, thus no CORS issues.
Reconfiguring Nginx
Let’s dive into the practical side of things — how do you set up Nginx to achieve this? Here’s an example Nginx configuration:
server {
listen 80;
server_name domainA.com;
location / {
# assuming your frontend files are in /var/www/frontend
root /var/www/frontend;
try_files $uri /index.html;
}
location /api {
# assuming your Express server is running on the same machine
# and listening on port 3000, if it's on a different machine
# replace 'localhost' with the appropriate IP address
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
The `location /` block is for your frontend. It serves files from the `/var/www/frontend` directory. The `location /api` block is for your backend. It forwards requests to the ExpressJS server running at `http://localhost:3000`.
The Monorepo Way
A monorepo (short for monolithic repository) is a
software development strategy where code for many projects is stored in the same repository. It’s popular in large-scale projects since it allows for easier code sharing and dependency management.
While a monorepo doesn’t dictate how you should deploy your applications, it does streamline your workflow. It centralizes the source of truth and simplifies many aspects of project management.
With the configuration above, the deployment becomes straightforward — both frontend and backend can be managed from the same server using Nginx, reducing complexity and keeping your codebase neat and tidy.
The Takeaway
CORS is a necessary but often tricky part of web development. Leveraging the power of Nginx as a reverse proxy, you can build and deploy your applications more seamlessly, eliminating CORS issues while maintaining a well-structured codebase in a monorepo. Remember, the key is to have a unified origin for both your frontend and backend — all under the umbrella of the same domain.
Note: This guide assumes you have some familiarity with Nginx. If you’re not comfortable configuring it yourself, consider working with a DevOps engineer or someone with relevant experience. It’s crucial to get your server configurations correct to avoid potential security and performance issues.