Alright, let's get started. Create a new Ubuntu 12.04 LTS instance, boot it up, and SSH into the fresh Linode as root. Now update/upgrade your sources and install Git and curl:
apt-get update
apt-get upgrade
apt-get install git-core curl
After this, you'll probably have to reboot the machine.
Now set the hostname, I often like to use nameofapp-main as the initial/sole instance.
echo "myapp-main" > /etc/hostname
hostname -F /etc/hostname
Now assign your machine a FQDN (Fully Qualified Domain Name)
vim /etc/hosts
Somewhere, usually at the top just blow the localhost.localdomain
bit,
substitute 0.0.0.0
with the public IP address of the machine.
0.0.0.0 myhostname.myapp.com myhostname
Set the system locale to UTF-8, so Postgres doesn't build DBs in ASCII.
locale-gen en_US.UTF-8
update-locale LANG=en_US.UTF-8
Configure the timezone, I recommend Etc/UTC because it's for real.
dpkg-reconfigure tzdata
Now, add your (and whoever else's) public key(s) to the root account:
mkdir ~/.ssh
cd ~/.ssh
vim authorized_keys
Set the correct permissions:
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
Log out of the machine and try logging in again, if it works without a password then it's time to disable noob-ass password auth:
vim /etc/ssh/sshd_config
Now, modify or add PasswordAuthentication no
and...
service ssh restart
Create the deploy user:
useradd -m -s /bin/bash deploy
Copy over SSH access stuff to the deploy user, you might want this to be different than the access for root, in that case, do your thing.
mkdir /home/deploy/.ssh
cp ~/.ssh/authorized_keys /home/deploy/.ssh/
chown -R deploy:deploy /home/deploy/.ssh/
Then install Postgres 9.2:
First, I update the shit according to this article:
Then:
sudo vim /etc/apt/sources.list.d/pgdg.list
And add the following line to that file:
deb http://apt.postgresql.org/pub/repos/apt/ precise-pgdg main
If you're not using precise, then run lsb_release -c
to get the codename of the release you are running and substitute accordingly.
Next add the Postgres repository key:
wget --quiet -O - http://apt.postgresql.org/pub/repos/apt/ACCC4CF8.asc | sudo apt-key add -
Now we can install Postgres:
sudo apt-get update
sudo apt-get install postgresql-9.2 libpq-dev postgresql-contrib-9.2
After that I run pg_tune:
cd ~/src
wget http://pgfoundry.org/frs/download.php/2449/pgtune-0.9.3.tar.gz
tar xzf pgtune-0.9.3.tar.gz
sudo ./pgtune-0.9.3/pgtune -i /etc/postgresql/9.2/main/postgresql.conf -o /etc/postgresql/9.2/main/postgresql.conf.pgtune
sudo mv /etc/postgresql/9.2/main/postgresql.conf /etc/postgresql/9.2/main/postgresql.conf.original
sudo mv /etc/postgresql/9.2/main/postgresql.conf.pgtune /etc/postgresql/9.2/main/postgresql.conf
sudo chown postgres:postgres /etc/postgresql/9.2/main/postgresql.conf
Create a "deploy" user that can't create databases or roles, and then create your app's database(s) under that user:
sudo su - postgres
createuser -D -R deploy
createdb -O deploy myapp_production
Note: By default Postgres will not bind to any IP interfaces, given the context of this guide, that is a perfectly acceptable default.
Time to install Redis for all your NoSQL needs. Create a src
directory in
root's home directory:
cd ~
mkdir src
cd src
Now go to the Redis website and wget the latest stable version.
wget {{redis-stable-tgz-url}}
tar -xzf {{redis-stable-tgz-file}}
cd {{uncompressed-redis-dir}}
make 32bit # Obvs remove the 32bit part if this is a 64bit instance.
make install
Now time to configure Redis, copy the redis.conf
file from the Redis source
directory into /etc
and go to town:
cp redis.conf /etc/redis.conf
useradd -r redis
mkdir -p /var/log/redis # <- Unless you use syslog instead
chown redis:redis /var/log/redis # <- Unless you use syslog instead
mkdir /var/lib/redis
chown redis:redis /var/lib/redis
Modify redis.conf (the Redis config file) to point to above directories, now is also a good time to ensure that you are only binding to 127.0.0.1:
bind 127.0.0.1 # <- Make sure this line is in /etc/redis.conf
In addition, since we're going to use Upstart to manage the Redis service now is a good time to ensure that the following is set in your redis.conf:
daemonize no
I urge you to read through your Redis config file and tailor it to your needs, it's documented very well.
Now create an Upstart script to manage the Redis service. Create a file at
/etc/init/redis.conf
and add the following to it:
description "Redis"
start on runlevel [23]
stop on shutdown
exec sudo -u redis /usr/local/bin/redis-server /etc/redis.conf
respawn
Finally, start Redis:
start redis
Time to compile and install Nginx, download the latest stable source from the Nginx Wiki, then download the latest version of the Nginx Upload Module, then compile and install:
Note: At the time of this writing, there is a bug with the downloadable version
of the Nignx Upload Module 2.2.0 and the version of GCC on Ubuntu 12.04, to work
around this issue, check-out this specific version of the Nignx Upload Module
into your /src
directory and compile against it instead of the downloadable
version above:
git clone -b 2.2 git://github.com/vkholodkov/nginx-upload-module.git nginx_upload_module-2.2.0
apt-get install libpcre3-dev
./configure --with-http_ssl_module --with-http_gzip_static_module --add-module=../nginx_upload_module-2.2.0
make
make install
Then create an Nginx user and a log directory:
useradd -r nginx
mkdir /var/log/nginx
chown nginx:nginx /var/log/nginx
Now copy over your favorite Nginx config into /etc/nginx.conf
:
cp nginx.conf /etc/nginx.conf
Create an Upstart process for Nginx, insert the following into
/etc/init/nginx.conf
:
# nginx
description "Nginx HTTP Daemon"
author "George Shammas <[email protected]>"
start on (filesystem and net-device-up IFACE=lo)
stop on runlevel [!2345]
env DAEMON="/usr/local/nginx/sbin/nginx -c /etc/nginx.conf"
env PID="/var/run/nginx.pid"
expect fork
respawn
respawn limit 10 5
pre-start script
$DAEMON -t
if [ $? -ne 0 ]
then exit $?
fi
end script
exec $DAEMON
Now it's time to install Ruby, use RVM, you will likely have to temporarily add the deploy user to sudoers in order to let RVM do it's automagic library install OR you can disable that probably and install them via your admin user.
Then install a Ruby:
rvm install 2.0.0
Make it the default interpreter for the deploy user:
rvm --default use 2.0.0
The base system is now provisioned! You have most of a full stack which you can deploy Ruby apps on with a database and Redis for running Sidekiq workers.
I have not covered a few things, for example logfile rotation. I feel that this is sort of a service-level decision, there are some different options or maybe you're using syslog, I leave that up to you.
I have not covered setting up a mail server such as Postfix, Linode provides some bad-ass guides if you choose that route. You might opt to use a third-party service such as Amazon's SES, or Sendgrid, I have used both and they are good options. Do some research and choose the best option for your needs.
I have not covered deploying a Ruby app to your new server either, I feel like that's outside the scope of this guide, but whatever you do deploy with Capistrano, and use Unicorn, or Puma, it looks pretty neat these days and I've used it successfully in production.
♥ ♥ ♥
@elucid Oh, you'd like that, wouldn't you!