<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Cristian</title>
    <description>The latest articles on DEV Community by Cristian (@cristian).</description>
    <link>https://dev.to/cristian</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F88410%2Ff9e4efff-a002-4b6b-9269-b18050f76638.jpeg</url>
      <title>DEV Community: Cristian</title>
      <link>https://dev.to/cristian</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/cristian"/>
    <language>en</language>
    <item>
      <title>Meet Ruby!</title>
      <dc:creator>Cristian</dc:creator>
      <pubDate>Thu, 13 Aug 2020 15:09:57 +0000</pubDate>
      <link>https://dev.to/cristian/meet-ruby-50ii</link>
      <guid>https://dev.to/cristian/meet-ruby-50ii</guid>
      <description>&lt;p&gt;She's an 11 week old Golden Retriever!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PLVa7qtX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/wii5rg9x6zj5jfkzv4qq.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PLVa7qtX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/wii5rg9x6zj5jfkzv4qq.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--he76XLzx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/64c0jllwcff1zzf7fi1f.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--he76XLzx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/64c0jllwcff1zzf7fi1f.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eA5NhOVh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/m4k3cgr3zveisfnqay19.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eA5NhOVh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/m4k3cgr3zveisfnqay19.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>watercooler</category>
    </item>
    <item>
      <title>GitHub is down...again. How is your week going?</title>
      <dc:creator>Cristian</dc:creator>
      <pubDate>Thu, 23 Apr 2020 13:24:56 +0000</pubDate>
      <link>https://dev.to/cristian/github-is-down-again-how-is-your-week-going-136o</link>
      <guid>https://dev.to/cristian/github-is-down-again-how-is-your-week-going-136o</guid>
      <description></description>
      <category>watercooler</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Share your WFH setup!</title>
      <dc:creator>Cristian</dc:creator>
      <pubDate>Fri, 03 Apr 2020 15:26:41 +0000</pubDate>
      <link>https://dev.to/cristian/share-your-wfh-setup-o45</link>
      <guid>https://dev.to/cristian/share-your-wfh-setup-o45</guid>
      <description></description>
      <category>discuss</category>
      <category>workstations</category>
    </item>
    <item>
      <title>To cd or not to cd...in a shell script?</title>
      <dc:creator>Cristian</dc:creator>
      <pubDate>Tue, 18 Feb 2020 15:55:57 +0000</pubDate>
      <link>https://dev.to/cristian/to-cd-or-not-to-cd-in-a-shell-script-2pd6</link>
      <guid>https://dev.to/cristian/to-cd-or-not-to-cd-in-a-shell-script-2pd6</guid>
      <description>&lt;p&gt;In a few cases, I've noticed the use of &lt;code&gt;cd&lt;/code&gt; in shell scripts, and this practice never really made sense to me. It seems so broken to change the current working directory to perform a command in a given context, such as another directory. I think using &lt;code&gt;cd&lt;/code&gt; seems broken to me because it opens up the door that you might forget to &lt;code&gt;cd&lt;/code&gt; back to the original directory if needed.&lt;/p&gt;

&lt;p&gt;What do you think?&lt;/p&gt;

&lt;h2&gt;
  
  
  Bad?
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;

&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail

&lt;span class="nv"&gt;EASYRSA_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'/etc/openvpn/easy-rsa'&lt;/span&gt;

&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="nv"&gt;$EASYRSA_PATH&lt;/span&gt;

./easyrsa init-pki

&lt;span class="c"&gt;# other commands unrelated to EASYRSA_PATH&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Good?
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;

&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail

&lt;span class="nv"&gt;EASYRSA_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'/etc/openvpn/easy-rsa'&lt;/span&gt;

&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;EASYRSA_PATH&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/easyrsa"&lt;/span&gt; init-pki

&lt;span class="c"&gt;# other commands unrelated to EASYRSA_PATH&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>bash</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Practicing Safe S...hell</title>
      <dc:creator>Cristian</dc:creator>
      <pubDate>Tue, 18 Feb 2020 00:38:26 +0000</pubDate>
      <link>https://dev.to/cristian/practicing-safe-s-hell-3im8</link>
      <guid>https://dev.to/cristian/practicing-safe-s-hell-3im8</guid>
      <description>&lt;p&gt;While creating &lt;a href="https://github.com/cristian-rivera/skyhole"&gt;SkyHole&lt;/a&gt;, I found myself writing a few shell scripts. They get the job done, and although I could have written them in a language such as Ruby or Python, it's a safe bet to make that any UNIX machine that execute these scripts have a shell.&lt;/p&gt;

