Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Iron-router behind nginx proxy #154

Closed
kimmoahokas opened this issue Sep 21, 2013 · 20 comments
Closed

Iron-router behind nginx proxy #154

kimmoahokas opened this issue Sep 21, 2013 · 20 comments
Labels

Comments

@kimmoahokas
Copy link

It seems that iron router doesn't handle meteor environment variable ROOT_URL properly.

For example i have defined route:

this.route('my_appointments', {
        path: '/',
        template: 'appointmentListTemplate',
    });

which works when running local debug server. In production environment I have to run meteor behind nginx reverse proxy, which has configuration like this:

server {
    listen [::]:80;
    server_name server.example.com;
    location /scheduler/ {
        proxy_pass http://localhost:3000;
        proxy_set_header  X-Real-IP  $remote_addr;
        proxy_set_header Host $host;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
    }
}

now I run the meteor server: ROOT_URL="http://server.example.com/scheduler" PORT=3000 node main.js
When i try to connect to http://server.example.com/scheduler I get this error to browser js console: "Error: No route found for path: /scheduler/".

Ok, so I figure out that I just modify the urls in router to something like this:

this.route('my_appointments', {
        path: '/scheduler',
        template: 'appointmentListTemplate',
    });

Now the index page at http://server.example.com/scheduler works but all the links produced by router contains additional scheduler part like this: http://server.example.com/scheduler/scheduler/reserve

Am I doing something wrong, or is this a bug in iron router?

@cmather
Copy link
Contributor

cmather commented Sep 28, 2013

I'm a little confused here. Are you trying to prefix all routes with /scheduler?

@kimmoahokas
Copy link
Author

Well kind of. In the end I'm trying to serve multiple meteor apps on one domain, each with different path (server.example.com/scheduler, server.example.com/app2 and so on). This is handled by the nginx proxy. Obviously I shouldn't need to add that prefix to ironrouter's routes, as the ROOT_URL variable for each meteor instance includes that prefix. But now ironrouter can't find any routes.

After that my second attempt was to hack my app by including the prefix to routes in my app. When I did that, ironrouter correctly serves all the pages, but after that I can't use Router.path('name'), as it returns URL's that contain the prefix twice.

It seems to me that ironrouter does not handle the ROOT_URL correctly if it contains a path in addition to domain name. Or then my configuration just has some bug which I can't find.

@jagill
Copy link
Contributor

jagill commented Oct 13, 2013

Are you sure your nginx config is correct? If your proxy_pass url isn't slash terminated, then it will pass the prefix (scheduler/ in your case). If your proxy_pass was instead

proxy_pass http://localhost:3000/;

