<?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: Thien DX</title>
    <description>The latest articles on DEV Community by Thien DX (@tdx).</description>
    <link>https://dev.to/tdx</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%2F454895%2F773ec96c-b53c-4380-8ea0-4603aa1233eb.jpeg</url>
      <title>DEV Community: Thien DX</title>
      <link>https://dev.to/tdx</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tdx"/>
    <language>en</language>
    <item>
      <title>BookmarkStart: A Minimal New Tab Extension for Organized Bookmarks</title>
      <dc:creator>Thien DX</dc:creator>
      <pubDate>Thu, 11 Dec 2025 16:27:04 +0000</pubDate>
      <link>https://dev.to/tdx/bookmarkstart-a-minimal-new-tab-extension-for-organized-bookmarks-d8e</link>
      <guid>https://dev.to/tdx/bookmarkstart-a-minimal-new-tab-extension-for-organized-bookmarks-d8e</guid>
      <description>&lt;p&gt;TL;DR, here's my extension :&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;👉 &lt;a href="https://chromewebstore.google.com/detail/jhkoppngfkhpakiejcdkcefkfldpgpdo?utm_source=item-share-cb" rel="noopener noreferrer"&gt;Install BookmarkStart &lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Why I Built My Own New Tab Extension?
&lt;/h3&gt;

&lt;p&gt;I wanted something simple: a clean view of my bookmarks in new tab page, organized the way I like them.&lt;/p&gt;

&lt;p&gt;I tried a lot of existing extensions. Some were beautiful but too cluttered with "features" (widgets, news feeds, ads). Others were simple but looked like they hadn't been updated since 2010.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxjvemi4c0vbt8xwjnl1v.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxjvemi4c0vbt8xwjnl1v.gif" alt="Me trying to find a decent new tab extension" width="480" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;None of them gave me the right balance of a modern look with zero distractions. So, I decided to build my own.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Result: BookmarkStart 🚀
&lt;/h2&gt;

&lt;p&gt;It's a Chrome New Tab extension that does one thing really well: organizing your bookmarks in new tab page.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Features ✨
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;🎨 It's just clean&lt;/strong&gt;: No clutter with tons of features. Just your links (and a clock).&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;🛠️ Customizable&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Dark/Light Mode&lt;/strong&gt; &lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Compact Mode&lt;/strong&gt; &lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Alignment&lt;/strong&gt;: Center, left, or right.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  &lt;strong&gt;🔒 Privacy&lt;/strong&gt;: Zero tracking (because why?)&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  See it in Action
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5lgh451vgq0908zpx0ud.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5lgh451vgq0908zpx0ud.png" alt="BookmarkStart Dark Mode screenshot" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzo9kxi1ngxr4ni91rt0p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzo9kxi1ngxr4ni91rt0p.png" alt="BookmarkStart Light Mode screenshot" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you're looking for a New Tab page that respects your time and looks great, give BookmarkStart a try!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;👉 &lt;a href="https://chromewebstore.google.com/detail/jhkoppngfkhpakiejcdkcefkfldpgpdo?utm_source=item-share-cb" rel="noopener noreferrer"&gt;Install BookmarkStart &lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I know there are other New Tab extensions out there, and many of them are great. But I wanted to give it a try and build something that felt right for me (and hopefully you). Sometimes, you just catch yourself thinking "I can make this myself".&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>tooling</category>
      <category>extensions</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Some mistakes you may make in PHP</title>
      <dc:creator>Thien DX</dc:creator>
      <pubDate>Fri, 30 Apr 2021 10:20:01 +0000</pubDate>
      <link>https://dev.to/tdx/some-mistakes-you-may-make-in-php-3ld1</link>
      <guid>https://dev.to/tdx/some-mistakes-you-may-make-in-php-3ld1</guid>
      <description>&lt;p&gt;Fast, flexible and pragmatic, PHP powers everything from your blog to the most popular websites in the world. Still during my work, I found it can have tricky behaviors that you may not aware of (yet) and create bugs in your code. &lt;br&gt;
Here are some of the most common mistakes I encountered :&lt;/p&gt;
&lt;h2&gt;
  
  
  array_merge
&lt;/h2&gt;

&lt;p&gt;Syntax : &lt;em&gt;array_merge ( array ...$arrays ) : array&lt;/em&gt;&lt;br&gt;
The function simply merges the elements of arrays together. But it also &lt;strong&gt;reset&lt;/strong&gt; the keys of elements if it's numeric. &lt;br&gt;
For example, a very basic use-case where you have arrays storing &lt;code&gt;[UserId =&amp;gt; UserName]&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$userArr1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"John"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"3"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"Mary"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="nv"&gt;$userArr2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"Ted"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"22"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"Doe"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;