&lt;p&gt;As I was writing these scripts, it became clear that out of the box, a shell script doesn't have the niceties that you might expect when coming from another language. Things such as &lt;strong&gt;the script exploding when a variable isn't defined&lt;/strong&gt; or &lt;strong&gt;the script exiting when a step in the function has failed&lt;/strong&gt; aren't handled normally in a shell script. The purpose of this post is to share a few tricks to make scripting in a shell a bit safer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Have a shebang
&lt;/h2&gt;

&lt;p&gt;Not every machine a script runs on might have an up to date version of &lt;code&gt;bash&lt;/code&gt; at &lt;code&gt;/bin/bash&lt;/code&gt;. For example, macOS ships with an old version on this path.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Set the exception parameter
&lt;/h2&gt;

&lt;p&gt;If a script fails at a certain point, what would you like to happen? Most of the time, you want it to stop and not continue because the rest of the script might depend on that command to succeed. You can tell the shell to exit if anything throws an error immediately, and therefore the rest of the script won't continue running.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to take this a step further, you can add &lt;code&gt;-o pipefail&lt;/code&gt;, which protects against any failure anywhere in a pipeline, rather than just the last command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-eo&lt;/span&gt; pipefail
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Set the undefined parameter
&lt;/h2&gt;

&lt;p&gt;A script might rely on user input or data from another source to run correctly. What happens when that data is empty, and a variable never gets set? Nothing. The script will continue and fail only when an empty input is invalid for that command. What about when you interpolate a path? For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;USER_FOLDER&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What's going to happen here if the variable &lt;code&gt;USER_FOLDER&lt;/code&gt; is never set? You guessed it; the shell will interpret that command as &lt;code&gt;rm -rf "/"&lt;/code&gt;. That would not be very good. You can prevent this from happening by adding the following to the top of your scripts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;What does this look like all together? I always add these two lines to the top of every shell script I write.&lt;/p&gt;

&lt;p&gt;Hint: you can combine multiple &lt;code&gt;set&lt;/code&gt; parameters.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;

&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check out &lt;a href="https://blog.yossarian.net/2020/01/23/Anybody-can-write-good-bash-with-a-little-effort"&gt;Anybody can write good bash (with a little effort)&lt;/a&gt; for more tips and tricks when scripting in shell. It was the inspiration for this post.&lt;/p&gt;

</description>
      <category>linux</category>
      <category>bash</category>
    </item>
    <item>
      <title>How do you maintain your security and privacy?</title>
      <dc:creator>Cristian</dc:creator>
      <pubDate>Thu, 13 Feb 2020 19:03:23 +0000</pubDate>
      <link>https://dev.to/cristian/how-do-you-maintain-your-security-and-privacy-1b02</link>
      <guid>https://dev.to/cristian/how-do-you-maintain-your-security-and-privacy-1b02</guid>
      <description>&lt;p&gt;macOS&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://brave.com/"&gt;Brave Browser&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://openvpn.net/"&gt;OpenVPN&lt;/a&gt; via &lt;a href="https://github.com/cristian-rivera/skyhole"&gt;SkyHole&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pi-hole.net/"&gt;Pi-hole&lt;/a&gt; via &lt;a href="https://github.com/cristian-rivera/skyhole"&gt;SkyHole&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://1password.com/"&gt;1Password&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gpgtools.org/"&gt;GPG Suite&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/drduh/macOS-Security-and-Privacy-Guide"&gt;macOS-Security-and-Privacy-Guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;iOS&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://openvpn.net/"&gt;OpenVPN&lt;/a&gt; via &lt;a href="https://github.com/cristian-rivera/skyhole"&gt;SkyHole&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pi-hole.net/"&gt;Pi-hole&lt;/a&gt; via &lt;a href="https://github.com/cristian-rivera/skyhole"&gt;SkyHole&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://1password.com/"&gt;1Password&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Brave Browser
&lt;/h2&gt;

