Pretty url of a MEAN-stack application in nginx - .htaccess

(* As some comments recommended, I removed index.ejs and use index.html in the project by following this answer. So I have adjusted my OP *)
I develop in Mac with apache a MEAN-stack application that can be requested by
https://localhost:3000/#/home. In production with a nginx server, the application can be requested by
https://www.myapp.io/#/home. The fragment-identifier # is needed in all cases because of angular ui-router.
So I wanted to make pretty url without # (eg, https://www.myapp.io/home, https://localhost:3000/home) work. I have done the following:
1) added $locationProvider.html5Mode(true); $locationProvider.hashPrefix('') in app.config(['$stateProvider'....
2) added <base href="/" /> in index.html
As a result, https://localhost:3000/#/home changes automatically to https://localhost:3000/home in the browser bar, similarly for https://www.myapp.io/#/home.
However, directly entering https://localhost:3000/home or https://www.myapp.io/home in the browser will raise an error (I don't know how to turn previous <h1><%= message %></h1><h2><%= error.status %></h2><pre><%= error.stack %></pre> in error.ejs to error.html, so I don't have more details).
So now, the goal is to make https://localhost:3000/home and https://www.myapp.io/home work.
By following this thread, I added the follows to app.js:
app.use('/js', express.static(__dirname + '/js'));
app.use('/dist', express.static(__dirname + '/../dist'));
app.use('/css', express.static(__dirname + '/css'));
app.use('/partials', express.static(__dirname + '/partials'));
app.all('/*', function(req, res, next) {
res.sendFile('index.html', { root: __dirname });
});
And in apache of mac, here is my httpd-vhosts.conf, after restarting apache,
https://localhost:3000/home still returns an error.
<VirtualHost *:443>
ServerName localhost
DocumentRoot "/Users/SoftTimur"
SSLEngine on
SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL
SSLCertificateFile /etc/apache2/ssl/localhost.crt
SSLCertificateKeyFile /etc/apache2/ssl/localhost.key
<Directory "/Users/SoftTimur">
RewriteEngine on
# Don't rewrite files or directories
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
# Rewrite everything else to index.html to allow html5 state links
RewriteRule ^ index.html [L]
Options Indexes FollowSymLinks
AllowOverride All
Order allow,deny
Allow from all
Require all granted
</Directory>
</VirtualHost>
In production, here is the nginx server block. After restarting nginx, https://www.myapp.io/home still returns an error.
server {
listen 443 ssl;
server_name myapp.io www.myapp.io;
ssl_certificate /etc/letsencrypt/live/myapp.io/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/myapp.io/privkey.pem;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_dhparam /etc/ssl/certs/dhparam.pem;
ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:EC$
ssl_session_timeout 1d;
ssl_stapling on;
ssl_stapling_verify on;
add_header Strict-Transport-Security max-age=15768000;
index index.html;
root /opt/myapp
location / {
try_files $uri $uri/ /index.html;
}
location ~ /.well-known {
allow all;
}
location / {
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Accept-Encoding "";
proxy_set_header Proxy "";
proxy_pass https://127.0.0.1:3000;
# These three lines added as per https://github.com/socketio/socket.io/issues/1942 to remove sock$
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
Could anyone help?

I think the better question you should be asking yourself is why don't you have index.html? Perhaps I've been asleep for too long, but browsers aren't really capable of executing JavaScript by itself on a webpage, without an underlying DOM from an HTML document.
Once you've got that figured out, you might as well succeed with the official configuration suggestion from angular-ui on GitHub.

Remove the nginx configuration you added. This can be achieved by performing the following:
There are 2 things that need to be done.
Configuring $locationProvider
Setting our base for relative links
See the following link for more detailed instructions on how to accomplish this:
Pretty URLs in AngularJS: Removing the #
For Angular 1.6 you will also need to change the hashPrefix:
appModule.config(['$locationProvider', function($locationProvider) {
$locationProvider.html5Mode(true);
$locationProvider.hashPrefix('');
}]);
I know in your question you stated that you had already done these two steps, but if you follow this tutorial perfectly it will work as I have tested this on my own Angular application (which is also hosted thru nginx).
To go with the server configuration route, I would recommend following this link:
AngularJS with Pretty URLs: Removing the # in Amazon S3
Additionally, here is the actual server configuration changes to make.
And lastly, I think you're mistaken with regard to how ejs works. It requires either HTML bootstrapping (after all, you must have some sort of index.html, with something like <script src="https://npmcdn.com/ejs/ejs.min.js"></script>), or processing on the server (e.g., with nodejs and/or friends).

Related

Proper ExpressJS and NGINX reverse proxy configuration for subdirectory

I have a VPS with NGINX installed, it's running a TLD website and I want to run my ExpressJS application from a subdirectory called nlapp. E.g. /var/www/website.com/public_html/nlapp.
Here's the app.js:
const express = require("express");
const bodyParser = require("body-parser");
const request = require("request");
const https = require("https");
const app = express();
app.use(express.static("public"));
app.use(bodyParser.urlencoded({ extended: true }));
app.get("/nlapp", function (req, res) {
res.sendFile(__dirname + "/signup.html");
});
My NodeJS application runs without errors and it works fine, but it doesn't seem to serve static content this far. I have disabled express static but it still doesn't work.
Here's my configuration for this right now:
server {
server_name website.com www.website.com;
root /var/www/website.com/public_html/;
index index.html index.php;
# Modsecurity
client_max_body_size 100M;
# Logs
access_log /var/log/nginx/access.log_website.com;
error_log /var/log/nginx/error.log_website.com;
# Don't allow pages to be rendered in an iframe on external domains.
add_header X-Frame-Options "SAMEORIGIN";
# MIME sniffing prevention
add_header X-Content-Type-Options "nosniff";
# Enable cross-site scripting filter in supported browsers.
add_header X-Xss-Protection "1; mode=block";
# Prevent access to hidden files
location ~* /\.(?!well-known\/) {
deny all;
}
# Prevent access to certain file extensions
location ~\.(ini|log|conf)$ {
deny all;
}
# Enable WordPress Permananent Links
location / {
try_files $uri $uri/ /index.php?$args;
autoindex off;
}
# Restrict GoAccess
location /rep_est_status.html {
auth_basic "Restricted Access";
auth_basic_user_file /etc/nginx/.htpasswd;
}
# Cache for 2 days
location ~* .(jpg|jpeg|png|gif|ico|css|js)$ {
expires 2d;
}
location ~ \.php$ {
include /etc/nginx/fastcgi_params;
fastcgi_pass unix:/run/php-fpm/www.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
# Deny access to xmlrpc.php
location = /xmlrpc.php {
include /etc/nginx/fastcgi_params;
fastcgi_pass unix:/run/php-fpm/www.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
allow 87.71.160.0/19;
deny all;
}
location /nlapp {
alias /var/www/website.com/public_html/nlapp/public;
proxy_pass http://127.0.0.1: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;
}
listen 443 ssl http2 default_server;
ssl_certificate /etc/letsencrypt/live/website.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/website.com/privkey.pem; # managed by Certbot
My NodeJS application is running on port 3000, and it worked great on my localhost.
But on this remote NGINX server (that I manage) the static content that is in /var/www/website.com/public_html/nlapp/public.
There I have 2 directories: css and images.
When I load the application from my browser, I go to this URL:
https://www.website.com/nlapp and it launches successfully.
The CSS and images are not loading, I've checked Network tab on dev tools and it seems it's trying to load them from the root directory of the website, e.g. https://www.website.com/css instead of https://www.website.com/nlapp/public/css
How do I fix this?
Thank you!
What did I try?
I tried using the alias or root directives under the specified location, as seen in the example above.
It didn't amount to anything, still the same.
Also tried googling and searching more and more for a few hours - couldn't arrive at a conclusion.

Nginx unable to serve the node.js POST requests

I've a VM Ubuntu15.04 server and I've configured nginx to listen requests on port 80 and forward them to respective applications on different ports. I have a simple node.js service running over port 3000 which has one GET and POST service. I have started it by using PM2 and added a proxy_pass to localhost:3000/ in my nginx default conf. The problem is when i try to use a GET request it is working fine but in case of POST it is showing 404 error. I've tried to use the POST service through postman client.
This is my default conf file of nginx
##
# You should look at the following URL's in order to grasp a solid understanding
# of Nginx configuration files in order to fully unleash the power of Nginx.
# http://wiki.nginx.org/Pitfalls
# http://wiki.nginx.org/QuickStart
# http://wiki.nginx.org/Configuration
#
# Generally, you will want to move this file somewhere, and start with a clean
# file but keep this around for reference. Or just disable in sites-enabled.
#
# Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples.
##
upstream my_nodejs_upstream {
server 127.0.0.1:3000;
keepalive 64;
}
server {
listen 80 default_server;
listen [::]:80 default_server;
# SSL configuration
#
# listen 443 ssl default_server;
# listen [::]:443 ssl default_server;
#
# Self signed certs generated by the ssl-cert package
# Don't use them in a production server!
#
# include snippets/snakeoil.conf;
root /var/www/face_rec/ServerTest;
# Add index.php to the list if you are using PHP
index index.html index.htm index.nginx-debian.html;
server_name localhost;
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
try_files $uri $uri/ =404;
proxy_pass http://localhost:3000;
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_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# include snippets/fastcgi-php.conf;
#
# # With php5-cgi alone:
# fastcgi_pass 127.0.0.1:9000;
# # With php5-fpm:
# fastcgi_pass unix:/var/run/php5-fpm.sock;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}}
# Virtual Host configuration for example.com
#
# You can move that to a different file under sites-available/ and symlink
that
# to sites-enabled/ to enable it.
#
#server {
# listen 80;
# listen [::]:80;
# server_name example.com;
# root /var/www/example.com;
# index index.html;
# location / {
# try_files $uri $uri/ =404;
# }
#}
Any reference, tutorial, suggestions or solutions please let me know how to do it.
Using try_files and proxy_pass in the same location block is probably not going to work.
If you want nginx to test for the presence of a static file and proxy everything else, use a named location:
root /path/to/root;
location / {
try_files $uri $uri/ #proxy;
}
location #proxy {
proxy_pass ...;
...
}
Test the configuration using nginx -t as your question appears to be missing a closing }.
See this document for details.
It's impossible to tell you what's wrong with your code if you didn't include even a single line of your Node program that your question is about.
Also "404 error" is not enough to know what's wrong because nginx shows a different error message than Express and knowing the exact message would let us know where the error originated.
What you should do is first to make sure that both your GET and POST handlers are working correctly by using:
curl -v http://localhost:3000/your/get/path
and:
curl -v -X POST -d 'somedata' http://localhost:3000/your/post/path
from the same host where your app is running.
Then add the nginx proxy, restart nginx to make sure that the config is reloaded, and do the same with port 80. If anything is different then work from there and diagnose the difference.
But if the POST handler doesn't work on localhost:3000 then you first need to fix that.

NodeJS multiple websites

I have been searching the Internet for a week now trying to find a good solution for this. First I read about http-master but I have been having issues installing it. Then I saw a few others that didn't have the features and ease of configurations. Or the answers were all outdated
We want to develop website in NodeJS, currently have three, two for test/dev and one for production. Each of these are hosted on the same server, currently an Apache server with the same domain name but different ports. We have another website we are working on as well with a different domain name.
Question is, what is the best way to use NodeJS to serve all the sites and more? Going forward we want to develop all applications in NodeJS.
Server Specs:
Windows Server 2012 R2
Two Cores
4 GB RAM
You want to use a reverse proxy. nginx is a good choice because configuration is so simple. But the same can also be achieved with apache.
Basically you just run each application under a different port, and based on domain name proxy over requests. Here's an example setup using nginx.
## Upstream www.example.com ##
upstream examplelive {
server 8081; # nodejs server running on port 8081
}
## Upstream dev.example.com ##
upstream exampledev {
server 8082; # nodejs server running on port 8082
}
## www.example.com ##
server {
listen 80;
server_name www.example.com;
access_log /var/log/nginx/log/www.example.access.log main;
error_log /var/log/nginx/log/www.example.error.log;
## send request back to examplelive ##
location / {
proxy_pass http://examplelive;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
## dev.example.com ##
server {
listen 80;
server_name dev.example.com;
access_log /var/log/nginx/log/dev.example.com.access.log main;
error_log /var/log/nginx/log/dev.example.com.error.log;
location / {
proxy_pass http://exampledev;
proxy_set_header Host static.example.com;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
The below apache example should work.
<VirtualHost *:80>
ServerAdmin admin#example.com
ServerName www.example.com
ProxyRequests off
<Proxy *>
Order deny,allow
Allow from all
</Proxy>
<Location />
ProxyPass http://localhost:8081/
ProxyPassReverse http://localhost:8081/
</Location>
</VirtualHost>
<VirtualHost *:80>
ServerAdmin admin#dev.example.com
ServerName dev.example.com
ProxyRequests off
<Proxy *>
Order deny,allow
Allow from all
</Proxy>
<Location />
ProxyPass http://localhost:8082/
ProxyPassReverse http://localhost:8082/
</Location>
</VirtualHost>
My preferred way of hosting multiple domains has always been to use vhost with Express, which allows you to match different domain names.
var mailapp = connect()
var staticapp = connect()
// create main app
var app = connect()
// add vhost routing to main app for mail
app.use(vhost('mail.example.com', mailapp))
app.use(vhost('assets-*.example.com', staticapp))
If you don't want to go through the hassle of getting multiple domains pointing to this server, I find that using multiple sub domains on one primary name (e.g. foo1.bar.com, foo2.bar.com and using a CNAME record with your DNS to point to those subdomains is very effective.

Static Website and Node server on same ec2 Instance

Can I serve my static website content and run a node server on the same ec2 Instance .
My ec2 instance is a t2.micro ubuntu 14.04 Image.
Tasks done :
Nodejs,npm installed. Nginx installed configured. Set up the ../../www/ directory to serve content through nginx.
I have a domain xyz.com pointed its # value to the elastic IP associated with the instance.
uploaded website files to directory . So now if I access xyz.com I get my website content through the nginx .
Cool.
But the node app is not accessible.
My node app is running on the port 3000.
tried adding
server {
root /var/www;
index: example.js
server_name _;
location / {
proxy_pass http://127.0.0.1:3000;
expires 30d; # not required
access_log off;
}
}
/etc/nginx/sites-available to point to the node server .
Cool . now xyz.com runs my node app . But no website content is accessible now :
(
And if I try hitting any API whose routes are defined in my Express routes there are no logs on the server side . only an nginx 404 error
eg:
xyz.com/myroute -404 nginx error, works on localhost:3000/myroute
xyz.com/ - returns the default route set for /
xyz.com:3000 - doesnot hit the node server. no logs.
Many online resources suggest rerouting the port 80 in the security zone to serve content over the port on which node is running. I could run the node app this way but again the whole website would have to be served through node.
I want to run them separately .
xyz.com - serves me the website
xyz.com:3000 - allows me to hit my node server Should I separate the app and website on to two different instances ? How can they be routed??
Hi I am running a similar setup but with a Jetty server instead of Node.
Below is my config;
server {
listen 80;
root /var/www/html/;
index index.php index.html index.htm;
server_name my_domain;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
try_files $uri /index.php =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name ;
include fastcgi_params;
}
location /app {
proxy_pass http://localhost:8080;
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;
}
}
As I understand it, you should only have to change the location /app to whatever your app path is, and obviously point the proxy_pass at the right port.
The other way of going about it will be to proxy pass on subdomain and have 2 virtual servers in nginx, so for example app.mydomain.com and app2.mydomain.com. For that kind of setup have a look at; nginx reverse proxy multiple backends
I believe you are looking for the kind of setup I have above. Good luck.

What is the equivalent value for apache configuration

I need to convert following nginx rule to Apache configuration.
can anyone help me.
location /chat {
rewrite /chat(/.+)$ $1 break;
proxy_pass http://localhost:8000;
proxy_set_header Host $host;
proxy_set_header Cookie $http_cookie;
proxy_buffering off;
proxy_send_timeout 310;
}
Have a look at the mod_proxy documentation, I think the ProxyPassMatch directive is of interest.
I would convert them to Apache2 like:
ReWriteEngine on
ProxyPreserveHost On
ProxyPass "/chat" "http://localhost:8000" flushpackets=on
ProxyPassReverse "/chat" "http://localhost:8000"
ProxyTimeout 310
in your <VirtualHost *:443> or <Location /chat> section

Resources