-
Configure Ubuntu server with some sensible defaults with required and useful packages.
-
Vagrant using Ansible as the provisioner handles the VirtualBox development environment.
-
Ansible playbooks for creating, provisioning, and deploying to a DigitalOcean Ubuntu 20.04 droplet.
-
Create a new deployment user (called 'deployer') with passwordless login
-
SSH hardening
- Prevent password login
- Change the default SSH port
- Prevent root login
-
Setup UFW (firewall)
-
Setup Fail2ban
-
Creates a swapfile as they're great protection against an outage.
-
Install Logrotate
-
Setup Nginx with some sensible config (thanks to nginxconfig.io)
-
Certbot (for Let's encrypt SSL certificates)
- In development self-signed certs are used.
-
Ruby (using Rbenv).
- Defaults to
2.7.3
. You can change it in theapp-vars.yml
file - jemmaloc is also installed and configured by default
- rbenv-vars is also installed by default
- Defaults to
-
Node.js
- Defaults to 12.x. You can change it in the
app-vars.yml
file.
- Defaults to 12.x. You can change it in the
-
Yarn
-
Postgresql.
- Defaults to v12. You can specify the version that you need in the
app-vars.yml
file.
- Defaults to v12. You can specify the version that you need in the
-
Puma (with Systemd support for restarting automatically)
-
GoodJob (with Systemd support for restarting automatically)
-
Ansistrano hooks for performing the following tasks -
- Pulling your app from code repo.
- Installing all our gems.
- Precompiling assets.
- Migrating our database (using
run_once
).
This repo is to provide further intel that started with EmailThis.me Ansible Rails repo, Noah Gibb's fork, and Pete Hawkins's repo.
These playbooks don't work out of the box as they are hard-coded with variable and names for my Borderhound app, therefore, you'll have to do some minor editing and replacing.
git clone https://github.com/minimul/borderhound-server ansible-rails-ubuntu
cd ansible-rails-ubuntu
ansible-galaxy install -r requirements.yml
Open app-vars.yml
and change the variable to suit your needs. Additionally, please review the app-vars.yml
and see if there is anything else that you would like to modify (e.g.: install some other packages, change ruby, node or postgresql versions etc.)
Create a new vault
file to store sensitive information.
- Come up with a secure new vault password.
- Put that password, all by itself, into a file called
.vault_pass
in the root of this repo. rm group_vars/all/vault.yml
ansible-vault create group_vars/all/vault.yml
- Add the following information to this new vault file
vault_postgresql_db_password: "XXXXX_SUPER_SECURE_PASS_XXXXX"
vault_rails_master_key: "XXXXX_MASTER_KEY_FOR_RAILS_XXXXX"
- Note: You can used
ansible-vault edit group_vars/all/vault.yml
to make edits.
The .vault_pass
file will not be checked in by Git automatically because it's in the .gitignore
.
After modifying the configuration let's see if everything is working locally.
Take a look at the Vagrantfile first:
# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure(2) do |config|
config.vm.box = "bento/ubuntu-20.04"
ip_address = "192.168.2.200"
config.vm.network "public_network", :bridge => "en0: Ethernet", :ip => ip_address
config.vm.provision "ansible" do |ansible|
ansible.compatibility_mode = "2.0"
ansible.playbook = "provision.yml"
# ansible.tags = "common,environment"
# ansible.tags = "swapfile"
ansible.extra_vars = {
ansible_python_interpreter: "/usr/bin/python3",
within_virtual_box: true,
ip_address: ip_address
}
end
end
The IP address I'm using works on my subnet but maybe not on yours. For example, if your local IP address starts with 192.168.1.xxx
then you'll need an IP with that prefix. You don't have to use a Vagrant public_network
setting but it makes a more orthodox setup because then both development and production inventory files can then be IP centric.
vagrant box add bento/ubuntu-20.04
vagrant up
# vagrant up will run the ansible provisioning also. See Vagrantfile above.
# Next deploy your Rails app using Ansistrano.
ansible-playbook -i inventories/development.yml deploy.yml
If all goes well you should be able to see your app when to the IP address, 192.168.2.200
in my case.
Notes:
-
To provision in development you must use
vagrant provision
and it has all of the proper SSH settings. -
Remember to make use of the tags. See the
Vagrantfile
above for examples. Tags will save a bunch of time as you modify and hack the roles to meet your needs. -
The
inventories/development.yml
file is only for using thedeploy.yml
playbook to deploy your Rails app. You can use the inventory file for provisioning after the initial provision but it's best to just stick withvagrant provision
in development. -
I also made a host name entry (
borderhound-local.com
) in my local host file/etc/hosts
. You can do the same with your domain/app name because within the nginx role there will be aserver_name
entry added like this:{{ app_name }}-local.com
. This modification is only done in development.
You are going to need a DigitalOcean (DO) account and an API key. You should definitely leverage a DO floating IP and that is what I'm doing in these playbooks. The do-provision.yml
playbook will create a floating IP automatically. If you make a floating IP on DO manually (probably the best route frankly) then enter it in .env.yml
(see step 2). On subsequent do-provision.yml
runs the playbook will not try to make a new floating IP if it is present in .env.yml
.:
- Create a SSH key for new server e.g.:
cd ~/.ssh
ssh-keygen -t ed25519 -f borderhound
- Create a new file called
.env.yml
using the.env.yml.sample
file as a template. - Put that file in
.gitignore
:
echo .env.yaml >> .gitignore
ansible-playbook -e "@.env.yml" do-provision.yml
- Put the returned floating IP in .env.yml.
- Create a DNS "A" and "CNAME" record with the floating IP mapped to your domain name.
- Make sure your rails app Puma config file is similar or the same as the sample provided.
- Provision the droplet
ansible-playbook -e "@.env.yml" -i inventories/production.yml provision.yml
- Deploy your Rails app
ansible-playbook -e "@.env.yml" -i inventories/production.yml deploy.yml
Notes:
- Tags usage example:
ansible-playbook --tags fail2ban -e "@.env.yml" -i inventories/production.yml provision.yml
By default, the following packages are installed. You can add/remove packages to this list by changing the required_package
variable in app-vars.yml
You'll need to configure your S3 bucket manually and add in your S3 credentials but beside those things there shouldn't be much modifications needed to the pgbackup
role.
I have a download and restore backup to local Postgres script that'll also take just a little bit of modification to get working for your app. To create the download and restore script run this command ansible-playbook local-provision.yml
. You can then modified the outputted script download.and.restore.prod.db.sh
to your hearts content.
These Ansible roles work for Ansible 2.9.23. I suggest using the excellent ASDF in and aid to use get the correct Ansible version installed. So install ASDF first and then do these steps:
$ asdf plugin add python
$ asdf list all python | less
$ asdf plugin add python
$ asdf reshim
$ cd [ansible-rails-ubuntu dir]
$ echo 'python 3.8.5' > .tool-versions
$ pip install --upgrade pip
$ pip install ansible
pip install ansible==2.9.23
$ asdf reshim python
$ which ansible