&lt;p&gt;I recently started using Brave as my daily browser, and I couldn't be happier. I was using the latest Firefox but noticed a few websites didn't render correctly. Brave is built on Chromium and is Chrome without Google plus more security features built right in. The best part is, all of your existing Chrome extensions will continue to work in Brave.&lt;/p&gt;

&lt;h2&gt;
  
  
  OpenVPN and Pi-hole
&lt;/h2&gt;

&lt;p&gt;I recently wrote a post regarding OpenVPN and Pi-hole. More information on both of these great projects can be found &lt;a href="https://dev.to/cristianrivera/skyhole-privacy-in-a-digital-age-ak2"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  1Password
&lt;/h2&gt;

&lt;p&gt;I'm not sure what I would do if I never found 1Password. It's a password manager loaded with features, and they have a ton of &lt;a href="https://support.1password.com/1password-security/"&gt;information&lt;/a&gt; related to the security practices they employ. Fast forward a few years, and now all of my login passwords are unique and consist of 64 alphanumeric characters, including symbols. It even supports two-factor authentication out of the box.&lt;/p&gt;

&lt;h2&gt;
  
  
  GPG Suite
&lt;/h2&gt;

&lt;p&gt;Granted, I don't use GPG to its full potential, but it doesn't hurt. Public/Private key cryptography is very popular. At the moment, I sign all of my Git commits and emails using GPG so their authenticity can be validated at any point in the future. Public-key cryptography is a method that I want to utilize more in the future.&lt;/p&gt;

&lt;h2&gt;
  
  
  macOS-Security-and-Privacy-Guide
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/drduh"&gt;drduh&lt;/a&gt; has compiled a vast collection of techniques for improving the security and privacy of a modern Apple Macintosh computer. Many of the methods are extreme and require quite a bit of technical know how but many are painless to implement and go a long way.&lt;/p&gt;

</description>
      <category>security</category>
      <category>privacy</category>
      <category>discuss</category>
    </item>
    <item>
      <title>SkyHole: Privacy In A Digital Age</title>
      <dc:creator>Cristian</dc:creator>
      <pubDate>Thu, 13 Feb 2020 15:08:48 +0000</pubDate>
      <link>https://dev.to/cristian/skyhole-privacy-in-a-digital-age-ak2</link>
      <guid>https://dev.to/cristian/skyhole-privacy-in-a-digital-age-ak2</guid>
      <description>&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;First and foremost, this post is not a guide explaining how to shield your online identity to engage in illegal activity.&lt;/p&gt;

&lt;p&gt;The dictionary definition of privacy is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;the state or condition of being free from being observed or disturbed by other people. E.g. "she returned to the privacy of her own home."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When people think about privacy, they think of things such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Closing the blinds in their home at night&lt;/li&gt;
&lt;li&gt;The right to enjoy time alone without intrusion&lt;/li&gt;
&lt;li&gt;Whispering when talking about something sensitive&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The examples above are only related to your personal space. We live in a digital age, where we increasingly share our lives on the internet. If you treat your personal space with such methods of privacy, why shouldn't you manage your online presence with the same effort? No one knows yourself better than you and your smartphone. In some cases, it's easier for someone to intrude on your privacy online than it is physically.&lt;/p&gt;

&lt;p&gt;As a software engineer, I like to think that I have a firm grasp of the reach the internet has on my privacy. To protect against that, I put specific practices in place to better safeguard and maintain my privacy. The problem is, not everyone is tech-savvy to the point where they can put in place the same measures with ease.&lt;/p&gt;

&lt;p&gt;There are many services where anyone can sign up and download an application that masks their internet traffic. The problem is that some of those services don't have the best track records, and their implementation is often private (go figure). The technology I'm referring to is a VPN or Virtual Private Network. In short, a VPN creates a tunnel from your device to a server on the internet. When configured correctly, nobody in-between you and the server can see your internet traffic.&lt;/p&gt;

&lt;p&gt;A VPN is useful when you want to protect yourself from:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Public WiFi hotspots&lt;/li&gt;
&lt;li&gt;Internet Service Providers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A VPN doesn't/shouldn't do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Safeguard you when engaging in illegal activity&lt;/li&gt;
&lt;li&gt;Natively block access to trackers or analytics services&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Fun Part
&lt;/h2&gt;

