Separate port for some URLs in Rails app - ruby-on-rails

My Rails app listens on single port for API calls and browser requests. To increase security I would like to open another port for API and make web page URLs unabailable for this port.
How to do this in Rails? (Possibly without losing current app integrity).
I use WEBrick or Puma during development and Apache+Passenger in production.
P.S.
Currently I'm thinking about making HTTP proxy which will forward API calls.

Unicorn will bind to all interfaces on TCP port 8080 by default. You may use the -l switch to bind to a different address:port. Each worker process can also bind to a private port via the after_fork hook. But I think it is not useful if you have nginx on top layer.

Related

Ruby on Rails - Starting server as a live website. [Linode]

I have made an account on Linode website and have a "linode" running. I have a server running using ruby on rails. The command I used is the following:
rails server --binding=<ip_adress>
The server starts up without issue. The question I have is why can't I visit the the side I created using my browser, just by putting the ip_address in the browser? The server logs display the following
Environment: development Listening on tcp:<ip_address>:3000
I can visit this ip_address on my browser but I need to add the ":3000" in the browser so I can view the site.
Shouldn't I be able to just visit the stand alone ip_address without entering ":3000"? I also wanted to say I am just learning ruby on rails as well.
I haven't tried anything more than described above
An IP address is a way to identify a machine on the internet.A port is a number assigned to uniquely identify a connection endpoint and to direct data to a specific service.
Therefore, your rails service is a combination of an IP address and a Port number. Since you can have different services running on the same machine at the same IP address.
HTTP has a default port of 80 which is what your browser will try to access when you don't provide a port.
Most likely, you will want a Reverse Proxy hosted at port 80 that forwards traffic to your rails app.
This post provides a better answer of how this works. https://superuser.com/questions/394078/how-can-i-map-a-domain-name-to-an-ip-address-and-port
Not Recommended
If you don't want to use a reverse proxy, you can host the rails server at port 80 itself.
rails server -p 80
Note that this requires you to have root permissions on the machine.

What does it mean to run a local web server?

I can program and develop in Ruby on Rails/JS/HTML/CSS to make a full stack app. However, there are holes in my understanding of the HTTP request/response cycle. Are the following points correct?
If I make a Rails app, and on the command line type rails server I get a local server, which I can make requests to. If I open a browser, type localhost:3000, and press enter, I am making an HTTP request to the local server.
Rails uses by default a web server called WEBrick, though there are others like Thin, Puma, and Unicorn. These are all pieces of software, and what makes them web servers is the fact that the software implements functionality to process HTTP requests.
When I run a local web server, it means that my computer is running one of these pieces of software that listen for HTTP requests.
Is the above what it means "to run a local web server"?
I have seen other examples of ways to "run a local web server". One of the is to run npm install -g http-server in a project directory, and then navigate to localhost:8080. Is this also just software that starts running and accepts HTTP requests on port 8080?
On a Ruby command line, install rack gem: gem install rack. Then in a new Ruby file we require 'rack', start a web server:
Rack::Server.start({ app: MySimpleApp, port: 3000 })
We can then define a web application MySimpleApp that is rack-compliant (object that responds to call method):
class MySimpleApp
def self.call
(...)
end
end
So now when we navigate in our browser to localhost:3000, MySimpleApp is executed. Is rack simply running it's default WEBrick server? Is what the above commands do simply run a local web server and define what to do when an HTTP request comes in (execute MySimpleApp)?
You're pretty much right on your understanding there. HTTP is just a text-based protocol that, like many, operates over TCP/IP.
The built-in WEBrick server isn't the best example of an HTTP server written in Ruby, but it's included for legacy reasons because it's often "good enough" to get you started. Pow is considerably better and despite being produced by the same company that produced Rails it's largely written in Node.
The beauty of HTTP, like a lot of internet based protocols, is it doesn't matter what language you use so long as you comply with the standard.
Rack is a layer that operates behind HTTP and provides a thin layer of abstraction on the request/response cycle.
A server is something that opens up a port (80, 443, 8080) for some sort of data transfer. Port 80 is the HTTP port and port 443 is the HTTPS port. 8080 is a commonly used port for development (as is 3000). https://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers
A local server by definition is a server running on your machine.
Overall, you are definitely on the right track.

What is the best practice for Nginx/ELB/Unicorn architecture on AWS?

