https://github.com/thredded/thredded-ansible
A starter set of playbooks for provisioning and deploying a Thredded app.
https://github.com/thredded/thredded-ansible
Last synced: 4 months ago
JSON representation
A starter set of playbooks for provisioning and deploying a Thredded app.
- Host: GitHub
- URL: https://github.com/thredded/thredded-ansible
- Owner: thredded
- License: mit
- Created: 2017-02-28T23:06:01.000Z (over 9 years ago)
- Default Branch: master
- Last Pushed: 2018-07-01T13:27:50.000Z (about 8 years ago)
- Last Synced: 2025-02-28T22:19:37.415Z (over 1 year ago)
- Language: HTML
- Homepage:
- Size: 38.1 KB
- Stars: 3
- Watchers: 5
- Forks: 2
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE.txt
Awesome Lists containing this project
README
# Ansible Playbooks for running a Thredded App on Ubuntu 18.04
This is a starter set of [Ansible](https://www.ansible.com/) playbooks
for deploying a Thredded app to an Ubuntu 18.04 server.
**Warning: Experimental, there be dragons.**
These playbooks provide a good starting point if you're looking to deploy
Thredded to a VPS or to a bare-metal server.
TODO:
1. Email via postfix.
2. Backups via [backup](https://github.com/backup/backup).
## Table of Contents
* [Overview](#overview)
* [Provisioning](#provisioning)
* [Deployment](#deployment)
* [App compatibility](#app-compatibility)
* [Usage](#usage)
* [Deploying to VirtualBox](#deploying-to-virtualbox)
* [Deploying to production](#deploying-to-production)
* [Adding the server to the hosts inventory](#adding-the-server-to-the-hosts-inventory)
* [Creating a user for provisioning](#creating-a-user-for-provisioning)
* [Provisioning](#provisioning-1)
* [Deploying](#deploying)
* [Configure HTTPS](#configure-https)
* [Enable backups](#enable-backups)
* [Configure outgoing email (SMTP)](#configure-outgoing-email-smtp)
* [How to](#how-to)
* [Deploy a new version of the app to the production server](#deploy-a-new-version-of-the-app-to-the-production-server)
* [Update the app's environment variables](#update-the-apps-environment-variables)
* [See the logs](#see-the-logs)
* [Open a rails console on a production server](#open-a-rails-console-on-a-production-server)
* [Tips](#tips)
* [Credits](#credits)
## Overview
There are two playbooks included: `provision.yml` and `deploy.yml`.
### Provisioning
The provisioning playbook must be run as a user with password-less `sudo` access.
This playbook ensures the following:
Via the `webapp` role:
* System-wide dependencies are installed and are up-to-date.
* The app-specific user exists.
* The app directory (`/var/www/$APP` by default) exists and belongs to the
app-specific user.
Via the `db` role:
* The Postgresql database server is set up and has a user for the app.
Via the `memcached` role:
* The memcached server is set up (by default, on the same machine(s) as
the webserver(s)).
Via the `nginx` role:
* The nginx webserver is set up and the app's site configuration is up to date.
Via the `foreman_systemd` role:
* The app services are managed by `systemd` and their configuration
is exported via [foreman](http://ddollar.github.io/foreman/) from `files/Procfile`.
* The app-specific user has permissions to start and stop app services.
Via the `letsencrypt` role (production only):
* Let's Encrypt is configured to provide and automatically renew the SSL
certificate for the app's webserver.
### Deployment
The deployment playbook is run as the app-specific user.
This playbook ensures the following via the `deploy-rails` role:
* The configured Ruby version is installed (via `rbenv`).
* The app's environment variables are up to date (set in `~/.pam_envinoment`).
The playbook then fetches the Rails app code from the configured git repository,
compiles the assets, runs the migrations, and restarts the app services.
### App compatibility
These playbooks work out of the box with apps created with
[thredded_create_app](https://github.com/thredded/thredded_create_app) v0.1.10+.
If your app was created with an older version of thredded_create_app,
or was not created with thredded_create_app, you'll need to:
1. Copy the [config/puma.production.rb](https://raw.githubusercontent.com/thredded/thredded_create_app/master/lib/thredded_create_app/tasks/production_configs/puma.production.rb) file.
2. Add the following snippet to the `config/environments/production.rb` file:
```ruby
if ENV['MEMCACHE_SERVERS']
config.cache_store = :dalli_store,
ENV['MEMCACHE_SERVERS'].split(','), {
namespace: ENV['APP_ID'] || raise("ENV['APP_ID'] not set"),
socket_timeout: 1.5,
socket_failure_delay: 0.2,
down_retry_delay: 60,
pool_size: [2, ENV.fetch('WEB_CONCURRENCY', 3).to_i *
ENV.fetch('MAX_THREADS', 5).to_i].max
}
end
```
3. Ensure that the `config/database.yml` file uses `ENV['DATABASE_URL']` in production, i.e.:
```yaml
production:
url: <%= ENV['DATABASE_URL'].inspect if ENV['DATABASE_URL'] %>
```
## Usage
First, clone this repo.
```bash
git clone https://github.com/thredded/thredded-ansible myapp-ansible
cd myapp-ansible
```
Then, copy the example variables file:
```bash
# Set the APP env var to your app name. Will be used throughout the Readme.
APP=myapp
# Copy the example variables file:
cp vars/example.yml "vars/${APP}.yml"
```
Then, set the required variables in the variables file.
Also, have a look at the `vars/defaults.yml` for the optional variables and
their defaults.
Finally, see the section below to try out your setup in a VM.
Once you've confirmed it's working in a VM, you can proceed to set up and deploy
to a real server or a VPS. **The Readme section for this is not ready yet.**
## Deploying to VirtualBox
First, install VirtualBox v5.0+ and Vagrant v1.9+.
Then, create a new instance with:
```bash
vagrant up
```
Then, **provision** the VM instance:
```bash
ansible-playbook provision.yml -e "config=vars/${APP}.yml" -u ubuntu --private-key=.vagrant/machines/vm1/virtualbox/private_key
```
*If you get an SSH error, verify that you can
[SSH into the host as the `ubuntu` user](#tips)*.
Now, add the app user SSH key to the app's Git repository deploy keys.
1. Print the key with:
```bash
ansible webservers -u $APP -a 'cat ~/.ssh/id_rsa.pub'
```
2. Add the key to the deploy keys in your repository settings.
On GitLab, the deploy keys settings page is at:
```
https://gitlab.com/$USER/$APP/deploy_keys
```
On GitHub, it's at:
```
https://github.com/$USER/$APP/settings/keys
```
Then, **deploy** to the VM instance:
```bash
ansible-playbook deploy.yml -e "config=vars/${APP}.yml"
```
This will run the migrations, but you might also want to seed the database
if deploying for the first time. You can do so by running:
```bash
ansible 'webservers[0]' -u $APP -a "chdir=/var/www/$APP/current bundle exec rails db:seed"
```
Congratulations! You can now open the app at http://localhost:8080 and log in as
`admin@$APP.com` with password `123456`.
## Deploying to production
The guide describes provisioning deploying to a single production server.
The process is largely identical to deploying to Vagrant, but we will also:
1. Enable HTTPS via letsencrypt with automated certificate renewal.
2. Enable daily database backups using [backup]. **TODO**
3. Configure the [postfix] mail transfer agent to send email. **TODO**
This guide focuses on the differences from the VirtualBox guide above and
assumes that you have already followed the VirtualBox guide.
[backup]: https://github.com/backup/backup
[postfix]: http://www.postfix.org/
### Adding the server to the hosts inventory
First, we need to create the hosts inventory file for our production hosts:
1. Copy the example hosts file:
```bash
cp hosts/example hosts/${APP}-prod
```
2. Set the host IP address in the `hosts/${APP}-prod` file.
We will need to tell Ansible to use this inventory file by passing
`-i hosts/${APP}-prod` to every `ansible` and `ansible-playbook` command.
Alternatively, you can change the default inventory file in `ansible.cfg`.
### Creating a user for provisioning
If you've created a new server with something like [Scaleway](https://scaleway.com)
(offers a 3 € a month VPS large enough for Thredded) then the server by default
will only have a root user with SSH key authentication, so you can skip this step.
**If** you do not have password-less SSH-as-root, or you'd prefer to not use
the root user (e.g. if you work in a team), you can create another user instead
like this:
1. Create a user with the same name as your local user on the production servers.
Omit the `password` argument if you're sure you'll never lose your SSH key.
```bash
ansible all -i hosts/${APP}-prod -u root -m user -a \
"name=$USER groups=sudo password=$(mkpasswd --method=sha-512)"
```
2. Authorize your SSH key to connect as `$USER`:
```bash
ansible all -i hosts/${APP}-prod -u root -m authorized_key -a \
"user=$USER key={{lookup('file', '~/.ssh/id_rsa.pub')}}"
```
3. Allow the newly created user to run `sudo` **without password**:
```bash
ansible all -i hosts/${APP}-prod -u root -m lineinfile -a \
"path=/etc/sudoers.d/$USER create=yes line='$USER ALL=(ALL) NOPASSWD:ALL' validate='/usr/sbin/visudo -cf %s'"
```
4. Pass `-u $USER` instead of `-u root` to Ansible in the
*Provisioning* commands below.
### Provisioning
Copy the vars config file you've created earlier for Vagrant, as we'll need the
configuration to be slightly different (we'll change it afterwards).
```bash
cp vars/${APP}.yml vars/${APP}-prod.yml
```
You may want to change all the passwords and the secret key in the new config.
Then, run the provisioning playbook:
```bash
ansible-playbook provision.yml -u root -e "config=vars/${APP}-prod.yml" -i hosts/${APP}-prod
```
### Deploying
1. Add the SSH key of the app user to your git repository deploy keys.
To print the key, run:
```bash
ansible webservers -i hosts/${APP}-prod -u $APP -a 'cat ~/.ssh/id_rsa.pub'
```
2. Run the deployment playbook:
```bash
ansible-playbook deploy.yml -i hosts/${APP}-prod -e "config=vars/${APP}-prod.yml"
```
3. Seed the database:
```bash
ansible 'webservers[0]' -i hosts/${APP}-prod -u $APP -a "chdir=/var/www/$APP/current bundle exec rails db:seed"
```
Congratulations! You can now open the app at the server's IP and log in as
`admin@$APP.com` with password `123456`. Change the password immediately.
### Configure HTTPS
Next, we will configure HTTPS with Let's Encrypt, including certificate
auto-renewal.
For this, you will need to have `{{app_host}}` and `www.{{app_host}}`
configured as the A-records for your server IP.
First, in the `vars/${APP}-prod.yml` file, set the `app_host` and uncomment the
*HTTPS with Let's encrypt* section.
Then, run the provisioning playbook:
```bash
ansible-playbook provision.yml -u root -e "config=vars/${APP}-prod.yml" -i hosts/${APP}-prod
```
That's it! Verify that `https://{{app_host}}` works, and that these variations
all redirect to that URL: `http://{{app_host}}`, `http://www.{{app_host}}`,
and `https://www.{{app_host}}`.
Test the quality of your HTTPS configuration at [SSL Labs](https://ssllabs.com/ssltest/).
### Enable backups
TODO
### Configure outgoing email (SMTP)
You'll also need to configure your app to send email correctly.
One way to do this is by using a 3-rd party SMTP server such as GMail or Zoho.
GMail requires a paid Google Apps for Business suite for use with a custom
domain, while [Zoho](https://www.zoho.com/) is free.
Once you configure your domain with Zoho, here is the email configuration
you can put in `config/environments/production.rb`:
```ruby
config.action_mailer.default_url_options = { host: ENV['APP_HOST'], protocol: 'https' }
config.action_mailer.perform_deliveries = true
config.action_mailer.raise_delivery_errors = true
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
address: 'smtp.zoho.com',
port: 587,
domain: ENV['APP_HOST'],
user_name: ENV['SMTP_USER'],
password: ENV['SMTP_PASSWORD'],
authentication: :plain,
enable_starttls_auto: true,
}
```
You also need to set `Thredded.email_from` in the Thredded initializer,
and `config.mailer_sender` in the devise initializer.
Then, set `SMTP_USER/PASSWORD` under `app_user_env` in `vars/${APP}-prod` and deploy.
**NB:** Many VPS hosting providers, such as Scaleway and DigitalOcean, block
outgoing connections to 587 by default. Make sure to change this in the settings.
For Scaleway, see [this FAQ entry](https://www.scaleway.com/faq/server/network/#-I-cannot-send-any-email).
Zoho free tier is limited to 1,000 emails sent per day (up to 5,000 on paid plans),
while GMail is limited to [2,000 / day](https://support.google.com/a/answer/166852?hl=en),
so you will want to use a specialized service like [Mailgun](https://www.mailgun.com/),
or host your own server once you exceed that. **TODO: Postfix role.**
## How to
### Deploy a new version of the app to the production server
Run the deployment playbook:
```bash
ansible-playbook deploy.yml -i hosts/${APP}-prod -e "config=vars/${APP}-prod.yml"
```
### Update the app's environment variables
Update the `vars/$APP.yml` file and either do a full deploy, or run:
```bash
ansible-playbook deploy.yml -e "config=vars/${APP}.yml" --tags env
```
The command above will only update the environment and then restart the app.
**NB**: Removing an environment variable from `vars/$APP.yml` does **not**
remove it from the environment file on the server (`~$APP/.pam_environment`).
### See the logs
The application and webserver logs are located at `/var/www/$APP/shared/log`.
The app service output (such as errors when starting the services)
is logged to `/var/log/syslog`.
### Open a `rails console` on a production server
In production:
```bash
# Replace "${IP}" with the server's IP address
ssh ${APP}@${IP} -t "cd /var/www/$APP/current && bundle exec rails c"
```
To print a server IP address / hostname:
```bash
ansible 'webservers[0]' -i hosts/${APP}-prod -m debug -a 'var=ansible_host' | grep -oE "[0-9.]{2,}"
```
On VirtualBox:
```bash
ssh $APP@127.0.0.1 -p 2222 -t "cd /var/www/$APP/current && bundle exec rails c"
```
## Tips
You can ssh into the VirtualBox instance on port 2222:
```bash
# As the "ubuntu" user (this user can run sudo without a password)
ssh ubuntu@127.0.0.1 -p2222 -i .vagrant/machines/vm1/virtualbox/private_key
# As the app user
ssh $APP@127.0.0.1 -p2222
```
To run a command as the web user via Ansible:
```bash
# Use webservers[0] for just one of the servers
ansible webservers -u $APP -a "chdir=/var/www/$APP/current bundle exec rails db:seed"
```
To see the output of commands as they run,
pass the `-vvv` flag to `ansible` or `ansible-playbook`.
## Credits
* The Rails deployment role is based on: https://github.com/nicolai86/ansible-rails-deployment.
* Rbenv installation is based on: https://github.com/erasme/ansible-rbenv.
* The Nginx role is based on: https://github.com/jdauphant/ansible-role-nginx.
* The Memcached role is based on: https://github.com/geerlingguy/ansible-role-memcached.
* The Nginx HTTPS config is based on: http://stackoverflow.com/a/41948807/181228
* Let's encrypt HTTPS certs and auto-renewal are based on:
* https://github.com/thefinn93/ansible-letsencrypt
* https://gist.github.com/mattiaslundberg/ba214a35060d3c8603e9b1ec8627d349