&lt;p&gt;Now that you know what this post is centered around (VPNs), let's see how easy it is to set one up. The most popular VPN software is &lt;a href="https://openvpn.net/"&gt;OpenVPN&lt;/a&gt;. It's open-source, which allows the code to be tested and verified to work correctly.&lt;/p&gt;

&lt;p&gt;The easiest and most straightforward way to set up your own OpenVPN server on AWS is by launching a preconfigured solution from the &lt;a href="https://aws.amazon.com/marketplace/seller-profile/ref=srh_res_product_vendor?ie=UTF8&amp;amp;id=aac3a8a3-2823-483c-b5aa-60022894b89d"&gt;AWS Marketplace&lt;/a&gt;. Preconfigured solutions are also available for Azure, DigitalOcean, or Google Cloud and, while easy to set up, they lack in terms of default security settings and customizability. A lot of magic happens to spin these solutions up, and when it comes to security, this is often not considered a best practice.&lt;/p&gt;

&lt;p&gt;The most difficult and least straightforward way to set up your own OpenVPN server on AWS is by provisioning a fresh flavor of Linux on an EC2 instance of your choice. We haven't begun the OpenVPN installation process, and we already have to think about things such as OS and hardware requirements. Once you settle on a desired EC2 configuration, you can install OpenVPN using various Linux packages. In the case of &lt;a href="https://ubuntu.com/"&gt;Ubuntu&lt;/a&gt;, something as simple as &lt;code&gt;apt -y install openvpn&lt;/code&gt; would work. The &lt;a href="https://openvpn.net/community-resources/how-to/"&gt;OpenVPN Community&lt;/a&gt; contains full step-by-step instructions.&lt;/p&gt;

&lt;p&gt;Once you've completed either form of getting OpenVPN up and running, you can enjoy many of the benefits that a VPN provides, such as the ones listed earlier. There's one issue, while you're more protected on public WiFi networks, and ISPs can't see your traffic anymore; trackers and analytics services are still using your new VPN IP address to target you. Wouldn't it be great if there was an open-source solution for this too? Luckily for you, there is, and it's called Pi-hole.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pi-hole.net/"&gt;Pi-hole&lt;/a&gt; considers itself as a black hole for advertisements and trackers. Its goal is to act as your primary DNS server and filter all queries while only letting the good ones through to real DNS servers. The bad queries are DNS lookups for advertising or tracking services such as Google or Facebook. Pi-hole was initially developed to run on a &lt;a href="https://www.raspberrypi.org/"&gt;Raspberry Pi&lt;/a&gt; since that would allow you to attach it to your local network and have your modem route all DNS traffic through it. Then your Kindle, Apple Watch, FireTV, and even your WiFi connected coffee maker would pass through Pi-hole without ever knowing it. Once a DNS request comes into Pi-hole for an advertiser such as Google, Pi-hole will recognize it based on Whitelists or Blacklists and either allow it through to upstream DNS servers or block it. If Pi-hole blocks it, the device that requested it thinks Google is offline and doesn't track or show you the advertisement.&lt;/p&gt;

&lt;p&gt;I know what you're thinking, this is so cool, can I use OpenVPN to secure my traffic and Pi-hole to filter it? You're in luck again. Although these two projects are entirely separate from each other, they can be used in tandem. You can spin up another EC2 instance alongside OpenVPN and install Pi-hole on it. Once completed, update your OpenVPN config to tell all of its clients to use the new Pi-hole server as the default DNS server. It just so happens that Pi-hole has some &lt;a href="https://docs.pi-hole.net/guides/vpn/setup-openvpn-server/"&gt;documentation&lt;/a&gt; on how to go about this. Though the documentation is a great start, it leaves some questions unanswered and assumes your configuration matches theirs.&lt;/p&gt;

&lt;p&gt;If only there were an open-source configuration that setups up OpenVPN and Pi-hole on AWS. It would be even better if it also set up the networking components required for OpenVPN and Pi-hole to work together seamlessly. Well, you're in luck. I felt that security and privacy online should be easy to obtain. Yet, there are so many guides and methods for achieving it that most people get lost and either make mistakes or give up in frustration. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/cristian-rivera/skyhole"&gt;SkyHole&lt;/a&gt; is an open-source Terraform configuration that will install and configure OpenVPN, Pi-hole, all networking components and leave you with a &lt;code&gt;client.ovpn&lt;/code&gt; file. This file can be imported into any compatible OpenVPN client and used to connect to the VPN instantly. The configuration also contains the required setup for OpenVPN to use Pi-hole.&lt;/p&gt;