&lt;span class="nv"&gt;$allUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;array_merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$userArr1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$userArr2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// $allUser will be&lt;/span&gt;
&lt;span class="c1"&gt;// Array&lt;/span&gt;
&lt;span class="c1"&gt;// (&lt;/span&gt;
&lt;span class="c1"&gt;//    [0] =&amp;gt; John&lt;/span&gt;
&lt;span class="c1"&gt;//    [1] =&amp;gt; Mary&lt;/span&gt;
&lt;span class="c1"&gt;//    [2] =&amp;gt; Ted&lt;/span&gt;
&lt;span class="c1"&gt;//    [3] =&amp;gt; Doe&lt;/span&gt;
&lt;span class="c1"&gt;// )&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Casting the numeric value to string like (string)10 won't work. This behavior is same for &lt;code&gt;array_merge_recursive()&lt;/code&gt;, so you should keep this in mind when calling these functions.&lt;/p&gt;

&lt;h2&gt;
  
  
  empty
&lt;/h2&gt;

&lt;p&gt;Syntax : &lt;em&gt;empty ( mixed $var ) : bool&lt;/em&gt;&lt;br&gt;
This check whether a variable is empty. Many use this function to check whether a key is set in array. It's all good and simple until value 0 came in.&lt;br&gt;
For example, an user submit formed validation code :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Function to check all required field are provided by user&lt;/span&gt;
&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;checkRequiredFields&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$requiredField&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'age'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'number_of_kids'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; 
    &lt;span class="nv"&gt;$errors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$requiredField&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$field&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$input&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$field&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="nv"&gt;$errors&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$field&lt;/span&gt;&lt;span class="s2"&gt; is missing"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$errors&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// A valid use-case in real likfe&lt;/span&gt;
&lt;span class="nv"&gt;$userData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'John'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'age'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'number_of_kids'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="nv"&gt;$inputError&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;checkRequiredFields&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$userData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// This return "number_of_kids is missing"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is because 0 is also considered as "empty" even though it's a valid response in many use-cases. I find people make this mistake mostly when validating user's input.&lt;br&gt;
A work around is adding &lt;code&gt;strlen($var)&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$input&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$field&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;strlen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$input&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$field&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Ternary operator (?:) vs null coalescing operator (??)
&lt;/h2&gt;

&lt;p&gt;When your first argument is null, they're basically the same&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="s1"&gt;'default'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// default&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt; &lt;span class="o"&gt;?:&lt;/span&gt; &lt;span class="s1"&gt;'default'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// default&lt;/span&gt;

&lt;span class="nv"&gt;$b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'a'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="nv"&gt;$b&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'a'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="s1"&gt;'default'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// default&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="nv"&gt;$b&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'a'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;?:&lt;/span&gt; &lt;span class="s1"&gt;'default'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// default&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Except that the Ternary operator will output an E_NOTICE when you have an undefined variable.&lt;/p&gt;

&lt;p&gt;But when the first argument is not null, they are different :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="s1"&gt;'default'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;
&lt;span class="nv"&gt;$b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="o"&gt;?:&lt;/span&gt; &lt;span class="s1"&gt;'default'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// default&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  That's it.
&lt;/h3&gt;

&lt;p&gt;Hope my short article can save you some debugging time.&lt;/p&gt;

</description>
      <category>php</category>
    </item>
    <item>
      <title>Beginner’s guide to SSL</title>
      <dc:creator>Thien DX</dc:creator>
      <pubDate>Sun, 03 May 2020 21:21:13 +0000</pubDate>
      <link>https://dev.to/tdx/beginner-s-guide-to-ssl-351j</link>
      <guid>https://dev.to/tdx/beginner-s-guide-to-ssl-351j</guid>
      <description>&lt;p&gt;Nowaday many websites have that cool green lock icon and HTTPS, meaning HTTP over SSL, but what benefits does SSL provide ?&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The problem
&lt;/h2&gt;

&lt;p&gt;Every technology aims to solve a problem, so does SSL.&lt;/p&gt;

&lt;p&gt;When users at home connect to a website like Facebook or Google, the messages sent between a web server and browser go through many devices such as routers, proxies. Any of them can be compromised, known as &lt;strong&gt;man-in-the-middle attack&lt;/strong&gt;  ( &lt;strong&gt;MITM&lt;/strong&gt; ).&lt;/p&gt;

