1

I'm trying to set the twilio client quickstart app up in nodejs. I'm using nginx as a reverse proxy so that requests made to http://example.com/calls, nginx routes that to localhost:3000, where I have the twilio nodejs quickstart running. The problem is that expressjs is expecting to serve files as if I were calling http://example.com with no subdirectory.

I understand that I would be able to use app.get, but I'm not sure how in the way this particular app is configured. Right now it has:

const http = require('http');
const path = require('path');
const express = require('express');
const bodyParser = require('body-parser');

const router = require('./src/router');

// Create Express webapp
const app = express();
app.use(express.static(path.join(__dirname, 'public')));// <-Pretty sure I'm supposed to change something here
app.use(bodyParser.urlencoded({extended: false}));

In the index.js that node is running on is at

/var/www/example.com/calls/index.js

The static content that I thought ought to be served is at

/var/www/example.com/calls/public/index.html

How to I change this to make express find the content?

Nodejs is definitely recieving the request. The error is Cannot GET /calls/ and the header X-Powered-By is present and set to Express

EDIT:

I would have liked to follow the instructions here but my at&t firewall isn't letting me make changes. Since I have ports 80 and 443 open already I decided my next best bet was to proxy the application to a subfolder of a domain I already have running on my system. Both of the solutions offered so far allow the index.html file inside of the /public folder to be served, but nginx is failing to serve the js file or the the css files located in the same folder.

app.use('/calls',express.static(path.join(__dirname, '/public')));

is currently serving the index.html file at https://example.com/calls, which is great. What stinks is the nginx somehow isn't passing the requests for https://example.com/calls/site.css along to nodejs.

If I add the line

rewrite ^/cawls(.*)$ $1 break;

then nothing gets found.

Here's the nginx call.

    location ~/calls(.*)$ {
#        rewrite ^/calls(.*)$ $1 break;
        proxy_pass   http://127.0.0.1:3000;
    }

Here and here are previous questions related to this problem that no one seems to have an answer for.

philnash
  • 70,667
  • 10
  • 60
  • 88
Altimus Prime
  • 2,207
  • 2
  • 27
  • 46
  • I think this might be an issue with your nginx config rather than express. How have you setup the reverse proxy? – philnash Feb 09 '18 at 21:33
  • Hi philnash. I marked this one Twilio tag specifically hoping that you would find it. I'm very glad you did. I think that Twilio is a relevant tag because it takes a Twilio person to know the inner workings and dependencies of the quickstart app. Any app where I know the dependencies and required structures would be written accordingly. – Altimus Prime Feb 10 '18 at 00:53
  • But this isn't about the inner workings of the quickstart app, more about that you are reverse proxying to a node.js application under a subdirectory. I'm happy to try to help though! – philnash Feb 10 '18 at 01:58
  • Thank you. Just explaining myself as to why I chose it. :) – Altimus Prime Feb 10 '18 at 02:03

2 Answers2

3

Twilio developer evangelist here.

The problem here is that express knows nothing of your /calls route. It expects to be serving content at its application root. You could fix this in the app by appending the /calls route to your static middleware, like so:

app.use('/calls', express.static(path.join(__dirname, 'public')));

But that would mean that your express app knows about the rest of the applications that you are reverse proxying with nginx. Instead, I would suggest you update your nginx config to proxy pass but strip the /calls route for your express app.

I'm guessing you have some nginx config that looks a bit like this:

location /calls {
    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://localhost:3000;
    proxy_redirect off;
}

If you add one line to this block it should strip the /calls route for the benefits of your express app.

rewrite ^/calls(/.*)$ $1 break;

Let me know if either of these things helps!

philnash
  • 70,667
  • 10
  • 60
  • 88
  • Your solution works, or doesn't work just the same as gwintrobs. Any idea why nginx wouldn't proxy the css and js files? Also twilio needs to access a subdirectory `/voice` but I can't find where that listener is created. – Altimus Prime Feb 10 '18 at 01:56
  • What do you mean exactly? Which solution? What doesn't work about it? What CSS and JS files and where are they located? – philnash Feb 10 '18 at 01:59
  • Thank you very much for taking time to help me. I updated the question with some more details. The solution I was referring to is your answer in how to serve the content through the proxy. Both allow the index.html of the Twilio client to be served. Neither allows the client side dependencies to be served, that I can tell anyway. – Altimus Prime Feb 10 '18 at 02:19
  • What do you get if you try to directly load `example.com/calls/site.css`? – philnash Feb 10 '18 at 02:24
  • An nginx generated 404 error with no express headers at all. Looking at network in the developer tools the only files that get served at the index.html and the remotely hosted files. The js and css files give the 404 error. – Altimus Prime Feb 10 '18 at 02:24
  • 1
    I wonder if your nginx `location` is causing trouble. You should get the behaviour you expect with something like `location /calls/ {`. Also, do you have any other `location` properties that match CSS or JS files somehow? – philnash Feb 10 '18 at 02:30
  • Thanks. There was a cache directive that matched on the css and js files. Something in the application is making a request to `/token` which isn't set and I think I need to open up `/voice` for Twilio. Thank you again for being so helpful. – Altimus Prime Feb 10 '18 at 02:38
  • Awesome, glad it's getting there! The call to `/token` is in [quickstart.js](https://github.com/TwilioDevEd/client-quickstart-node/blob/master/public/quickstart.js#L9). [`/voice` is defined here](https://github.com/TwilioDevEd/client-quickstart-node/blob/master/src/router.js) but you should be able to change your TwiML App to point to `example.com/calls/voice` and it just work in this setup. – philnash Feb 10 '18 at 02:41
1

I haven't seen express.static used for HTML. What about serving it from a route?

app.get('/', function(req, res) {
  res.sendFile(path.join(__dirname, 'public/index.html'));
})
gwintrob
  • 3,253
  • 2
  • 18
  • 14
  • 1
    Thank you for taking the time to look at the question. The original question already references that I could use app.get, but it messes up the references of the application. The real question is how to tell express where the root is so that everything downstream requests the appropriate resource. – Altimus Prime Feb 09 '18 at 19:23