&lt;p&gt;SkyHole is very opinionated. It's in the early stages of development and has a long way to come, but it works, and it works pretty well. Most of the default OpenVPN settings are replaced with hardened choices. I would greatly appreciate any contributions to the project in the form of suggesting or adding new features, writing, clarifying, or fixing documentation and reporting or fixing bugs. The best part of open-source is anyone can learn from everyone. I hope this project serves as an excellent resource for anyone to take their security and privacy into their own hands.&lt;/p&gt;

&lt;p&gt;Lastly, you might think this sounds expensive, but SkyHole uses two of the smallest EC2 instances, which comes out to about $8 a month. Roughly the same amount that other 3rd party VPN services cost, but now you are in full control of the entire VPN implementation.&lt;/p&gt;

&lt;p&gt;Enjoy! &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/cristian-rivera/skyhole"&gt;SkyHole&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Stay tuned for other posts involving device security and simple things you can do to shield yourself in this digital age.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>privacy</category>
      <category>security</category>
      <category>aws</category>
    </item>
    <item>
      <title>How did we upgrade and containerize our largest Rails monolith in one quarter?</title>
      <dc:creator>Cristian</dc:creator>
      <pubDate>Wed, 13 Nov 2019 18:19:43 +0000</pubDate>
      <link>https://dev.to/cristian/how-did-we-upgrade-and-containerize-our-largest-rails-monolith-in-one-quarter-part-1-3mki</link>
      <guid>https://dev.to/cristian/how-did-we-upgrade-and-containerize-our-largest-rails-monolith-in-one-quarter-part-1-3mki</guid>
      <description>&lt;h2&gt;
  
  
  Early days
&lt;/h2&gt;

&lt;p&gt;In the early days, we built &lt;a href="https://aircall.io/"&gt;Aircall&lt;/a&gt; with a single Ruby on Rails app. Using Rails was great because we were able to bootstrap the development process. Besides, it helped us focus on reiterating until we landed upon a market fit. Though, as we grew, it was clear this app was becoming too big, so we split it into four Ruby on Rails apps.&lt;/p&gt;

&lt;p&gt;The first of the four apps contained most of the product, such as user accounts, number settings, and both the internal/public API. The second contained all logic used to connect Aircall to custom integrations such as Salesforce and Zendesk. The third handled all real-time call logic, such as routing and conferences. Lastly, the fourth handled all billing related tasks such as processing payments and generating invoices.&lt;/p&gt;

&lt;p&gt;While this helped our engineering team manage different parts of the product in a more organized manner, the main app containing most of the product continued to grow. Also, we were using AWS Elastic Beanstalk to host these applications since it allowed us to build our infrastructure and serve our customers quickly but would later prove to be a major pain point in our CI pipeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  Now
&lt;/h2&gt;

&lt;p&gt;Fast forward a few short years, we now have a rapidly growing engineering team with an elaborate fleet of containerized microservices. That being said, at the heart of it all is still our very first Ruby on Rails app. Granted, the responsibility of this app has significantly diminished over the years, but it still serves an essential role within our company being the single source of truth for most of our data.&lt;/p&gt;

&lt;p&gt;During Q2 of 2019, we decided to show a little love to this app, which for the rest of this post, we'll call &lt;em&gt;Web&lt;/em&gt;. Web was running Rails 4.2 on Elastic Beanstalk. Rails 6 was on the horizon, and many of our other applications were already running in Docker containers on ECS, so it was logical to upgrade Web to a newer Rails version and containerize it. Though this process is much easier said than done, we managed to achieve this in just a single quarter.&lt;/p&gt;

&lt;h2&gt;
  
  
  Upgrading Rails from 4.2 to 5.2
&lt;/h2&gt;

&lt;p&gt;It was the second to last day of Rails Conf 2019 where I was sitting in on a talk given by Eileen M. Uchitelle, a Software Engineer at GitHub and a member of the Rails Core Team. Her talk highlighted how GitHub managed to upgrade both Ruby and Rails. If they managed to upgrade from Rails 2.3 to 5.2 and ditch their custom fork of Ruby while maintaining uptime, why couldn't we do the same? I mean, we were only going from Rails 4.2 to 5.2, so this should be a piece of cake. I was wrong. Here's what we learned and how we did it.&lt;/p&gt;