&lt;p&gt;We need to deal with 2 problems :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The data transferred is not secured and can be read/modified.&lt;/li&gt;
&lt;li&gt;Clients can’t be sure whether they are talking to the &lt;strong&gt;&lt;em&gt;true&lt;/em&gt;&lt;/strong&gt; server or someone pretending.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F556%2F0%2Aj6XiR6mbUN4J15e1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F556%2F0%2Aj6XiR6mbUN4J15e1.png" width="800" height="400"&gt;&lt;/a&gt;Man-in-the-middle attack&lt;/p&gt;

&lt;h2&gt;
  
  
  2. What is SSL and how it can help ?
&lt;/h2&gt;

&lt;p&gt;SSL-Secure Sockets Layer is a security protocol that creates an encrypted connection between a client and a web server.&lt;br&gt;&lt;br&gt;
SSL can :  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Secure messages transmission with encryption
&lt;/li&gt;
&lt;li&gt;Verify Server’s identity by SSL Certificate&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s set an example, Alice is the client surfing the webs, Bob is the server, and Eve is the evil MITM attacker. Now let go into how SSL can help Alice and Bob.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Secured messages transmission with encryption&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;The basic idea is : Alice and Bob can come up with a shared secret key and use a &lt;strong&gt;symmetric encryption&lt;/strong&gt; algorithm like AES, DES, 3DES to hide their messages.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F0%2ASTW7kAVYEm2ZSOZP.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F0%2ASTW7kAVYEm2ZSOZP.jpeg" width="800" height="400"&gt;&lt;/a&gt;Symmetric encryption between Bob and Alice&lt;/p&gt;

&lt;p&gt;But, how can Alice/Bob exchanges that secret key securely with Eve watching ? The answer is &lt;strong&gt;asymmetric encryption&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Asymmetric Encryption&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;is a form of encryption with 2 keys :&lt;/em&gt; &lt;strong&gt;&lt;em&gt;public key&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;, which may be openly distributed, and&lt;/em&gt; &lt;strong&gt;&lt;em&gt;private key&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;, which is known only to the owner. Data encrypted by either key can&lt;/em&gt; &lt;strong&gt;&lt;em&gt;only&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;be decrypted by the other.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Upon initial contact, Bob sends Alice a &lt;strong&gt;SSL certificate&lt;/strong&gt; , which contains his &lt;strong&gt;public key&lt;/strong&gt; and some meta data &lt;em&gt;(we will discuss it in Verify Server’s identity section)&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Alice then can generate a shared secret key, encrypt it by Bob’s public key and send to Bob, only Bob can decrypt using his &lt;strong&gt;secret key&lt;/strong&gt; , Eve cannot.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F425%2F0%2AQwg3Is_FbJqX_Kbl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F425%2F0%2AQwg3Is_FbJqX_Kbl.png" width="800" height="400"&gt;&lt;/a&gt;&lt;em&gt;Asymmetric Encryption between Alice and Bob&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now both side have securely exchanged a secret key, and can start using symmetric encryption.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Q : Why not just use asymmetric encryption all the way ?&lt;/p&gt;

&lt;p&gt;A : Performance, asymmetric encryption requires more computational cost.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Verify Server’s identity by SSL Certificate&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;As said earlier, Alice receive Bob’s public key via SSL Certificate. So is it vulnerable to Eve MITM attack ?  &lt;strong&gt;Short answer&lt;/strong&gt; : technically, Eve cannot attack it, Alice can verify and decide to trust the certificate or not &lt;strong&gt;on client-side&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;SSL Certificate is a digital document issued to Bob for his domain by a trusted 3rd-party, called &lt;strong&gt;CA-Certificate Authority.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The SSL certificate has Bob’s public key and meta data (domain, organization, …). The CA validate those information and ensure the public key in the certificate match Bob’s private key, then sign it with their private key, creating a &lt;strong&gt;Digital Signature&lt;/strong&gt; which prevent any changes to the certificate later.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Digital Signature&lt;/strong&gt; is well described in the following picture :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1000%2F0%2Arfk_6ihyfJ3lUTCy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1000%2F0%2Arfk_6ihyfJ3lUTCy.png" width="800" height="400"&gt;&lt;/a&gt;Digital Signature&lt;/p&gt;

&lt;p&gt;If Eve tries modifying the public key, she won’t be able to generate a new signature. Later, Alice just need to use the CA's public key to validate the signature, if it's valid then the certificate is indeed from BOB and hasn't been changed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where can browsers get CA’s public key to verify the signature ?&lt;/strong&gt;&lt;br&gt;
It's already in the client browser or OS.&lt;/p&gt;

&lt;p&gt;CA have their own certificate containing the public key that browsers can use to verify their Digital Signature on website’s SSL certificates.&lt;/p&gt;

