2017-07-20 16:48:34 +02:00
# Install Fabmanager app in production with Docker
2016-03-23 18:39:41 +01:00
2017-07-20 17:14:02 +02:00
This README tries to describe all the steps to put a fabmanager app into production on a server, based on a solution using Docker and DigitalOcean.
2017-07-20 16:48:34 +02:00
In order to make it work, please use the same directories structure as described in this guide in your fabmanager app folder.
2016-03-23 18:39:41 +01:00
2017-07-20 17:14:02 +02:00
##### Table of contents
2017-07-20 17:18:19 +02:00
1. [Preliminary steps ](#preliminary-steps )< br />
1.1. [docker/env file ](#docker-env )< br />
1.2. [docker/nginx_with_ssl.conf.example file ](#nginx-conf )< br />
1.3. [setup the server ](#setup-server )< br />
1.4. [buy a domain name and link it with the droplet ](#buy-domain-link-droplet )< br />
1.5. [connect to the droplet via SSH ](#connect-to-droplet )< br />
1.6. [create SWAP file in coreOs ](#create-swap-file )< br />
1.7. [setup folders and env file ](#setup-folders-env-file )< br />
1.8. [SSL certificate with LetsEncrypt ](#ssl-certificate-letsencrypt )< br />
2017-07-20 17:15:20 +02:00
1.9. [install docker-compose ](#install-docker-compose )
2017-07-20 17:18:19 +02:00
2. [Deployment ](#deployment )< br />
2.1. [pull images ](#pull-images )< br />
2.2. [setup database ](#setup-database )< br />
2.3. [build assets ](#build-assets )< br />
2.4. [prepare Elasticsearch (search engine) ](#prepare-elastic )< br />
2017-07-20 17:15:20 +02:00
2.5. [start all services ](#start-services )
2017-07-20 17:14:02 +02:00
3. [Generate SSL certificate by Letsencrypt ](#generate-sll-cert-letsencrypt )
4. [Docker utils ](#docker-utils )
2017-07-20 17:18:19 +02:00
5. [Fabmanager update ](#update-fabmanager )< br />
5.1. [Steps ](#update-steps )< br />
2017-07-20 17:15:20 +02:00
5.2. [Good to know ](#good-to-know )
2017-07-20 17:14:02 +02:00
2017-07-20 16:48:34 +02:00
## Preliminary steps
2017-07-20 17:14:02 +02:00
< a id = "preliminary-steps" > < / a >
2017-07-20 16:48:34 +02:00
2017-07-20 17:14:02 +02:00
### docker/env file
< a id = "docker-env" > < / a >
2016-03-23 18:39:41 +01:00
2016-04-11 20:24:09 +02:00
Make a copy of the **env.example** and use it as a starting point.
2017-07-20 16:48:34 +02:00
Set all the environment variables needed by your application. Please refer to the [FabManager README ](https://github.com/LaCasemate/fab-manager/blob/master/README.md ) for explanations about those variables.
2016-03-23 18:39:41 +01:00
2017-07-20 17:14:02 +02:00
### docker/nginx_with_ssl.conf.example file
< a id = "nginx-conf" > < / a >
2016-04-11 20:24:09 +02:00
* Replace **MAIN_DOMAIN** (example: fab-manager.com).
* Replace **URL_WITH_PROTOCOL_HTTPS** (example: https://www.fab-manager.com).
* Replace **ANOTHER_URL_1** , **ANOTHER_URL_2** (example: .fab-manager.fr)
2017-07-20 16:48:34 +02:00
Side note:
* Use nginx.conf.example if you are not using **SSL**
2016-04-11 20:24:09 +02:00
### setup the server
2017-07-20 17:14:02 +02:00
< a id = "setup-server" > < / a >
2016-04-11 20:24:09 +02:00
Go to **DigitalOcean** and create a Droplet with operating system coreOS **stable** .
2017-07-20 16:48:34 +02:00
You need at least 2GB of addressable memory (RAM + swap) to install and use FabManager.
Choose a datacenter. Set the hostname as your domain name.
2016-04-11 20:24:09 +02:00
2017-07-20 17:14:02 +02:00
### buy a domain name and link it with the droplet
< a id = "buy-domain-link-droplet" > < / a >
2016-04-11 20:24:09 +02:00
1. Buy a domain name on OVH
2017-07-20 16:48:34 +02:00
2. Replace the IP address of the domain with the droplet's IP (you can enable the flexible ip and use it)
3. **Do not** try to access your domain name right away, DNS are not aware of the change yet so **WAIT** and be patient.
2016-04-11 20:24:09 +02:00
2017-07-20 17:14:02 +02:00
### connect to the droplet via SSH
< a id = "connect-to-droplet" > < / a >
2016-04-11 20:24:09 +02:00
You can already connect to the server with this command: `ssh core@droplet-ip` . When DNS propagation will be done, you will be able to
connect to the server with `ssh core@your-domain-name` .
2017-07-20 17:14:02 +02:00
### create SWAP file in coreOS
< a id = "create-swap-file" > < / a >
2016-03-23 18:39:41 +01:00
2017-07-20 16:48:34 +02:00
Firstly, switch to sudo and create a swap file
2016-04-11 20:24:09 +02:00
2016-03-23 18:39:41 +01:00
```bash
sudo -i
touch /2GiB.swap
chattr +C /2GiB.swap
fallocate -l 2048m /2GiB.swap
chmod 600 /2GiB.swap
mkswap /2GiB.swap
```
2016-04-11 20:24:09 +02:00
Create file ** /etc/systemd/system/swap.service**, filling it with the lines:
2016-03-23 18:39:41 +01:00
```bash
[Unit]
Description=Turn on swap
[Service]
Type=oneshot
Environment="SWAPFILE=/2GiB.swap"
RemainAfterExit=true
ExecStartPre=/usr/sbin/losetup -f ${SWAPFILE}
ExecStart=/usr/bin/sh -c "/sbin/swapon $(/usr/sbin/losetup -j ${SWAPFILE} | /usr/bin/cut -d : -f 1)"
ExecStop=/usr/bin/sh -c "/sbin/swapoff $(/usr/sbin/losetup -j ${SWAPFILE} | /usr/bin/cut -d : -f 1)"
ExecStopPost=/usr/bin/sh -c "/usr/sbin/losetup -d $(/usr/sbin/losetup -j ${SWAPFILE} | /usr/bin/cut -d : -f 1)"
[Install]
WantedBy=multi-user.target
```
Then add service and start:
2016-04-11 20:24:09 +02:00
2016-03-23 18:39:41 +01:00
```bash
systemctl enable /etc/systemd/system/swap.service
2016-04-11 20:24:09 +02:00
systemctl start swap
2016-03-23 18:39:41 +01:00
exit
```
2017-07-20 17:14:02 +02:00
### setup folders and env file
< a id = "setup-folders-env-file" > < / a >
2016-03-23 18:39:41 +01:00
2016-04-11 20:24:09 +02:00
```bash
2016-03-23 18:39:41 +01:00
mkdir -p /home/core/fabmanager/config
2016-04-11 20:24:09 +02:00
```
2016-07-21 15:11:08 +02:00
Copy the previously customized `env.example` file as `/home/core/fabmanager/config/env`
2016-04-11 20:24:09 +02:00
```bash
2016-03-23 18:39:41 +01:00
mkdir -p /home/core/fabmanager/config/nginx
2016-04-11 20:24:09 +02:00
```
2016-03-23 18:39:41 +01:00
2016-07-21 15:11:08 +02:00
Copy the previously customized `nginx_with_ssl.conf.example` as `/home/core/fabmanager/config/nginx/fabmanager.conf`
OR
Copy the previously customized `nginx.conf.example` as `/home/core/fabmanager/config/nginx/fabmanager.conf` if you do not want ssl support (not recommended !).
2016-07-21 15:21:33 +02:00
### SSL certificate with LetsEncrypt
2017-07-20 17:14:02 +02:00
< a id = "ssl-certificate-letsencrypt" > < / a >
*TO BE READ ONLY IF YOU WANT TO USE SSL*.
2017-07-20 16:48:34 +02:00
2016-07-21 15:11:08 +02:00
Let's Encrypt is a new Certificate Authority that is free, automated, and open.
Let’ s Encrypt certificates expire after 90 days, so automation of renewing your certificates is important.
2017-07-20 16:48:34 +02:00
Here is the setup for a systemd timer and service to renew the certificates and reboot the app Docker container:
2016-07-21 15:11:08 +02:00
```bash
mkdir -p /home/core/fabmanager/config/nginx/ssl
```
Run `openssl dhparam -out dhparam.pem 4096` in the folder /home/core/fabmanager/config/nginx/ssl (generate dhparam.pem file)
```bash
mkdir -p /home/core/fabmanager/letsencrypt/config/
```
Copy the previously customized `webroot.ini.example` as `/home/core/fabmanager/letsencrypt/config/webroot.ini`
```bash
mkdir -p /home/core/fabmanager/letsencrypt/etc/webrootauth
```
Run `docker pull quay.io/letsencrypt/letsencrypt:latest`
2017-07-20 16:48:34 +02:00
Create file (with sudo) /etc/systemd/system/letsencrypt.service and paste the following configuration into it:
2016-07-21 15:11:08 +02:00
```bash
[Unit]
Description=letsencrypt cert update oneshot
Requires=docker.service
[Service]
Type=oneshot
2016-12-01 12:01:44 +01:00
ExecStart=/usr/bin/docker run --rm --name letsencrypt -v "/home/core/fabmanager/log:/var/log/letsencrypt" -v "/home/core/fabmanager/letsencrypt/etc:/etc/letsencrypt" -v "/home/core/fabmanager/letsencrypt/config:/letsencrypt-config" quay.io/letsencrypt/letsencrypt:latest -c "/letsencrypt-config/webroot.ini" certonly
2016-11-30 21:48:46 +01:00
ExecStartPost=-/usr/bin/docker restart fabmanager_nginx_1
2016-07-21 15:11:08 +02:00
```
2017-07-20 16:48:34 +02:00
Create file (with sudo) /etc/systemd/system/letsencrypt.timer and paste the following configuration into it:
2016-07-21 15:11:08 +02:00
```bash
[Unit]
Description=letsencrypt oneshot timer
Requires=docker.service
[Timer]
OnCalendar=*-*-1 06:00:00
Persistent=true
Unit=letsencrypt.service
2016-11-30 21:48:46 +01:00
[Install]
WantedBy=timers.target
2016-07-21 15:11:08 +02:00
```
2017-07-20 16:48:34 +02:00
That's all for the moment. Keep on with the installation, we'll complete that part after deployment in the [Generate SSL certificate by Letsencrypt ](#generate-ssl-cert-letsencrypt ).
2016-03-23 18:39:41 +01:00
2017-07-20 16:48:34 +02:00
### Install docker-compose
2017-07-20 17:14:02 +02:00
< a id = "install-docker-compose" > < / a >
2016-03-23 18:39:41 +01:00
```bash
2017-07-20 16:48:34 +02:00
curl -L https://github.com/docker/compose/releases/download/1.7.1/docker-compose-`uname -s` -`uname -m` > ./docker-compose
sudo mkdir -p /opt/bin
sudo mv docker-compose /opt/bin/
sudo chmod +x /opt/bin/docker-compose
2016-03-23 18:39:41 +01:00
```
2017-07-20 16:48:34 +02:00
Then copy docker-compose.yml to your app folder `/home/core/fabmanager` .
2016-03-23 18:39:41 +01:00
2017-07-20 16:48:34 +02:00
## Deployment
2017-07-20 17:14:02 +02:00
< a id = "deployment" > < / a >
2016-03-23 18:39:41 +01:00
2017-07-20 16:48:34 +02:00
### pull images
2017-07-20 17:14:02 +02:00
< a id = "pull-images" > < / a >
2016-03-23 18:39:41 +01:00
```bash
2017-07-20 16:48:34 +02:00
docker-compose pull
2016-03-23 18:39:41 +01:00
```
2017-07-20 17:14:02 +02:00
### setup database
< a id = "setup-database" > < / a >
2016-03-23 18:39:41 +01:00
```bash
2017-07-20 16:48:34 +02:00
docker-compose run --rm fabmanager bundle exec rake db:create # create the database
docker-compose run --rm fabmanager bundle exec rake db:migrate # run all the migrations
docker-compose run --rm fabmanager bundle exec rake db:seed # seed the database
2016-03-23 18:39:41 +01:00
```
2017-07-20 16:48:34 +02:00
### build assets
2017-07-20 17:14:02 +02:00
< a id = "build-assets" > < / a >
2016-03-23 18:39:41 +01:00
2017-07-20 16:48:34 +02:00
`docker-compose run --rm fabmanager bundle exec rake assets:precompile`
2016-03-23 18:39:41 +01:00
2017-07-20 17:14:02 +02:00
### prepare Elasticsearch (search engine)
< a id = "prepare-elastic" > < / a >
2016-03-23 18:39:41 +01:00
2017-07-20 16:48:34 +02:00
`docker-compose run --rm fabmanager bundle exec rake fablab:es_build_stats`
2016-03-23 18:39:41 +01:00
2017-07-20 16:48:34 +02:00
#### start all services
2017-07-20 17:14:02 +02:00
< a id = "start-services" > < / a >
2016-03-23 18:39:41 +01:00
2017-07-20 16:48:34 +02:00
`docker-compose up -d`
2016-09-06 12:19:47 +02:00
2017-07-20 16:48:34 +02:00
### Generate SSL certificate by Letsencrypt
< a name = "generate-ssl-cert-letsencrypt" > < / a >
2016-03-23 18:39:41 +01:00
2017-07-20 16:48:34 +02:00
**Important: app must be run before starting letsencrypt**
2016-07-21 15:21:33 +02:00
2016-07-21 15:11:08 +02:00
Start letsencrypt service :
```bash
sudo systemctl start letsencrypt.service
```
2016-07-21 15:21:33 +02:00
2017-07-20 16:48:34 +02:00
If the certificate was successfully generated then update the nginx configuration file and activate the ssl port and certificate
editing the file `/home/core/fabmanager/config/nginx/fabmanager.conf` .
Remove your app container and run your app to apply the changes running the following commands:
```bash
docker-compose down
docker-compose up -d
```
2016-07-21 15:11:08 +02:00
Finally, if everything is ok, start letsencrypt timer to update the certificate every 1st of the month :
2016-07-21 15:21:33 +02:00
2016-07-21 15:11:08 +02:00
```bash
2016-11-30 21:48:46 +01:00
sudo systemctl enable letsencrypt.timer
2016-07-21 15:11:08 +02:00
sudo systemctl start letsencrypt.timer
2016-11-30 21:48:46 +01:00
(check) sudo systemctl list-timers
2016-07-21 15:11:08 +02:00
```
2017-07-20 16:48:34 +02:00
## Docker utils
2017-07-20 17:14:02 +02:00
< a id = "docker-utils" > < / a >
2016-03-23 18:39:41 +01:00
2017-07-20 16:48:34 +02:00
### Restart app
2016-04-11 20:24:09 +02:00
`docker restart fabmanager-app`
2017-07-20 16:48:34 +02:00
### Remove app
2016-04-11 20:24:09 +02:00
`docker rm -f fabmanager-app`
2017-07-20 16:48:34 +02:00
### Open a bash in the app context
2016-04-11 20:24:09 +02:00
`docker exec -it fabmanager-app bash`
2017-07-20 16:48:34 +02:00
### Show services status
2016-06-14 14:33:57 +02:00
2017-07-20 16:48:34 +02:00
`docker-compose ps`
2016-06-14 14:33:57 +02:00
2017-07-20 16:48:34 +02:00
### Restart all services
2016-06-14 14:33:57 +02:00
2017-07-20 16:48:34 +02:00
`docker-compose restart`
2016-06-14 14:33:57 +02:00
2017-07-20 17:14:02 +02:00
## Fabmanager update
< a id = "update-fabmanager" > < / a >
*This procedure updates fabmanager to the last version by default.*
### Steps
< a id = "update-steps" > < / a >
2016-06-14 14:33:57 +02:00
2017-07-20 16:48:34 +02:00
When a new version is available, this is how to update fabmanager app in a production environment, using docker-compose :
2016-06-14 14:33:57 +02:00
2017-07-20 17:14:02 +02:00
#### go to your app folder
2016-06-14 14:33:57 +02:00
2017-07-20 16:48:34 +02:00
`cd fabmananger`
2016-06-14 14:33:57 +02:00
2017-07-20 17:14:02 +02:00
#### pull last docker images
2016-06-14 14:33:57 +02:00
2017-07-20 16:48:34 +02:00
`docker-compose pull`
2016-07-21 15:21:33 +02:00
2017-07-20 17:14:02 +02:00
#### stop the app
2016-06-14 14:33:57 +02:00
2017-07-20 16:48:34 +02:00
`docker-compose stop fabmanager`
2016-06-14 14:33:57 +02:00
2017-07-20 17:14:02 +02:00
#### remove old assets
2016-06-14 14:33:57 +02:00
2017-07-20 16:48:34 +02:00
`sudo rm -Rf public/assets/`
2016-06-14 14:33:57 +02:00
2017-07-20 17:14:02 +02:00
#### compile new assets
2016-06-14 14:33:57 +02:00
`docker-compose run --rm fabmanager bundle exec rake assets:precompile`
2017-07-20 17:14:02 +02:00
#### run specific commands
2016-06-14 14:33:57 +02:00
2017-07-20 17:14:02 +02:00
Do not forget to check if there are commands to run for your upgrade. Those commands
2017-07-20 16:48:34 +02:00
are always specified in the [CHANGELOG ](https://github.com/LaCasemate/fab-manager/blob/master/CHANGELOG.md ) and prefixed by *[TODO DEPLOY]* .
They are also present in the [release pages ](https://github.com/LaCasemate/fab-manager/releases ).
2016-06-14 14:33:57 +02:00
2017-07-20 16:48:34 +02:00
They execute specific tasks so they can't be automatic and have to be run by hand.
2016-06-14 14:33:57 +02:00
2017-07-20 17:14:02 +02:00
#### restart all containers
2016-06-14 14:33:57 +02:00
2017-07-20 16:48:34 +02:00
```bash
docker-compose down
docker-compose up -d
```
2016-06-14 14:33:57 +02:00
2017-07-20 16:48:34 +02:00
You can check that all containers are running with `docker ps` .
2016-06-14 14:33:57 +02:00
2017-07-20 16:48:34 +02:00
### Good to know
2017-07-20 17:14:02 +02:00
< a id = "good-to-know" > < / a >
2016-06-14 14:33:57 +02:00
2017-07-20 16:48:34 +02:00
#### Is it possible to update several versions at the same time ?
2016-06-14 14:33:57 +02:00
2017-07-20 16:48:34 +02:00
Yes, indeed. It's the default behaviour as `docker-compose pull` command will fetch the latest versions of the docker images.
Be sure to run all the specific commands listed in the [CHANGELOG ](https://github.com/LaCasemate/fab-manager/blob/master/CHANGELOG.md ) between your actual
and the new version in sequential order. (Example: to update from 2.4.0 to 2.4.3, you will run the specific commands for the 2.4.1, then for the 2.4.2 and then for the 2.4.3).