Running an ember-app on the same machine as a Rails API Server

I would like to know what the best way is to run an ember.js application on the same machine as the Rails API server, where the ember-app RESTadapter is configured to make calls to the backend rails-app-api via /api/v1.

The ember app should go in the document root, and any calls it makes to /api/v1 need to be passed to the rails app which is running here:

 /home/deploy/rails-app-api/current/public/

Right now I can deploy my Rails API server using capistrano, and I would like to do the same with the ember app and combine the process into a single cap script.

What is the best practice for this setup?

Here’s how we do it; iw will work with Rails as well as any other backend.

We just use nginx. It allows us to:

  • serve the assets (including the Ember app itself)
  • proxy to the API
  • many other benefits out of the scope of this post :slight_smile: (feel free to ask)

Here’s an example config (dev environment) to illustrate:

#
# Define your upstream cluster
#
upstream rails {
  server 0.0.0.0:3000 fail_timeout=0;
}

server {
    listen   80;
    server_name your_app.dev;

    #
    # This is the proxy to your API
    #
    location ~ ^/v1/api/(.+)$ {
        sendfile off;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_set_header X-Real-IP         $remote_addr;
        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Protocol   $scheme;
        proxy_pass http://rails;
    }

    #
    # This section serves the index.html of your Ember app
    #
    location ~ ^/$ {
        sendfile off; # Don't know why, but necessary
        alias /path/to/ember/;
        try_files index.html =500; #index.html can not be found
    }

    #
    # This section serves the other files of your Ember app
    #
    location ~ ^/(.+)$ {
        sendfile off; # Same as above
        alias /path/to/ember/;
        try_files /$1 =404;
    }
}

Is it the best practice? It’s easy, works well and scales gracefully, that’s enough for us!

2 Likes

Great stuff, but not using nginx. Is there an apache version for accomplishing the same thing?

Here’s an example apache configuration file that works for me:

root@CMSM003:/etc/apache2# cat ./sites-available/example.conf
Listen 8080

<VirtualHost example.com:80>
    DocumentRoot /home/deploy/ember-client/dist/
    <Directory /home/deploy/ember-client/dist>
        Options Indexes FollowSymLinks
        AllowOverride None
        Require all granted
    </Directory>
    ProxyPass /api/v1 http://example.com:8080/api/v1
</VirtualHost>

<VirtualHost *:8080>
    DocumentRoot /home/deploy/rails-api/current/public/
    <Directory /home/deploy/rails-api/current/public>
        Options Indexes FollowSymLinks
        AllowOverride None
        Require all granted
    </Directory>
</VirtualHost>

Hope this helps.

No idea, I didn’t use Apache for years.

I hoped this blog post would help, but if it doesn’t, I can’t either. No doubt that the Apache forums/mailing lists/IRC channels will provide a fast and acurate answer.

Here is the Apache config I used on Mac OS X 10.9 with the bundled Apache 2:

<IfModule mod_proxy.c>
  ProxyRequests on
  ProxyPreserveHost on

  ProxyPass /api/1 http://0.0.0.0:6543/api/1
  ProxyPassReverse /api/1 http://0.0.0.0:6543/api/1

  ProxyPass / http://0.0.0.0:4200/
  ProxyPassReverse / http://0.0.0.0:4200/
</IfModule>

Just sudo to root like a bad developer and then add this config to the file /etc/apache2/httpd.conf right before the last line of config (Include /private/etc/apache2/other/*.conf). Then run apachectl graceful and you’re good to run Ember.js on http://localhost and your API server on http://localhost/api/1.

Probably works with Rails? 6543 is the default port for Pyramid.

My app/application/adapters.js looks like this (with ember-simple-auth in the mix too):

import DS from 'ember-data';
import DataAdapterMixin from 'ember-simple-auth/mixins/data-adapter-mixin';

export default DS.JSONAPIAdapter.extend(DataAdapterMixin, {
    host: 'http://0.0.0.0:80',
    namespace: 'api/1',
    authorizer: 'authorizer:application'
});