&lt;p&gt;We decided early on that those who managed the Rails upgrade would continuously merge &lt;strong&gt;master&lt;/strong&gt; into the &lt;strong&gt;feat/upgrade-rails&lt;/strong&gt; branch and retroactively fix any deprecation issues as we progressed. This process left us with our &lt;strong&gt;master&lt;/strong&gt; branch running Rails 4.2 and a &lt;strong&gt;feat/upgrade-rails&lt;/strong&gt; branch running Rails 5.2. Next came the fun part, fixing all deprecation warnings, and since we went straight to Rails 5.2, they were mostly exceptions instead of warnings.&lt;/p&gt;

&lt;p&gt;It's worth it to note that it isn't recommended to skip versions and is suggested to first begin with 5.0, then 5.1, and finally 5.2. Ultimately, we decided on jumping straight to 5.2 because it would help us smoke test problems quicker and saved us from having to scrub test logs for deprecation warnings.&lt;/p&gt;

&lt;p&gt;There are many changes from Rails 4.2 to 5.2, some breaking and some not. Below are the ones we think are the most important and the steps needed to upgrade&lt;/p&gt;

&lt;h3&gt;
  
  
  Ruby
&lt;/h3&gt;

&lt;p&gt;Rails 5 requires a minimum of Ruby 2.2.2 or later. If you're using &lt;code&gt;rvm&lt;/code&gt;, &lt;code&gt;rbenv&lt;/code&gt;, or &lt;code&gt;asdf&lt;/code&gt;, this should be as simple as running the following commands from your shell.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rvm &lt;span class="nb"&gt;install &lt;/span&gt;2.2.2

rbenv &lt;span class="nb"&gt;install &lt;/span&gt;2.2.2

asdf &lt;span class="nb"&gt;install &lt;/span&gt;ruby 2.2.2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Dependencies
&lt;/h3&gt;

&lt;p&gt;Dependencies in your Gemfile might not be compatible with newer versions of Rails. I suggest locking your Rails version in your Gemfile on a newer version: &lt;code&gt;gem 'rails', '~&amp;gt; 5.2'&lt;/code&gt;. Then run &lt;code&gt;bundle update rails&lt;/code&gt; while incrementally bumping conflicting gems until you get a successful bundle.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuration
&lt;/h3&gt;

&lt;p&gt;After you’ve achieved a successful bundle, run &lt;code&gt;rails app:update&lt;/code&gt; to interactively upgrade configuration files in &lt;code&gt;bin/&lt;/code&gt; and &lt;code&gt;/config&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Schema
&lt;/h3&gt;

&lt;p&gt;Unique and foreign indexes now live inside the &lt;code&gt;create_table&lt;/code&gt; method. Running &lt;code&gt;rails db:migrate&lt;/code&gt; generates a new &lt;code&gt;db/schema.rb&lt;/code&gt; file with these changes regardless of whether or not you have any pending migrations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Migrations
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;ActiveRecord&lt;/code&gt; migration files need to be tagged with the version of Rails in which they were generated. &lt;code&gt;CreateCalls &amp;lt; ActiveRecord::Migration&lt;/code&gt; now becomes &lt;code&gt;CreateCalls &amp;lt; ActiveRecord::Migration[4.2]&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CreateCalls&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Migration&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;4.2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;change&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ActionController
&lt;/h3&gt;

