Nginx on ec2 instance does not serve static files - node.js

What was working
I have MERN stack dashboard up and running on AWS EC2 instance.
Ec2 instance is at ec2...aws.com
React app is served on port 5004.
Node app is running on port 5003.
What was changed
The problem started when I set up the domain at GoDaddy to forward (with masking)
from somebusiness.com to ec2.....aws.com.
First, I set up NGINX reverse proxy to serve / as my react app (frontend) and /api as my node app (backend)
(you will find nginx code down below later)
http://somebusiness.com/ <- opens up React app and is working correctly
http://somebusiness.com/api/heartbeat <- not working as I expected (heartbeat is just endpoint to check if the app is alive) but for some reason, does not return application/JSON but rather a text/HTML webpage with the correct 'real URL' inside a frame of some kind:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
  <title>Somebusiness Dashboard</title>
  <meta name="description" content="">
  <meta name="keywords" content="">
</head>
<frameset rows="100%,*" border="0">
  <frame src="http://ec2-...aws.com/api/heartbeat" frameborder="0" />
</frameset>
</html>
The actual URL in the frame is the one that is working as expected:
http://ec2-...aws.com/api/heartbeat <- is working correctly
I think GoDaddy has something to do with this because on GoDaddy I can specify title, description, and keywords for this forwarding. So as backend, I'm forced to use http://ec2-...aws.com/api/ as my backend URL, which is OK for now (it is my secondary problem at the moment since it's just convenient to use the domain name for backend as well)
Main Problem
if i send a request to
http://ec2.....aws.com:5003/uploads/avatars/user1.jpg
the image is loaded OK.
So if i send a request to
http://ec2.....aws.com/api/uploads/avatars/user1.jpg
the image is NOT loaded.
So to recap: http://ec2-...aws.com/api/ is working OK for routes and requests, but not for serving static files. That leads me to believe my nginx setup is wrong, and I've spent countless hours trying all kinds of different setups. Here I present where i left it:
Source & code for help
Since I'm using Amazon Linux 2, I've used its tools to install nginx1 and set-up reverse proxy.
When i used NGINX on my other VPS, there was a bit different structure to it (sites-enabled & sites-available folders). But on this nginx there is only nginx.conf file where I did the setup. (I guess it doesn't make difference, just wanted to note that)
# For more information on configuration, see:
# * Official English Documentation: http://nginx.org/en/docs/
# * Official Russian Documentation: http://nginx.org/ru/docs/
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;
events {
worker_connections 1024;
}
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Load modular configuration files from the /etc/nginx/conf.d directory.
# See http://nginx.org/en/docs/ngx_core_module.html#include
# for more information.
include /etc/nginx/conf.d/*.conf;
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name eyeratereviews.com;
root /home/ec2-user/somebusiness-web-backend;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
include /etc/nginx/mime.types;
location / {
proxy_pass http://127.0.0.1:5004;
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;
}
location /api {
root /home/ec2-user/somebusiness-web-backend/uploads/avatars;
default_type application/json;
proxy_pass http://127.0.0.1:5003;
# Following is necessary for Websocket support
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
}
My node.js project folder structure is like this
...
controllers/
models/
static/
- pictures/
-- logo.png
uploads/
- avatars/
-- user1.jpg
-- user2.jpg
-- ...

Your existing code does not attempt to remove the /api from the front of the URI before passing it upstream. Add a trailing / to both the location and proxy_pass values. For example:
location /api/ {
proxy_pass http://127.0.0.1:5003/;
...
}
See this document for details.
Alternatively, use a rewrite...break to modify the URI instead.
For example:
location /api {
rewrite ^/api(.*)$ $1 break;
proxy_pass http://127.0.0.1:5003;
...
}
See this document for details.

Related

Should I open port 3000 of my server to serve NodeJS application?

I have an Angular + Node.JS app. When I was running the program locally I defined a baseurl = http://localhost:3000/ in my Angular app and used this prefix for accessing to my NodeJS backend in my program defined links, but now when I wanted to deploy my app on a remote server, I changed the baseurldefinition to the baseurl = http://111.222.333.444:3000/(111.222.333.444 is my server ip address for example), but it doesn't work!
How should I connect my Angular app to the NodeServer on a remote server?
EDIT: This is my /etc/nginx/nginx.conf file content:
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;
events {
worker_connections 1024;
}
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Load modular configuration files from the /etc/nginx/conf.d directory.
# See http://nginx.org/en/docs/ngx_core_module.html#include
# for more information.
include /etc/nginx/conf.d/*.conf;
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /demo/stock-front9/dist/strategy;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location / {
#proxy_pass http://localhost:3000;
#proxy_http_version 1.1;
# First attempt to serve request as file, then
# as directory, then redirect to index(angular) if no file found.
try_files $uri $uri/ /index.html;
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
I would not, I think is better to run the Node app with a tool like PM2 and then place a reverse proxy using Nginx in front of it, PM2 will act as orchestrator over your service while Nginx will provide access only through standard web ports (80, 443).
And in the case of Angular, when compiling, it should generate a static web app which you can serve using the same Nginx reverse proxy, doing it like so you'll save yourself the effort of configuring things like CORS, API routes and so forth, everything will go through Nginx.
Update on an example of Nginx config file
server {
listen 80;
server_name example.org;
location /api {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_redirect off;
proxy_http_version 1.1;
}
location / {
root /path/to/angular/compiled/app;
index index.html;
}
}
And then the angular app should point to the same host.
Good luck and cheers :)
You can still run your angular app locally. And for backend server, you can use proxy.
Please take a look at this.
https://github.com/angular/angular-cli/blob/master/docs/documentation/stories/proxy.md#using-corporate-proxy

Deploy node js express application - cent os

I am trying to deploy a node js application on GoDaddy VPS hosting.
I have uploaded all the files to the server and started the server using pm2
following This Tutorial
My server is running on port 3021 which I want to run on port 80
for a particular domain.
I have completed steps till pm2 in the tutorial but from Nginx part, I cannot understand what to do next.
I have installed Nginx then running this command sudo vi /etc/nginx/sites-available/default
and adding configurations and when I am saving it an error shows [ Error writing /etc/nginx/sites-available/default: No such file or directory ]
I am running apache in the server. Is it possible to do the same using apache??
Edit
Here is my nginx config::
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /var/run/nginx.pid;
include /usr/share/nginx/modules/*.conf;
events {
worker_connections 1024;
}
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
include /etc/nginx/conf.d/*.conf;
}
So if you have pm2 running then you are half way through :) About nginx conf. This command: sudo vi /etc/nginx/sites-available/default probably does not work because the sites-available directory does not exist. Keep in mind that sites-available and sites-enabled are not required by nginx. It's just a good practice to have each server config in a separate file. But nginx will work without them too. If you are not planning to add any more servers, just use the /etc/nginx/nginx.conf file to configure your server. What you need to do is to create a new server block with desired configuration, e.x:
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name yourapp.com www.yourapp.com;
root /var/www/html; # <- for you it can be any other dir
index index.html index.htm # <- or any other file which is your main file
# You want to proxy_pass the traffic on any route to your internal app
location ~ /(.*) { # ~ means that you are using regex
proxy_pass http://localhost:3021/$1$is_args$args; # <- proxy_pass to your internal app
proxy_redirect off;
proxy_read_timeout 60s;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
}
}
Just place the above config into /etc/nginx/nginx.conf inside http block.
Now check your nginx config:
nginx -t
If it's successful, your nginx config is done.
It's not over yet. One more thing to do- open port 80 in the firewall, like so:
firewall-cmd --zone=public --add-port=80/tcp --permanent
firewall-cmd --reload
You can check if it's open:
firewall-cmd --list-ports
Open your browser at http://yourapp.com/ and see if it works.
Remember to keep an eye on nginx and your app's logs:
tail -f /var/logs/nginx/access.log # or error.log to see nginx access/error log
pm2 logs # to see your app logs
Hope it helps. Do not hesitate to share more info if you encounter any more problems
Try to use /etc/nginx/conf.d/default.conf instead of /etc/nginx/sites-available/default to add your configuration. According to your config it should be the correct path to configure your server.
If you want to use /etc/nginx/sites-available/defaultyou should add include /etc/nginx/sites-available/*; to your nginx.conf.
http {
...
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-available/*;
}

EPIPE Error with ExpressJS, nginx proxy server

I am running multiple ExpressJS Node apps through an Nginx proxy server, and am getting an EPIPE Error thrown whenever my users try to download a file. This does not happen on my local setup (which is identical to the server's except for the proxy server), so I figure it has something to do with my Nginx configuration.
Here are my Nginx configs:
/etc/nginx/nginx.conf
user www www;
worker_processes 1;
error_log /home/alex/logs/error.log;
pid /var/run/nginx.pid;
worker_rlimit_nofile 8192;
events {
worker_connections 4096; ## Default: 1024
}
http {
include mime.types;
index index.html index.htm index.php;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] $status '
'"$request" $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /home/alex/logs/access.log main;
sendfile on;
tcp_nopush on;
gzip on;
server_names_hash_bucket_size 128; # this seems to be required for some vhosts
include /etc/nginx/conf.d/*.conf;
}
/etc/nginx/conf.d/default.conf
server {
listen 80;
server_name example.com;
# log access and stuff
access_log /home/alex/logs/example-site.log main;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
# Proxy to the NodeJS server
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://127.0.0.1:8999;
}
# redirect server error pages to their HTML
include /etc/nginx/errpages.conf;
}
The ExpressJS server is sending the download using the following code:
app.get('/citrite/p/:patch', function(req, res)
{
if(set.citFiles.indexOf(req.params.patch) == -1)
{
res.send(mbuild.get404());
}
else
{
track.incrViewcount(req.params.patch, 'citrite');
res.download(set.citDir + '/' + req.params.patch, files.doneSaving);
}
});
That code and everything else works fine on my local git repo, but when I push from there and pull on the server-side, the site kicks and screams - it times out on the user's end and gives me an EPIPE error in the console. I am running Node.js version 4.2.1 and ExpressJS version 4.13.3.
I figured out what the problem was: apparently, having sendfile set to on is what was causing the downloads to stall, and turning that off (specifically, removing the directive in the config) fixed the issue. Not exactly sure why this would interfere, but getting rid of the setting cleared things up.

How to set and configure node.js with express to nginx reverse proxy on centos 6.4 virtualbox client?

I am creating a development VM on my Windows 8.1 system using VirtualBox 4.3.4 and installed CentOS 6.4 as my VMServer. I installed NginX and Node.js with no problems. With little knowledge of administration I deleted the contents of /etc/sysconfig/iptables allowing all connections for development purpose only as of the moment (which will be changed later).
NginX is working fine, on my Windows host, and pointing the browser to http://192.168.1.20 shows that the "Welcome to nginx on EPEL!" page is working.
Verifying that my node.js app is working correctly, I created a node app on my VMServer by running
[~]# express node_nginx_practice
[~]# cd node_nginx_practice && npm install
[~]# node app
Then, on my Windows host, point the URL to http://192.168.1.20:3000, the "Express default" page is running with no problem.
The question is how could I set and configure node app to serve on nginx reverse-proxy?
example: http://192.168.1.20 //will point to Express default page
I tried setting my nginx config in /etc/nginx/nginx.conf by following some tutorials on the web with no luck url still points to the NginX "Welcome to nginx on EPEL!" page.
Here's my nginx.conf
# For more information on configuration, see:
# * Official English Documentation: http://nginx.org/en/docs/
# * Official Russian Documentation: http://nginx.org/ru/docs/
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log;
#error_log /var/log/nginx/error.log notice;
#error_log /var/log/nginx/error.log info;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
# Load config files from the /etc/nginx/conf.d directory
# The default server is in conf.d/default.conf
include /etc/nginx/conf.d/*.conf;
server {
listen 80;
server_name localhost;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarder-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://127.0.0.1:3000;
proxy_redirect off;
}
}
}
I know I am missing something. Could someone point me to right direction?
EDIT ANSWER:
Here's what i did to solve the issue in step by step! (Thanks to "C Blanchard")
edit the default NginX config file:
[~]# vim /etc/nginx/conf.d/default.conf
and comment everything that is inside by prepending "#" to all of the lines.
restart NginX
[~]# /etc/init.d/nginx restart
Now the url points to the express page.
EDIT UPDATE: Better solution.
Open /etc/nginx/conf.d/default.conf find the location block and comment it by appending "#", and change specify the right location block pointing to node.js app. See code example below.
...
#access_log logs/host.access.log main;
# Comment this block
#location / {
# root /usr/share/nginx/html;
# index index.html index.htm;
#}
# This is the changed location block
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarder-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://127.0.0.1:3000;
proxy_redirect off;
}
error_page 404 /404.html;
location = /404.html {
root /usr/share/nginx/html;
}
...
Now I remove the server block that I specified in /etc/nginx/nginx.conf
# Load config files from the /etc/nginx/conf.d directory
# The default server is in conf.d/default.conf
include /etc/nginx/conf.d/*.conf;
# Remove from here
server {
listen 80;
server_name localhost;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarder-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://127.0.0.1:3000;
proxy_redirect off;
}
}
# Remove till here
}
The directive in your configuration (shown below) loads the default server block. This is the reason why you see the nginx welcome page when you request localhost:80 on a newly installed instance of nginx
# Load config files from the /etc/nginx/conf.d directory
# The default server is in conf.d/default.conf
include /etc/nginx/conf.d/*.conf;
You'll find that nginx is already listening on port 80 for localhost so your requests may never reach your newly defined reverse-proxy
Try disabling your default nginx server by opening /etc/nginx/conf.d/default.conf, commenting out the server block there and then restarting nginx

502 Bad Gateway in node + nginx proxy setup on Heroku

I'm using this buildpack to serve static files on Heroku with a node + nginx setup. While static assets are served properly, trying to serve content through node results in a 502 Bad Gateway. Node on its own works fine and so does nginx. The problem is when the two need to work together which I guess is because I haven't configured the nginx upstream settings right.
Here's my nginx conf:
worker_processes 1;
error_log /app/nginx/logs/error.log;
daemon off;
events {
worker_connections 1024;
}
http {
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
gzip on;
upstream node_conf {
server 127.0.0.1:<%= ENV['PORT'] %>;
keepalive 64;
}
server {
listen <%= ENV['PORT'] %>;
server_name localhost;
location / {
root html;
index index.html index.htm;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_set_header Connection "";
proxy_http_version 1.1;
proxy_pass http://node_conf;
}
location ~* ^.+\.(jpg|gif|png|ico|css|js|html|htm)$ {
root /app;
access_log off;
expires max;
}
location /static {
root /app;
index index.html index.htm;
}
}
}
.
My _static.cfg:
SERVER_TYPE="nginx"
BUILD_WEB_ASSETS="true"
.
My node server:
var app = require( 'express ')()
app.get( '/', function(req, res) { res.send( 'This is from Node.' ) })
app.listen( process.env.PORT )
.
I also have a sample html file in /static to test if nginx works:
<html>This is from nginx.</html>
.
With this config, appname.herokuapp.com should display "This is from Node." but instead I get the 502.
appname.herokuapp.com/static displays "This is from nginx" as it should, so no problems with nginx and static content.
I have tried every combination of values for upstream in nginx server settings but none have worked. What else can I try to make nginx proxy requests to node?
Here's my Heroku Procfile in case it helps: web: bin/start_nginx
I am not really familiar with Heroku, and pretty new to Nginx, but I'll give it a shot: To me it looks like the Nginx-config is saying that Nginx and the node.js app are using the same port (<%= ENV['PORT'] %>).
What you want is Nginx to listen to incoming connections (usually port 80), and have it forward them to the node.js app. Here is an example Nginx config:
# the IP(s) on which your node server is running. I chose port 4000.
upstream xxx.xxx.xxx.xxx { #Your IP adress as seen from the internet
server 127.0.0.1:4000; #Your local node.js process
}
# the nginx server instance
server {
listen 0.0.0.0:80; #Have Nginx listen for all incoming connections on port 80
server_name my-site;
access_log /var/log/nginx/my-site.log;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://xxx.xxx.xxx.xxx/; #Your IP adress as seen from the internet
proxy_redirect off;
}
}
This config is working for me on a webserver I am hosting in my living-room. Good luck!
Here's a README with information to get nginx and Node.js working together from a project I created a while back. Also included is an example nginx.conf.
As an overview, basically you're just creating sockets with Node then setting nginx to pipe those upstream. I commonly use this when I want to run multiple Node processes and have nginx stand in front of it.
It also includes working with socket.io out of the box, so you can use those to see how to configure your Node instance as well.

Resources