Skip to content
This repository was archived by the owner on Nov 8, 2024. It is now read-only.

Commit df8dc3f

Browse files
committed
Create ansible playbooks for Elixir build server and for Phoenix Website
0 parents  commit df8dc3f

File tree

51 files changed

+1154
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+1154
-0
lines changed

.gitignore

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
.DS_Store
2+
.vagrant
3+
ubuntu-xenial-16.04-cloudimg-console.log
4+
*.retry
5+
callback_plugins/human_log.pyc
6+
/.downloaded_roles
7+
8+
# ignore private pass that you use to encrypt/decrypt credentials with Ansible
9+
vault_pass.txt
10+
11+
# ignore private keys for CI server
12+
/apps/elixir-build-server/circle_ci
13+
/apps/phoenix-website/circle_ci

LICENSE

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
Copyright (c) 2017 Lunar Logic https://lunarlogic.io
2+
3+
MIT License
4+
5+
Permission is hereby granted, free of charge, to any person obtaining
6+
a copy of this software and associated documentation files (the
7+
"Software"), to deal in the Software without restriction, including
8+
without limitation the rights to use, copy, modify, merge, publish,
9+
distribute, sublicense, and/or sell copies of the Software, and to
10+
permit persons to whom the Software is furnished to do so, subject to
11+
the following conditions:
12+
13+
The above copyright notice and this permission notice shall be
14+
included in all copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

README.md