&lt;p&gt;There are Root-CA and Intermediate CA.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Root-CA :&lt;/strong&gt; default set of trusted CA, their certificates are called &lt;strong&gt;root-Certificate&lt;/strong&gt; and stored within Alice’s browsers or OS. Browsers can locally get their public key. The root-CA signed their own certificate, in other words, self-sign.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Intermediate CA :&lt;/strong&gt; Can be considered child CA. Their certificates are signed by root-CA. They can also signed website’s certificates normally or can issue another child node. If signed by an &lt;strong&gt;Intermediate CA,&lt;/strong&gt; Bob need to provide Alice all the Intermediate CA Certificates (recursively) along with his own SSL Certificate, the root-CA is excluded since Alice already have it. That will form a &lt;strong&gt;chain of trust&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F0%2AmPq9Ny9D9Z8_eXQl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F0%2AmPq9Ny9D9Z8_eXQl.png" width="800" height="400"&gt;&lt;/a&gt;Chain of trust&lt;/p&gt;

&lt;p&gt;Websites get the awesome green lock if the certificate’s chain of trust lead back to a local root-CA, otherwise browsers will show warning “Certificated not issued by a trusted CA”.&lt;/p&gt;

&lt;p&gt;For example, you can check your self, &lt;strong&gt;StackOverFlow&lt;/strong&gt; ’s certificate is signed by &lt;strong&gt;Let’s Encrypt &lt;/strong&gt; — an intermediate CA, and its certificate is signed by &lt;strong&gt;Digital Signature Trust Co&lt;/strong&gt;  — a root CA.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F709%2F1%2Af5LqjbL3aYfGT5fgTR2PLQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F709%2F1%2Af5LqjbL3aYfGT5fgTR2PLQ.png" width="800" height="400"&gt;&lt;/a&gt;&lt;strong&gt;StackOverFlow&lt;/strong&gt;’s certificate is signed by &lt;strong&gt;Let’s Encrypt &lt;/strong&gt;— an intermediate CA&lt;/p&gt;

&lt;h2&gt;
  
  
  3. So, getting a SSL certificate, where ?
&lt;/h2&gt;

&lt;p&gt;Oh, now I have to mention that there’s no free lunch, and you probably have to pay to get it, one place to check is &lt;a href="https://www.digicert.com/" rel="noopener noreferrer"&gt;Digicert&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But you like free stuff, it’s make sense you want to test before actually spending, &lt;a href="https://letsencrypt.org/" rel="noopener noreferrer"&gt;Let’s encrypt&lt;/a&gt; is a good free solution, the drawback is their certificate only last 3 months, then you will have to renew.&lt;/p&gt;

&lt;p&gt;Of course CA can be compromised and may cause security risks, but that’s another problem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;That’s all, since I want to keep it short, I tried not to go too far into any small areas, but I did my best to have the keywords included.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ssl</category>
      <category>https</category>
      <category>security</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Set up your own VPN with OpenVPN and DigitalOcean</title>
      <dc:creator>Thien DX</dc:creator>
      <pubDate>Sat, 22 Feb 2020 16:45:46 +0000</pubDate>
      <link>https://dev.to/tdx/set-up-your-own-vpn-with-minimal-effort-using-openvpn-and-digitalocean-4ocd</link>
      <guid>https://dev.to/tdx/set-up-your-own-vpn-with-minimal-effort-using-openvpn-and-digitalocean-4ocd</guid>
      <description>&lt;h3&gt;
  
  
  What is a VPN and why you need it ?
&lt;/h3&gt;

&lt;p&gt;VPN — Virtual Private Network, allows you to create a &lt;strong&gt;secure&lt;/strong&gt; connection over the &lt;strong&gt;public Internet&lt;/strong&gt; to &lt;strong&gt;&lt;em&gt;private networks at a remote location.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A VPN can provide protection if you are traveling or using untrusted WiFi networks as all your traffic will be going through an encrypted tunnel, it also provide some privacy bonuses since websites you connect to won’t know your starting location and IP.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F984%2F1%2Arp42P0KmAFhAmYi2-1L0lw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F984%2F1%2Arp42P0KmAFhAmYi2-1L0lw.png" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  OpenVPN
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://openvpn.net/" rel="noopener noreferrer"&gt;&lt;strong&gt;OpenVPN&lt;/strong&gt;&lt;/a&gt; is an open-source commercial software that implements virtual private network (VPN) techniques.&lt;/p&gt;

&lt;h3&gt;
  
  
  Set up OpenVPN on DigitalOcean
&lt;/h3&gt;