&lt;p&gt;Strong parameters have replaced protected attributes. If you’ve been using strong parameters already, then this shouldn’t cause problems. It’s important to note &lt;code&gt;ActionController::Parameters&lt;/code&gt; now returns an &lt;code&gt;Object&lt;/code&gt; instead of a &lt;code&gt;Hash&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To access the raw parameters as a &lt;code&gt;Hash&lt;/code&gt;, you can add &lt;code&gt;#to_h&lt;/code&gt; to the &lt;code&gt;Object&lt;/code&gt;: &lt;code&gt;params.to_h&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;permit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:per_page&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to_h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reverse_merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;page: &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;per_page: &lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ActiveRecord
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;ActiveRecord&lt;/code&gt; models now inherit from &lt;code&gt;ApplicationRecord&lt;/code&gt; instead of &lt;code&gt;ActiveRecord::Base&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# app/models/application_record.rb&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ApplicationRecord&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abstract_class&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# app/models/call.rb&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Call&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="n"&gt;belongs_to&lt;/span&gt; &lt;span class="ss"&gt;:number&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;belongs_to&lt;/code&gt; associations are required by default, and the use of &lt;code&gt;required: true&lt;/code&gt; in &lt;code&gt;belongs_to :company, required: true&lt;/code&gt; has now been replaced by &lt;code&gt;optional: false&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# app/models/call.rb&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Call&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="n"&gt;belongs_to&lt;/span&gt; &lt;span class="ss"&gt;:number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;optional: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;ActiveRecord&lt;/code&gt; and &lt;code&gt;ActiveModel&lt;/code&gt; callbacks no longer halt when returning &lt;code&gt;false&lt;/code&gt;. You need to use &lt;code&gt;throw(:abort)&lt;/code&gt; instead.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="n"&gt;before_create&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="kp"&gt;throw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:abort&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;you_need_to_stop_creation&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Tests
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;ActionController::TestCase&lt;/code&gt; now only accepts keyword arguments. Inside your specs, &lt;code&gt;get :show, id: 1&lt;/code&gt; becomes &lt;code&gt;get :show, params: { id: 1 }&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What didn’t work?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Tests
&lt;/h3&gt;

&lt;p&gt;As mentioned, Web has been around for a while, and many hands have touched it over the years. In any codebase, things could get out of hand, and we knew some parts might not have extensive tests in place. This lack of tests caused some issues because once we got the existing RSpec suite green, we still knew some things might not work as a result of the upgrade.&lt;/p&gt;

&lt;p&gt;At this point, we had two solutions. First, manually testing the product and trying to reproduce any edge cases that came to mind. Second, deploying the upgraded app to only a percentage of our production traffic and acting fast to patch issues. Smoke testing this way was not an ideal situation, but it worked for us and kept our uptime at 99.99%.&lt;/p&gt;

&lt;p&gt;To prevent this from happening in the future, we’ve stressed importance on code coverage within our engineering team. &lt;a href="https://github.com/colszowka/simplecov"&gt;Simplecov&lt;/a&gt; is excellent for this and is now a part of our CI pipeline, calculating test coverage for every branch of Web, seamlessly. I’ll be releasing a blog post in the coming weeks showing how we aggregate code coverage across multiple CPU cores and containers on CircleCI to produce a single report.&lt;/p&gt;

&lt;h3&gt;
  
  
  Communication
&lt;/h3&gt;

&lt;p&gt;Besides testing, communication is essential when executing a migration of this scale. To sum it up, communication was good, not great. We’re a multinational engineering team with 10 engineers in NYC and 50 in Paris. In retrospect, a project of this scale is better suited for the team with the largest amount of engineers, but the NYC team handled it instead, given the availability of resources at the time.&lt;/p&gt;

&lt;p&gt;Failure of communication became apparent as the Paris team would leave for the day while the NYC team would arrive and work vigorously on the upgrade. Shortly after that, as the NYC team went home, the Paris team would arrive back the next day and occasionally be faced with an unstable staging environment. Since Web is at the core of our ecosystem, an unstable environment hindered the development of some projects. In most cases, the unstable portions were those in which there were no tests. You could say this was beneficial because it allowed us to spot issues before they reached our customers. At the same time, the Paris team was not familiar with the procedures or status of the upgrade and often had to troubleshoot in the dark until the NYC team arrived. To make matters worse, in some cases, the Paris team didn’t know if an issue was related to their project or the upgrade of Web.&lt;/p&gt;

&lt;p&gt;This upgrade quickly pointed out an area in which we needed to improve on as a team. Additionally, we think when undertaking an upgrade of this scale, you need to make sure all engineering teams are looped in on every aspect, regardless of location or perceived interactions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;All in all, this project was a success. Our legacy monolith is now ready to run another few years while we continue to grow. We learned a lot and continue to apply our findings to every new project here at Aircall. This upgrade wasn’t easy, but it was worth it. Now we can better serve our customers by releasing new features and bug fixes quicker than ever, thanks to our improved CI pipeline.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>aws</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
