Simple Rails Server on AWS with Vagrant

Last time, we learned why vagrant up with the AWS provider sometimes hangs on “waiting for SSH to become ready” (because I accidentally set it to use a private IP, but didn’t map routes or anything), and why it sometimes says “invalid group ID” (because if the group id provided doesn’t match your security role and region, AWS reports the same error as if you’d passed in a null group id).

Now, I’m going to resume doing the rails tutrial book’s “mostly static pages” and try to deploy it in AWS. I’m not going to worry about DNS entries for this post – I’ll declare victory when I can paste the public DNS entry that AWS generates for my instance in the browser and see some Rails content come back.

The first difference I notice between the rails dev I was doing when the VM was running locally is that folder syncing isn’t instant. I guess this makes sense – we certainly need to be more deliberate about making folders sync between the host environment and the guest if the guest is running in the cloud somewhere, and the process will certainly be slower. To make a long story short: You have to have a tool called “rsync” installed, the sync is a one-way push (content on your machine is pushed to the cloud), and the sync only happens on a up, provision or reload. Still, having a local folder that will just get pushed to the cloud every time my AWS EC2 instances is reloaded is much more repeatable and remembering to copy folders into a VM every time I change something, so I’m happy about that.

Here’s my first steps:

  1. Go into AWS management console and update the security group that my instance belongs to is listening on port 3000 and port 80, so that I can browse to it.
  2. Copy my local implementation of the rails sample app into the shared directory.
  3. Do vagrant up --provision --provider=AWS
  4. Do vagrant ssh
  5. cd into the directory of the rails app, update my ruby gems and launch the server. (I want to get rid of the requirement that I update gems myself – my Vagrantfile should be doing that.)

Then I open a browser, paste the instance’s public DNS entry into a new tab, add :3000 to the end, and hit enter. Boom, I’m looking at the sample rails app output. That wasn’t bad.

Rather than declare victory right away, I’m going to try getting standard http (port 80) to work. As far as I can tell, the quick-and-dirty way to do this is just to forward port 80 to port 3000. (Note: I think this has some security implications, but I’m just trying to get server working at all; I’m willing to do it.) I think this real way to do this is to set up some other web server, such as Apache on Nginx, and instruct that server to forward suitable requests to port 3000, but for now, I just add this to the script block in my Vagrantfile:

iptables -t nat -I PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 3000

(Thanks to this SO answer.)

Then I reload with --provision, and then browse to the public DNS name AWS assigned to my instance. It worked.

(Note: because rails server is still having some strange config issue, I am launching my server with bundle exec puma -C config/puma.rb instead.)

Also, keep in mind that AWS can cost money. So far, the tutorial I’ve been doing has fallen within the free tier of the AWS activities, but, for example, if I open up port 80 and leave the server on all the time, I’ll end up paying to handle http requests from bots. I make sure to vagrant halt every time I’m done working, for this reason.

Anyway, I serving rails over port 80 in the cloud was the goal for this post, and that’s done. I’m going to declare victory for this week. Next week, I’ll keep messing around with rails and see what I learn.

Till then, happy learning!


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s