Pretty url of a MEAN-stack application in nginx
Asked Answered
W

2

7

(* 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?

Wivern answered 12/4, 2017 at 23:11 Comment(0)
S
1

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.

Saltzman answered 21/4, 2017 at 5:26 Comment(4)
I have index.ejs rather than index.html. But I'm not sure how to modify the suggestion from angular-ui on GitHub...Wivern
What's in index.ejs? Perhaps not having index.html is the root cause?Saltzman
This is ejs. When I created this application, I followed some examples where index.ejs is used (eg, this one). I just realised that I don't really use the feature of ejs, so I would change that to index.html, and see what happens, I will test it tomorrow and update...Wivern
@SoftTimur, I think you're missing how ejs works. I'm pretty sure it requires either HTML bootstrapping (e.g., 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).Saltzman
I
0

Remove the nginx configuration you added. This can be achieved by performing the following:

There are 2 things that need to be done.

  1. Configuring $locationProvider

  2. 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).

Iroquois answered 15/4, 2017 at 14:38 Comment(8)
My steps 1) and 2) are what your link describes, they are not enough.Wivern
What version of Angular are you using?Iroquois
Which link (Angular 1.6) are you using?Wivern
https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js. Those two steps remove the # from the url (change eg, https://.../#/new to https://.../new), but it does not treat the new url (eg, https://.../new). That's why in a php server, they use also .htaccess on top of those two steps.Wivern
I'm using Angular 1.5 in my test application. I use Angular-CLI so I do not provide an actual link, just list the version I want in the config file. See updated answer for server config route, that should accomplish what you wantIroquois
What puzzles me (and this question is about) is the server config. I know that github link... as I said, I don't have index.html in my application, I don't know how to adapt that link to my application, and I would appreciate a more precise answer for that...Wivern
Instead of index.html have you tried using index.ejs?Iroquois
I tried... I think I need to know what I am doing and should do rather than just trying...Wivern

© 2022 - 2024 — McMap. All rights reserved.