I think it would strip scheduler/ from the passed url, and (if I'm understanding your question correctly), it should do what you want.

@cmather cmather closed this as completed Oct 19, 2013
@cmather
Copy link
Contributor

cmather commented Oct 19, 2013

@mr-kimia, The Router uses the entire path on the client. So whatever is in the browser pathname. This all happens on the client. A possible improvement would be to make the ROOT_URL what we use instead of what's in the browser. Is that what you're suggesting? I closed the issue, but we can continue discussion and possibly create a design issue.

@thatjuan
Copy link

thatjuan commented Dec 4, 2013

@cmather it looks like making all routes relative to ROOT_URL by default would be the way to go. In a lot of cases it makes sense to run an entire meteor app within a unique route of a domain.

For example:

On development, I'd use something like http://192.168.1.1:3000/ but when deployed I'd use http://myapps.com/app1

Or if I'm releasing this app as an open source project, some people might want to run it in an entire domain or limit it to a route.

@cmather
Copy link
Contributor

cmather commented Dec 4, 2013

@thatjuan, That's an interesting approach.

@thatjuan
Copy link

thatjuan commented Dec 4, 2013

@cmather I'm temporarily reading from Meteor.absoluteUrl() and then taking the route portion of it to append it to all of my route declarations.

@eprabhakar
Copy link

@thatjuan
Thanks for the workaround suggested by you. I got into the same issue to refer http://localhost:3000/app1 and resolved the routing problem.
But how can I resolve the 'pubilc' folder contents, like images, icons etc with this solution? I can not find a way to add the 'app1' to the 'public' folder to be able to resolve the issue of not being able to load the images, icons etc that exist in public folder. Any thoughts please?

@eprabhakar
Copy link

I figured out the problem. I have some programmatic url references to the image and font files, which also I need to append with the app name. Too many changes to the code just to support this.
I wish the 'ROOT_URL' support is inbuilt in the Iron Router as suggested by @thatjuan

@meule
Copy link

meule commented Sep 28, 2014

I have the same problem when my app is in subfolder.
@thatjuan How did you finally solve this problem?

@meule
Copy link

meule commented Sep 29, 2014

@eprabhakar how did you solve the problem with the image and font files in your case?

@eprabhakar
Copy link

@meule,
Let me explain few steps that I used to solve my case. I needed the public folder to be a sub folder of the appname.
In my forever script, I will initialize the ROOT_URL to something like

export ROOT_URL="http://localhost/appname" 

Then, in the client router

appname = Meteor.absoluteUrl().split('/')[3]; 

this.route('time_t3/:report', {
      path: appname+'time_t3/:report',
      template: "app",
      yieldTemplates: {
         'time_t3': {
            to: 'appPage'
         }
      },
   });

Then, I will have a helper called 'logourl' in one of the top level client helper files (it will be invoked first and available).

Handlebars.registerHelper('logourl', function () {
      try {
        var app = Meteor.absoluteUrl().split('/')[3];
        if(app)
        return  '/'+app+'/';
        return '/'; 
      } catch (err) {
     }
   });

Finally, in the template, it will be something like

<img src={{logourl}}images/icons/loading1.gif />

If there is an appname in the ROOT_URL, the logourl helper will return the appname subfolder path and it will actually use the 'public' folder inside the app subfolder..

Hope the above is clear and helpful to you.

@meule
Copy link

meule commented Sep 30, 2014

@eprabhakar, thank you so much!
It works.
But in public folder I have fonts and images files. They are used in my css files. What about them? Is it possible to have helpers for css?

@eprabhakar
Copy link

@meule
Yes, it is possible to use the relative url in your CSS to refer to the fonts, images etc.
Please see a sample CSS below. This CSS file is in my 'client/style' folder. So, the relative url '../../fonts' will actually point to the 'public/fonts' folder.

@font-face {
    font-family: 'icomoon';
    src:url('../../fonts/icomoon.eot');
    src:url('../../fonts/icomoon.eot?#iefix') format('embedded-opentype'),
        url('../../fonts/icomoon.ttf') format('truetype'),
        url('../../fonts/icomoon.woff') format('woff'),
        url('../../fonts/icomoon.svg#icomoon') format('svg');
    font-weight: normal;
    font-style: normal;
}

@jasonshouse
Copy link

+1 for Iron Router to support ROOT_URL

@lllama
Copy link

lllama commented Feb 24, 2015

This has just bitten me when trying to run the example todos app behind nginx and under a test URL (i.e. non-'/' location). Would be good if ROOT_URL could be supported. (pathFor caused the most obvious problem for me - links end up removing the initial path component)

@tlau
Copy link

tlau commented Feb 26, 2015

+1 here too. We need to run multiple meteor apps within a single nginx instance, proxied from different subdomains (e.g. http://myhost/app1 and http://myhost/app2). It would be nice if we didn't have to rewrite the app to support being run in a subdomain.

@donpdonp
Copy link

donpdonp commented Apr 1, 2015

+1. We have a simple meteor app with no routes and it works fine with a ROOT_URL of http://example.com/one. A more complex app is mounted at http://example.com/two. The routes.js of path: '/' will fail because the ROOT_URL_PATH_PREFIX is not being removed and there is no route (nor should there be) for '/two/'

@baszalmstra
Copy link

+1. Would also like to run two meteor applications within the same single nginx instance.

@johipsum
Copy link

johipsum commented Aug 5, 2015

I've slightly modified the URL.parse function (johipsum/iron-url@2fc1c70) from the iron:url package to make all routes relative to the ROOT_URL env. Works for me..!

But I still have a problem with the IE9. For some reason meteor places the /#/ (fallback for the missing History API) right before the ROOT_URL_PATH_PREFIX (http://example.com/one => http://example.com/#/one), which is wrong...
I'm not sure if it has something to do with the Iron:Router because if I use the urlToHashStyle function everything looks fine and if I force Chrome or Firefox to use hash styled routes everything works fine too... any idea? (clearing the cache solved the problem :) )

I created a pull-request for this so you can have a look...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests