Step 1: Create your Digital Ocean droplet
Make sure you add your SSH when creating digital ocean and do not add a paraphrase to your SSH. It doesn’t work with paraphrase.
Step 2: Setting up your server (DO droplet)
Log into your server.
|
|
Setup VIM as default editor on your server.
|
|
Make sure you select the /usr/bin/vim.basic
option which is number 3.
Update your locale.
|
|
Create new deploy user
The next step is to create a non-root user on the server which will own our application and handle deployments. We’ll configure the .ssh directory for the user, configure the user to have passwordless sudo access, and disabled password login to harden the server a bit.
Let’s create the user deploy
.
As root
on the target server:
|
|
Fill out the data as required. Like password.
Next, run this series of commands to configure the user’s .ssh
directory:
|
|
As root
on the target server:
|
|
Verify that password authentication is set to “no”:
|
|
Add deploy to sudoers
Finally we’ll add the user to sudo.
As root
on the target machine:
|
|
This will open the sudoers file where we can add the deploy
users privileges below root
like this:
|
|
Add ssh public key to authorized_keys
In another terminal window, on your local machine:
|
|
On the target server, paste the key into authorized_keys:
|
|
Now we can safely log in and work as the deploy
user on the target machine without having to enter a password.
Now go to Basic Hardening article to remove root
login.
Set up your firewall on Ubuntu
source/credit: https://www.digitalocean.com/community/tutorials/initial-server-setup-with-ubuntu-18-04
Ubuntu 18.04 servers can use the UFW firewall to make sure only connections to certain services are allowed. We can set up a basic firewall very easily using this application.
Different applications can register their profiles with UFW upon installation. These profiles allow UFW to manage these applications by name. OpenSSH, the service allowing us to connect to our server now, has a profile registered with UFW.
You can see this by typing:
|
|
Output:
|
|
We need to make sure that the firewall allows SSH connections so that we can log back in next time. We can allow these connections by typing:
|
|
Afterwards, we can enable the firewall by typing:
|
|
Type “y
” and press ENTER
to proceed. You can see that SSH connections are still allowed by typing:
|
|
Output:
|
|
As the firewall is currently blocking all connections except for SSH, if you install and configure additional services, you will need to adjust the firewall settings to allow acceptable traffic in. You can learn some common UFW operations in this guide.
Step 3: Target Server - Install asdf
Sometimes, you’ll need to install specific versions or Erlang, Elixir or Node, and we’ll use asdf, a version manager to tackle this complex task.
asdf
is an extendable version manager with support for Ruby, Node.js, Elixir, Erlang & more.
To install it, we’ll first switch over to our newly created deploy
user.
On the target server as root
:
|
|
Install asdf
Install dependencies:
|
|
Ensure that you are using the deploy account, and clone the repo:
|
|
After this you need to add asdf to your deploy
user bash profile:
|
|
Add this at the end of your profile:
|
|
Optional step if you are on $5 Digital Ocean Droplet
For $5 droplet, asdf only works if you create a swapspace (I set it to 4GB) and wait a bit for asdf to install and build erlang felt like 30 min. See solution: (https://www.digitalocean.com/community/tutorials/how-to-add-swap-space-on-ubuntu-18-04) See the problem reported: (https://github.com/asdf-vm/asdf-erlang/issues/91)
Switch to root to create swap space.
We can see if the system has any configured swap by typing:
|
|
You can verify that there is no active swap using the free
utility:
|
|
Create swap file.
The size of swap file is usually double your ram. But do 4G minimum.
|
|
We can verify that the correct amount of space was reserved by typing:
|
|
Enabling the swap file
Now that we have a file of the correct size available, we need to actually turn this into swap space.
First, we need to lock down the permissions of the file so that only the users with root
privileges can read the contents. This prevents normal users from being able to access the file, which would have significant security implications.
Make the file only accessible to root
by typing:
|
|
Verify the permissions change by typing:
|
|
As you can see, only the root
user has the read and write flags enabled.
We can now mark the file as swap space by typing:
|
|
Output:
|
|
After marking the file, we can enable the swap file, allowing our system to start utilizing it:
|
|
Verify that the swap is available by typing:
|
|
Making the swapfile permanent
Our recent changes have enabled the swap file for the current session. However, if we reboot, the server will not retain the swap settings automatically. We can change this by adding the swap file to our /etc/fstab
file.
Back up the /etc/fstab
file in case anything goes wrong:
|
|
Add the swap file information to the end of your /etc/fstab
file by typing:
|
|
Now switch to deploy user and check to see if asdf by typing asdf
.
Step 4: Target Server - Install Erlang/Elixir
Because we need our Phoenix project to run on both the local development machine and the production server, we’ll need to install the same languages and tools in both places. Erlang 21.1, and Elixir 1.7.4.
Install Erlang
We’re going to use asdf
to install Erlang. I uses plugins for different libraries, so let’s add the plugin:
As deploy
on the target machine:
|
|
Install Erlang/OTP 22 (or whichever version your app needs)
|
|
OPTIONAL If anything went wrong or if dependencies skipped
|
|
Install Elixir
As deploy
add the plugin:
|
|
Install Elixir and make it global:
|
|
Now you can open a new terminal and try erl
:
|
|
And you can try iex
:
|
|
Use asdf .tool-versions
file to manage which version is active on each of your projects.
Use Mix
to install Hex
.
|
|
Step 5: Target Server - Install Nodejs
Installing Node is straightforward with a few commands.
NOTE: Look up what NODE version to install. Replace XX with version number such as 12. see https://github.com/nodesource/distributions/blob/master/README.md
|
|
Step 6: Target Server - Install Postgresql
base on https://computingforgeeks.com/install-postgresql-11-on-ubuntu-18-04-ubuntu-16-04/
As root
on the target server:
Add PostgreSQL 11 APT repository (for Bionic 18.04 ubuntu)
https://www.postgresql.org/download/linux/ubuntu/
Create the file /etc/apt/sources.list.d/pgdg
list and add a line for the repository.
|
|
Add this line:
|
|
Import the repository signing key, and update the package lists :
|
|
Install PostgreSQL 11 on Ubuntu 18.04 / Ubuntu 16.04
After importing GPG key, add repository contents to your Ubuntu 18.04/16.04 system:
|
|
Verify repository file contents
|
|
Create new database user
During the postgres installation, a postgres root user postgres
was created, but we don’t want to connect to the server with this user. Let’s create a separate postgres user for our app.
You can switch to the postgres user with su postgres
than back to root with exit
On the target server, switch to the postgres
user, create a phx
database user and set the new user’s password:
|
|
NOTE: Remember these credentials as they’ll be used once we configure our Phoenix application for production.
Create production database:
We’ll need to create our production database manually as edeliver only manages migrations.
As postgres
on the target server:
|
|
Then log in to psql
:
|
|
Ensure that you are logged into the postgres cli tool and run:
|
|
This gives our new phx
user access to the newly created database. Exit psql with \q
.
Database credentials:
To re-cap:
- username:
phx
- password:
<yourpass>
- database:
fumigate_prod
Step 7: Target Server - Production Configuration
Create prod.secret.exs
You may have noticed that Phoenix created a config/prod.secret.exs
file. This is imported by config/prod.exs
but is ignored by git by default. We’ll need to create this file on the target machine so edeliver can symlink to it during the build process.
We’re also going to store our applications in ~/apps/<appname>
format which is the equivalent of /home/deploy/apps/<appname>
.
Let’s switch over to our deploy
user. On the target machine:
|
|
Make a new directory for our secrets:
|
|
Then create a new prod.secret.exs
file in that directory:
|
|
Add this content to it:
|
|
You can generate a new secret key by using mix phx.gen.secret
on your local machine.
IMPORTANT: Update the file to have a production ready secret key, and the database credentials you set from earlier.
Step 8: Install Distillery and edeliver
As previously mentioned, Distillery compiles our Phoenix application into releases, and edeliver uses ssh and scp to build and deploy the releases to our production server.
On your local machine, open mix.exs
and add 2 deps:
|
|
And add :edeliver
to extra_applications
in the application
block:
|
|
Use mix to install deps:
|
|
Initialize Distillery
Distillery requires a build configuration file that is not generated by default.
Let’s generate it with:
|
|
This generates configuration files for Distillery in the rel
directory. We don’t need to make any changes to the default config.
We now need to exclude .deliver/releases/
from our git repo.
|
|
Configure edeliver
Create a .deliver
directory in your project folder and add the config
file: (Change the IP to your server IP 134.209.8.141)
|
|
These are mostly environment variables use by Edeliver in the shell scripts. Go through them one by one and try to understand what they’re doing.
You can read more about the configuration variables in their Wiki.
Don’t forget to update your host configuration
The custom functions are hooks that run during different phases of the deployment.
You can also read more about running additional tasks in their Wiki.
Project prod configuration
We’ll need to make some changes to the default production configuration in our project.
DO NOT RUN ON PORT 80. KEEP IT AT 4000. The application is running on deploy there fore it cannot run on port 80. We need to route incoming requests from 80 http and https to port 4000. Do not attempt to run app as root. That’s asking for trouble. Source: https://elixirforum.com/t/running-on-ec2-giving-error/13574/5
Open config/prod.exs
and update it to this:
|
|
These are settings recommended by Distillery. You might notice that we’re setting the system port using the PORT
environment variable. This needs to be available during the build process and we can add it to the ~/.profile
file on our production server.
Add env Variables to Target Server
Login as deploy
to the target server.
Open up the .profile
.
|
|
And add these lines:
|
|
This will ensure that our system runs on port 4000, and that the environment is set to prod
.
Logout of deploy and log back in for ~/.profile
be in effect.
Step 9: Deployment
We’re finally ready to build and deploy our first release. The default version is 0.1.0
so let’s just keep that for now.
Warning: the commands for building and deploy can seem complicated at first but once you become familiar with them, you will see that they use a natural language style.
Build the production release:
NOTE: edeliver uses git master branch
to build the code into release package.
In your project directory and git master branch:
|
|
This builds the release on the target server, and stores the archive in your local .edeliver/releases
directory.
Deploy the reload to production:
In your project directory:
|
|
Other neat edeliver commands:
|
|
You can read more about Edeliver in their documentation.
View our website on our server
|
|
Step 10: Generating SSL CERT - BEFORE Routing incoming http request to port 4000 (our phoenix app)
https://github.com/certbot/certbot/issues/5257
We should generate SSL Certificate. The certbot generator needs port 80. So you need to do this before rerouting incoming port 80 requests to our phoenix web app that’s listening on port 4000.
Step 1 — Installing Certbot
The first step to using Let’s Encrypt to obtain an SSL certificate is to install the Certbot software on your server.
Certbot is in very active development, so the Certbot packages provided by Ubuntu tend to be outdated. However, the Certbot developers maintain a Ubuntu software repository with up-to-date versions, so we’ll use that repository instead.
First, add the repository:
|
|
Install certbot:
|
|
Step 2 — Generating Certificate
Make sure that your firewall is accepting port 80.
|
|
Generate the SSL cert:
|
|
Enable it so deploy user and app own by deploy can read those certs:
|
|
We’ll get back to using cert on the server soon in step 13.
Step 11: Routing incoming http request to port 4000 (our phoenix app)
https://serverfault.com/questions/238563/can-i-use-ufw-to-setup-a-port-forward
Let’s say you want to forward requests going to 80 (http) to a server listening on port 4000.
Note that you will need to make sure port 8080 is allowed, otherwise ufw will block the requests that are redirected to 4000.
|
|
There are no ufw commands for setting up the port forwards, so it must be done via configuraton files. Add the lines below to /etc/ufw/before.rules
, before the filter
section, right at the top of the file:
|
|
|
|
Then restart the server:
|
|
Enable ufw to start on boot:
|
|
Debug tips: check /var/log/syslog
Step 12: Fail2ban
https://www.lifewire.com/harden-ubuntu-server-security-4178243
https://www.techrepublic.com/article/how-to-install-fail2ban-on-ubuntu-server-18-04/
The fail2ban system is an intrusion prevention system that monitors log files and searches for particular patterns that correspond to a failed login attempt. If a certain number of failed logins are detected from a specific IP address (within a specified amount of time), fail2ban will block access from that IP address.
To install fail2ban, open a terminal window and issue the command:
|
|
Within the directory /etc/fail2ban
, you’ll find the main configuration file, jail.conf. Also in that directory is the subdirectory, jail.d. The jail.conf file is the main configuration file and jail.d contains the secondary configuration files. Do not edit the jail.conf file. Instead, we’ll create a new configuration that will monitor SSH logins with the command:
|
|
In this new file add the following contents:
|
|
This configuration does the following:
- Enables the jail.
- Sets the SSH port to be monitored to 22.
- Uses the sshd filter.
- Sets the log file to be monitored.
Save and close that file. Restart fail2ban with the command:
|
|
If you attempt to Secure Shell into that server and fail the log in three times (set as the default by fail2ban), access will be then blocked from the IP address you are working from.
Testing and unbanning
You can test to make sure the new jail works by failing three attempts at logging into the server, via ssh. After the third failed attempt, the connection will hang. Hit [Ctrl]+[c]
to escape and then attempt to SSH back into the server. You should no longer be able to SSH into that server from the IP address you were using.
You can then unban your test IP address with the following command:
|
|
where IP_ADDRESS
is the banned IP Address.
You should now be able to log back into the server with SSH.
Scratching the surface
This barely scratches the surface as to what fail2ban can do. But now you have a good idea on how to use the system. To find out more, make sure to read the man page with the command:
|
|
That manual page provides a good overview of what fail2ban can do.
Step 13: Port foward SSL to Port 4001
Set up the firewall:
|
|
There are no ufw commands for setting up the port forwards, so it must be done via configuraton files. Add the lines below to /etc/ufw/before.rules
, before the filter
section, right at the top of the file:
|
|
|
|
Then restart the server:
|
|
Step 14: SSL
https://blog.progressplum.app/ssl-migration-from-nginx-to-cowboy-2-in-phoenix-1-4/
https://medium.com/@zek/secure-your-phoenix-app-with-free-ssl-48ac749c17d7
Step 1 — Generating Diffie Hellman parameters
If you don’t already have a set of Diffie Hellman parameters[2] to use with your SSL, generate a new set for extra security. Run this command on the server but be aware that it’s very CPU-intensive and may take a while on a slow VPS.
|
|
Step 2 — Set up your environment
|
|
|
|
Change fumigatedb.com
to your domainname.
Step 3 — prod Configuration
Update your application’s Endpoint configuration to add SSL support in config/prod.exs
.
|
|
|
|
Save to git master repo and rerun edeliver again.
|
|
Check the ssl website now with: https://www.ssllabs.com/ssltest/
Step 4 — Application Configuration forcing SSL
|
|
Step 5 — Increasing the security of SSL
https://elixirforum.com/t/making-ssl-tests-all-pass-for-phoenix-lets-encrypt/3507/11
|
|
Credit
Base on these resources:
- https://devato.com/automate-elixir-phoenix-1-4-deployment-with-distillery-and-edeliver-on-ubuntu/#step-6-target-server-install-nodejs
- https://medium.com/@zek/deploy-early-and-often-deploying-phoenix-with-edeliver-and-distillery-part-one-5e91cac8d4bd
- https://medium.com/@zek/deploy-early-and-often-deploying-phoenix-with-edeliver-and-distillery-part-two-f361ef36aa10
- https://blog.progressplum.app/ssl-migration-from-nginx-to-cowboy-2-in-phoenix-1-4/
- https://elixirforum.com/t/elixir-1-9-releases-with-edeliver/23728/3?u=mythicalprogrammer
Pictures
- First picture: Color Phoenix Tradition