We have an RoR application in AWS Beijing. AWS Beijing does not have Route 53 (We can't use Alias to apply ELB to Apex domain), so we must use a Front-end Server running Nginx in front of ELB.
Now our architecture likes below:
Front-end (Nginx) -- ELB --- App-(1~n) (Nginx--Unicorn)
We have noticed the words from Unicorn description below:
"Unicorn must never be exposed to slow clients, as it will never ever use new-fangled things like non-blocking socket I/O, threads, epoll or kqueue. Unicorn must be used with a fully-buffering reverse proxy such as nginx for slow clients."
So my question are:
1. Before Unicorn, do we need nginx on the App Server?
2. If we remove nginx on App Server, can nginx on Front-end Server play such the effect like unicorn describing?
I would recommend replacing the ELB with HAProxy in this scenario where you don't have the alias feature from Route53 to point to your apex domain. Putting a Nginx instance in front of the ELB doesn't seem to be a good idea because you are adding a new layer just because you can't reference the ELB on Route53. You also lose the benefit of high availably by putting a Nginx instance in front of it the ELB.
My suggestion is that you keep one instance of Nginx on each of your app servers in front of Unicorn and use HAProxy as load balancer: HAProxy > [Nginx > Unicorn]. In a simple setup of HAProxy you also don't have the same availability of the ELB but you can setup a high available configuration if needed.
1) Nginx must be always in front Unicorn because Unicorn can't deal with slow clients efficiently, it just locked by those clients
2) Never talk to Unicorn via network, it means each app server need to have its own Nginx. Nginx as Load Balancer is a way better than ELB black box.

Using Thin Web Server with HTTP and HTTPS

I'm using the Thin web server to serve my Rails app.
Starting the server with thin start serves http requests.
Starting the server with thin start --ssl serves https requests.
Is there a way to have thin serve both http and https requests concurrently?
The reason I ask is because when I use redirect_to some_path in my controllers, they redirect to http. Since thin is serving https requests, nothing is rendered.
Note: I'm using Rack::SSL in Rails 3.0.7.
(Comment converted to answer as requested.)
Simplest option is probably to run two separate instances of thin: one accepting SSL requests and one accepting plaintext requests. Any reason you don't want to do this? (Alternatively, if thin is running behind another web server, like Apache or Nginx, you only need one instance of thin: the frontend server can report whether the request came in over SSL.)
You can't accept both HTTP and HTTPS connections on the same port. (This is why, by default convention, HTTP runs on port 80 whereas HTTPS runs on port 443.)
you can use foreman (https://github.com/ddollar/foreman);
You create a Procfile with 2 process then start both with forman start command.
put this on a file called Procfile:
web: thin start
ssl: thin start --ssl
Then use foreman start and he start the 2 process.
This is how i am using... hope this helps you!

Deploying Rails and Nodejs

I wrote a real-time web app that consists of the following:
Rails to serve the web pages (listens on port 80)
Nodejs to handle real-time logic (listens to port 8888)
So on a particular page served by my rails app, the JS will use socket.io to establish a connection to my nodejs instance to allow real time http push.
Currently Nodejs communicates with Rails simply by updating the rails database. (I know this is ghetto but it works).
What are my options for deployment?
I have deployed simple web apps on heroku before and I really like the simplicity.
I have also deployed a web app with similar functionality (except it's made up of django + nodejs). I used HAProxy to do reverse proxying to handle direction of traffic to the correct process on my machine. However, I deployed this on a VPS server instead.
Note: the ugliness will probably revolve around:
I am relying on a common db
These processes are listening on different ports
We had this exact issue. We deployed them to separate Heroku applications, but kept them within the same code base. http://techtime.getharvest.com/blog/deploying-multiple-heroku-apps-from-a-single-repo outlines how to do it.
Manually set the buildpack
Set a config variable that you can reuse in step #3.
Create a custom web script that your Procfile uses
A custom script in bin/web
#!/bin/bash
if [ "$RAILS_DEPLOYMENT" == "true" ]; then
bundle exec rails server -p $PORT
else
node node/index.js
fi
And the Procfile:
web: bin/web
I would consider setting these two applications up as separate Heroku applications on different subdomains and just having them both on port 80. The communication between them goes through a shared database so they don't need to reside on the same machine or even datacenter. Socket.io supports cross domain requests on all browsers, so that shouldn't cause any problems.

Resources