&lt;p&gt;Since we are going to host our own VPN, first we need a server, and DigitalOcean is easy to start with, you can also try AWS or Google Cloud if you want more options.&lt;/p&gt;

&lt;p&gt;Sign Up for DigitalOcean account with the following URL to get $100 credits.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://m.do.co/c/7d6bf3bf13c0" rel="noopener noreferrer"&gt;https://m.do.co/c/7d6bf3bf13c0&lt;/a&gt; (and yes, it’s my referral link)&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Step 1&lt;/strong&gt;  : Creating cloud server with OpenVPN enabled on DigitalOcean_
&lt;/h4&gt;

&lt;p&gt;After you create your account, go straight to CREATE &amp;gt; DROPLETS to create a “droplet” — cloud server.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F268%2F1%2Ap-ImmEyE7qPYPzaCqyrK3Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F268%2F1%2Ap-ImmEyE7qPYPzaCqyrK3Q.png" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You don’t need to start fresh on a new Ubuntu, there’s already an image that support OpenVPN. Marketplace &amp;gt; choose OpenVPN Access Server.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AXBV82PoyGUdttf7cNvDhKA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AXBV82PoyGUdttf7cNvDhKA.png" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For personal or family usage, the cheapest plan with 1TB data should be enough and it costs only 5$/month; Remember ? With my &lt;a href="https://m.do.co/c/7d6bf3bf13c0" rel="noopener noreferrer"&gt;referral&lt;/a&gt; link you got 100$ credit.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F202%2F1%2A-WPCCYfWHu7M5W3o0qeIDg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F202%2F1%2A-WPCCYfWHu7M5W3o0qeIDg.png" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For region you will want to choose the closest.&lt;/p&gt;

&lt;p&gt;For Authentication, since you are going to create your own VPN, I assume you should have fundamental technical background and care about privacy, &lt;strong&gt;&lt;em&gt;please choose SSH&lt;/em&gt;&lt;/strong&gt;. If you have not had a pair of public-private key yet, please check &lt;a href="https://www.digitalocean.com/community/tutorials/how-to-set-up-ssh-keys-on-ubuntu-1604" rel="noopener noreferrer"&gt;ssh-keygen&lt;/a&gt; for Ubuntu or &lt;a href="https://www.digitalocean.com/docs/droplets/how-to/add-ssh-keys/create-with-putty/" rel="noopener noreferrer"&gt;PuTTy&lt;/a&gt; for Window.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 2 : A little configuration
&lt;/h4&gt;

&lt;p&gt;On the MANAGE panel, go to Droplets &amp;gt; Click on your droplet.&lt;/p&gt;

&lt;p&gt;You may want to wait a bit if it’s showing the droplet is being created, once it’s ready, you can proceed.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Log on via SSH to start the setup procedure, you will be asked a number of questions that need to be answered, mostly you can just use default by pressing Enter.&lt;/li&gt;
&lt;li&gt;Once that is complete, enter the command “passwd openvpn” to set a password for your Access Server.&lt;/li&gt;
&lt;li&gt;Now open the address of your server in a web browser &lt;code&gt;https://your_droplet_IP/admin/&lt;/code&gt;, for example: &lt;code&gt;https://123.45.67.89/admin/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;If you see any SSL certificate warnings, that is normal, proceed anyway.&lt;/li&gt;
&lt;li&gt;Now log on with username ‘openvpn’ and the password you set.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;OpenVPN Access Server is ready, you can now add more users if you want to share this VPN with friends by adding users in the User Permissions table.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 3 : Almost done, just the client left
&lt;/h4&gt;

&lt;p&gt;Go to &lt;code&gt;https://your_droplet_IP&lt;/code&gt;, there’s no &lt;em&gt;“/admin”&lt;/em&gt; part this time.&lt;/p&gt;

&lt;p&gt;Download the suitable version of client for your OS.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F504%2F1%2A19OJGC8PMh5TLuleluutTQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F504%2F1%2A19OJGC8PMh5TLuleluutTQ.png" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After installing the client, go ahead and open it to find the Access Profile already there for you, turn it on &amp;gt; Enter username +passwords that you set in User Permissions table of the admin tools, THAT’S IT.&lt;/p&gt;

&lt;p&gt;Now you can enjoy your very own self-hosted VPN.&lt;/p&gt;

&lt;p&gt;You can double check if everything is working by &lt;a href="https://www.whatismyip.com" rel="noopener noreferrer"&gt;https://www.whatismyip.com&lt;/a&gt; , it should point to your droplet IP.&lt;/p&gt;

</description>
      <category>openvpn</category>
      <category>beginners</category>
      <category>vpn</category>
      <category>security</category>
    </item>
  </channel>
</rss>
