(If needed, please see my last question for some more background info.)
I'm developing an app that uses a decoupled front- and backend:
- The backend is a Rails app (served on
localhost:3000
) that primarily provides a REST API.
- The frontend is an AngularJS app, which I'm building with Gulp and serving locally (using BrowserSync) on
localhost:3001
.
To get the two ends to talk to each other, while honoring the same-origin policy, I configured nginx to act as a proxy between the two, available on localhost:3002
. Here's my nginx.conf:
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 3002;
root /;
# Rails
location ~ \.(json)$ {
proxy_pass http://localhost:3000;
}
# AngularJS
location / {
proxy_pass http://localhost:3001;
}
}
}
Basically, any requests for .json
files, I'm sending to the Rails server, and any other requests (e.g., for static assets), I'm sending to the BrowserSync server.
The BrowserSync task from my gulpfile.coffee
:
gulp.task 'browser-sync', ->
browserSync
server:
baseDir: './dist'
directory: true
port: 3001
browser: 'google chrome'
startPath: './index.html#/foo'
This all basically works, but with a couple of caveats that I'm trying to solve:
- When I run the gulp task, based on the configuration above, BrowserSync loads a Chrome tab at
http://localhost:3001/index.html#/foo
. Since I'm using the nginx proxy, though, I need the port to be 3002. Is there a way to tell BrowserSync, "run on port 3001, but start on port 3002"? I tried using an absolute path for startPath
, but it only expects a relative path.
- I get a (seemingly benign) JavaScript error in the console every time BrowserSync starts:
WebSocket connection to 'ws://localhost:3002/browser-sync/socket.io/?EIO=3&transport=websocket&sid=m-JFr6algNjpVre3AACY' failed: Error during WebSocket handshake: Unexpected response code: 400
. Not sure what this means exactly, but my assumption is that BrowserSync is somehow confused by the nginx proxy.
How can I fix these issues to get this running seamlessly?
Thanks for any input!
To get more control over how opening the page is done, use opn instead of browser sync's mechanism. Something like this (in JS - sorry, my Coffee Script is a bit rusty):
browserSync({
server: {
// ...
},
open: false,
port: 3001
}, function (err, bs) {
// bs.options.url contains the original url, so
// replace the port with the correct one:
var url = bs.options.urls.local.replace(':3001', ':3002');
require('opn')(url);
console.log('Started browserSync on ' + url);
});
I'm unfamiliar with Nginx, but according to this page, the solution to the second problem might look something like this:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
# ...
# BrowserSync websocket
location /browser-sync/socket.io/ {
proxy_pass http://localhost:3001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
}
}
I only succeed by appending /browser-sync/socket.io
to proxy_pass url.
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
# ...
# BrowserSync websocket
location /browser-sync/socket.io/ {
proxy_pass http://localhost:3001/browser-sync/socket.io/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
}
}
You can also do this from the gulp/browsersync side very simply by using its proxy option:
gulp.task('browser-sync', function() {
browserSync({
...
proxy: 'localhost:3002'
});
});
This means your browser connects to browsersync directly like normally via gulp, except now it proxies nginx. As long as your front-end isn't hard-coding hosts/ports in URLs, the requests to Rails will go through the proxy and have the same origin so you can still POST and such. This might be desirable for some as this change for a development setting goes in the development section of your code (gulp+browsersync) versus conditionalizing/changing your nginx config which also runs in production.
Setup for browser-sync to work with python (django) app that runs on uwsgi via websocket. Django app is prefixed with /app to generate url that looks like http://example.com/app/admin/
server {
listen 80;
server_name example.com;
charset utf-8;
root /var/www/example/htdocs/static;
index index.html index.htm;
try_files $uri $uri/ /index.html?$args;
location /app {
## uWSGI setup
include /etc/nginx/uwsgi_params;
uwsgi_pass unix:///var/run/example/uwsgi.sock;
uwsgi_param SCRIPT_NAME /app;
uwsgi_modifier1 30;
}
location /media {
alias /var/www/example/htdocs/storage;
}
location /static {
alias /var/www/example/htdocs/static;
}
}