+199
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
# Ansible Elixir Playbooks
2+
3+
This project has ansible playbooks for:
4+
5+
* Elixr Build Server - it has installed Erlang, Elixir and nodejs. Basically, all what is required to compile the Phoenix Framework application.
6+
* Phoenix Website - it is a playbook to provision server with installed PostgreSQL and configured nginx and Let's Encrypt for SSL. There is no Erlang/Elixir on this server because we will deploy there only compiled Phoenix application.
7+
8+
You can learn more about the project from this blog post (TODO: add here url).
9+
10+
## Requirements
11+
12+
### Control machine (your computer)
13+
14+
* Install [Ansible](https://www.ansible.com/)
15+
16+
* Download roles:
17+
18+
```shell
19+
$ ansible-galaxy install -r requirements.yml
20+
```
21+
22+
* Generate `vault_pass.txt` file into this repository. You need it to be able to encrypt/decrypt secrets.
23+
24+
:warning: For security reasons, the `vault_pass.txt` file should not be committed into the repository. It's ignored in `.gitignore`.
25+
26+
```shell
27+
$ openssl rand -base64 256 > vault_pass.txt
28+
```
29+
30+
* Generate your DB password and put output to `apps/phoenix-website/host_vars/phoenix-website.lunarlogic.io`
31+
32+
```shell
33+
$ ansible-vault encrypt_string --name db_password "YOUR_DB_PASSWORD"
34+
```
35+
36+
### Target machine (server)
37+
38+
* Server with [Ubuntu](https://www.ubuntu.com/) 16.04 LTS.
39+
40+
## Public keys
41+
42+
We keep our public keys in [public_keys/] directory. This set of keys is uploaded to the server during each provisioning
43+
and overwrites the list of authorized keys, so proper people have access to the server. It is important to keep
44+
the list of keys up to date.
45+
46+
If you don't know how to generate a key for yourself,
47+
[read this article](https://help.github.com/articles/connecting-to-github-with-ssh/).
48+
49+
## App deployement
50+
51+
### CircleCI deployment
52+
53+
If you want to deploy app from CI to the staging/production host then you must generate RSA keys for CircleCI.
54+
55+
```shell
56+
$ ssh-keygen -t rsa -b 4096 -N "" -C "circle_ci" -f ./apps/elixir-build-server/circle_ci
57+
$ ssh-keygen -t rsa -b 4096 -N "" -C "circle_ci" -f ./apps/phoenix-website/circle_ci
58+
```
59+
60+
Add `circle_ci.pub` public key to your app playbook for the role `user`:
61+
62+
```
63+
- role: user/0.0.1
64+
username: phoenix
65+
authorized_key_paths:
66+
- ../../public_keys/*.pub
67+
- ./circle_ci.pub # add this line
68+
```
69+
70+
Go to CircleCI and find your project, open settings and find `SSH Permissions`. Click `Add an SSH key` button and paste there private key `apps/YOUR_APP_NAME/circle_ci`.
71+
72+
Now you can remove private key `apps/YOUR_APP_NAME/circle_ci` from local machine. It should not be commited into repo!
73+
74+
Commit into repo only public key `apps/YOUR_APP_NAME/circle_ci.pub`.
75+
76+
You can always generate a new fresh keys if you need it hence no reason to backup private key. You already added it to CircleCI.
77+
78+
## Run playbooks
79+
80+
__Warning:__ This command will provision all servers listed in inventory file for particular app `apps/app_name`.
81+
82+
```shell
83+
$ ./play apps/app_name
84+
```
85+
86+
If you want to provision only specific machine do (it's useful if your app is deployed to multiple servers like staging and production):
87+
88+
```shell
89+
# Warning: There must be comma and the end of the hosts list!
90+
$ ansible-playbook -i 'example-staging.lunarlogic.io,' apps/app_name/playbook.yml
91+
```
92+
93+
## Provisioning logs
94+
95+
You can check when and with what git commit the host was provisioned in log file: `/var/log/provision.log` (stored on the target machine).
96+
97+
## System users
98+
99+
There are 3 types of users on the server:
100+
101+
* `root` - for provisioning
102+
* `admin` - user has the sudo access
103+
* `app_name_user` - for instance `phoenix` user for Phoenix Website application. The user has no sudo access. The application is running under this user.
104+
105+
## Add playbook for new app
106+
107+
* create new app directory in the `app` directory
108+
* in this new directory create `playbook.yml` and `inventory` files
109+
* in the `inventory` file put host names to provision (see [Ansible docs](http://docs.ansible.com/ansible/intro_inventory.html))
110+
* implement `playbook.yml`
111+
112+
## Secrets
113+
114+
We store secrets in encrypted version using [Vault]. If you are adding new secrets, make sure you commit them to the repository in the encrypted form.
115+
116+
* Encrypting single values (that can be placed inside a "clear text" YAML file, using the `!vault` tag):
117+
118+
```shell
119+
$ ansible-vault encrypt_string --name pass_to_some_service "secret" # stdout encrypted string
120+
```
121+
122+
* Encrypting whole YAML files:
123+
124+
```shell
125+
$ ansible-vault encrypt secret.yml # encrypt unencrypted file
126+
$ ansible-vault edit secret.yml # edit encrypted file
127+
$ ansible-vault decrypt secret.yml # decrypt encrypted file
128+
```
129+
130+
## Roles
131+
132+
### Role versioning
133+
134+
We use roles versioning the simplest possible way, we just add version subdirectories under every role directory.
135+
136+
```shell
137+
roles/role-name/role-version/ # e.g. roles/webserver/0.3.2/
138+
```
139+
140+
To create a new version just copy an existing one, bump the role version and modify it.
141+
Please, respect [Semantic Versioning 2.0.0].
142+
143+
### Community developed roles
144+
145+
Include the roles in [requirements.yml] and download them using the following command:
146+
147+
```shell
148+
$ ansible-galaxy install -r requirements.yml
149+
```
150+
151+
### SSL with Let's Encrypt
152+
153+
You can use `lets_encrypt` role to generate free SSL certificate thanks to https://letsencrypt.org
154+
155+
#### Rate Limits
156+
157+
The main limit is Certificates per Registered Domain (20 per week).
158+
159+
https://letsencrypt.org/docs/rate-limits/
160+
161+
If you are testing Let's Encrypt then use `staging` environment with higher limits!
162+
163+
```
164+
- role: lets_encrypt/0.0.1
165+
app_name: myapp
166+
lets_encrypt_contact_email: [email protected]
167+
lets_encrypt_environment: staging # you can change it to production once ready
168+
```
169+
170+
#### If you want to change main domain for your certificate
171+
172+
If you want to change main domain for your certificate then you need to generate a new certificate.
173+
174+
Here is example file for [Phoenix Website project with multiple domains](apps/phoenix-website/host_vars/phoenix-website.lunarlogic.io).
175+
176+
In order to generate a new certificate please remove first the old files generated by `lets_encrypt` role on the server:
177+
178+
```shell
179+
$ rm -rf /etc/letsencrypt/accounts/*
180+
$ rm -rf /etc/letsencrypt/archive/*
181+
$ rm -rf /etc/letsencrypt/csr/*
182+
$ rm -rf /etc/letsencrypt/keys/*
183+
$ rm -rf /etc/letsencrypt/live/*
184+
$ rm -rf /etc/letsencrypt/renewal/*
185+
186+
# remove the snippents that load SSL certificate
187+
$ rm -rf /etc/nginx/snippets/project_name
188+
```
189+
190+
Ensure the nginx is running. It's required so Let's Encrypt can do request to our domain.
191+
Provision server again.
192+
193+
Note: If you would like to add a new subdomain to domain list then you can just provision server and a new subdomain will be added to the certificate. You need to generate certificate from scrach only if you change the main domain (the first domain on the list of domains).
194+
195+
196+
[Vault]: http://docs.ansible.com/ansible/playbooks_vault.html
197+
[public_keys/]: public_keys/
198+
[requirements.yml]: requirements.yml
199+
[Semantic Versioning 2.0.0]: http://semver.org/

ansible.cfg

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[defaults]
2+
vault_password_file = ./vault_pass.txt
3+
roles_path = ./.downloaded_roles:./roles
4+
callback_plugins = ./callback_plugins
5+
6+
[ssh_connection]
7+
control_path = %(directory)s/%%C
+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC7MmV55/7vG7kCYmwwVVOYRGz2bT2RHlSmoAVGUZ95+hDdVIRKZsP3zs+jm0Kr08RlYlw1BToH0yyZK3rjq7QARfmw1zmwtVtccP3nscHT1KQyx+docjYdmsTLGm7ylKyHrQ+lOq80/rCMsnxf0S+/fxGEThGgh0zxRsEZUz0AofSqEgrm10PBcPdw7m6RE8DTEArjXaQRwhrlcMyEHaEvAVpLhEKjpE/9DY8ZJB4y8bxXlr0ORBaw0G6IPXVSOUaWNiJqgJ+OyzSqiMTqKDqg6BhSetcDCEMn3VW+kQquqbuU8qp6Yr8XjG+NXDb6gt4S48TdqQg/o4uZnNPUDW8otyyAcHBpVqdF1nNwqE80wvDHHpOytfD/+s9M2l43s6f/RV71myghtALxFKMo44Fzw30L0gsL79iQw8WXClI1bdBdjLiSG3vj67LKk+OCy335816VsfTYU7Oh7H6TUc5jooiUPKAopLF9Qm9WSFm8B1CW1UdajrWzT6SAdScFxaQbG6IUX4EDz32jz3mpDFN8huLCXkmgDctynhTROHJxq3vbOSOi8gGYUIDJuSbe2OvuMSZ1wILPqu5k1Tw5zMUC63Ggqi9TfRt++eX30hU4YVIyNJJEaiMmGTzSnN9/awUl5bqdmPkwQ9xrBhi8U4DR7edtX2LVUHfujpdL6PJNbQ== circle_ci

apps/elixir-build-server/inventory

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
elixir-build-server.lunarlogic.io

apps/elixir-build-server/playbook.yml

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
---
2+
- hosts: all
3+
user: root
4+
gather_facts: no
5+
pre_tasks:
6+
- name: install python
7+
raw: sudo apt-get -y install python-minimal
8+
9+
- action: setup
10+
11+
roles:
12+
- role: bootstrap/0.0.1
13+
hostname: elixir-build-server
14+
domain: lunarlogic.io
15+
authorized_key_paths:
16+
- ../../public_keys/*.pub
17+
18+
- role: user/0.0.1
19+
username: admin
20+
sudoer: True
21+
authorized_key_paths:
22+
- ../../public_keys/*.pub
23+
24+
- role: install-build-essential/0.0.1
25+
26+
- role: install_elixir/0.0.1
27+
28+
- role: install_nodejs/0.0.1
29+
30+
- role: user/0.0.1
31+
username: builder
32+
authorized_key_paths:
33+
- ../../public_keys/*.pub
34+
- ./circle_ci.pub
35+
36+
# This must be the last one role to log info about successfully provisioned machine.
37+
- role: provision_log/0.0.1

apps/phoenix-website/circle_ci.pub

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQChdYQSoh1rlAS1YBzoB4hMPA/Mm88WqV9ANa/gcxDH4Q+urc5MM35srlv7G9KMY5I0XHeFb1eT0GyldoNnvJFr6ZvtyaUAKloN8s4uavST7xofFhKH0WU3PhVM83Uu6kVDikfwmgTkvaW+dfkW02TWBJWP6taKPGRcVvGk5QISCxYKreUPFj0BIL+d66S2+vp2ypGpEAt3RjHfpa+ExgNnhqNk6pARhwQxGKa2wwgTcfPVdisBJ3cr0N1YTzLz+ko2KYQec2IR/W4gjsubKb7NeJpDkRDmYIqJUomQf5IA8OgXNZ1i/jt6W/3IXdq5wjnZKUAd88PvnFTVHGseY+QEvMlhqsUxZYAFqvbADyofNwilJsy4ZBU4tizR6dHJ4P5G9qT7D1MBx7AwbMiw2z/b2brLgrDcSHD/N/lT3+VJAASNQrn42PB+WaaDQhkCSPCVM+3njQisO24ARQNsqfRcaqDv/faBJKqLcRsk3QQkGgqaJVXWHLsLYAQxALsOz8QA2bWrO3rVy6vjFtLzgosgmB7zHfb39Pv966AWBn5BicYMCw1Pa2YEqNxcXcNOvXnquSL0IxCVTedT+hiJg8WKcRNbeZ0ZsW1zVIQW42X70nKlnC5S3aAx+6II8aVdXaSgjTypidkrv/n6mRimdNW+2tQCEHPMU5TQaDBXUHL20w== circle_ci
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
hostname: phoenix
3+
domains:
4+
# first domain is the main domain
5+
- phoenix-website.lunarlogic.io
6+
# other domains redirect to the main domain
7+
- www.phoenix-website.lunarlogic.io
8+
db_password: !vault |
9+
$ANSIBLE_VAULT;1.1;AES256
10+
35313965306661613265333736386365613931643764616533613137626161623232393261653832
11+
6631393234313761303539316335373539663965613963620a663831366338383934346632643065
12+
33646165303366623464623730363530656438373262373937396164383963396262393266343035
13+
6137663666353562640a383361653635396437313936373365313431303734316461326364336538
14+
63356331666263643665306561386664636138646265663036646331383037643531393366613963
15+
3536313631373166303865303636393038396365306466376166

apps/phoenix-website/inventory

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
phoenix-website.lunarlogic.io

apps/phoenix-website/playbook.yml

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
---
2+
- hosts: all
3+
user: root
4+
gather_facts: no
5+
pre_tasks:
6+
- name: install python
7+
raw: sudo apt-get -y install python-minimal
8+
9+
- action: setup
10+
11+
roles:
12+
- role: bootstrap/0.0.1
13+
authorized_key_paths:
14+
- ../../public_keys/*.pub
15+
16+
- role: user/0.0.1
17+
username: admin
18+
sudoer: True
19+
authorized_key_paths:
20+
- ../../public_keys/*.pub
21+
22+
- role: install_nginx/0.0.1
23+
24+
- role: install_postgresql/0.0.1
25+
26+
- role: imagemagick/0.0.1
27+
28+
- role: user/0.0.1
29+
username: phoenix
30+
authorized_key_paths:
31+
- ../../public_keys/*.pub
32+
- ./circle_ci.pub
33+
34+
- role: configure-postgresql/0.0.1
35+
username: phoenix
36+
database_name: phoenix
37+
38+
- role: phoenix-app/0.0.1
39+
username: phoenix
40+
app_name: phoenix
41+
42+
- role: lets_encrypt/0.0.1
43+
app_name: phoenix
44+
45+
# This must be the last one role to log info about successfully provisioned machine.
46+
- role: provision_log/0.0.1

0 commit comments

Comments
 (0)