<?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>Forem: Peeyush Man Singh</title>
    <description>The latest articles on Forem by Peeyush Man Singh (@pssingh21).</description>
    <link>https://forem.com/pssingh21</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%2F335021%2Fc59a03b2-b12c-40d5-a6b2-8e65678585ca.png</url>
      <title>Forem: Peeyush Man Singh</title>
      <link>https://forem.com/pssingh21</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/pssingh21"/>
    <language>en</language>
    <item>
      <title>VPN access to USB SMB Server on OpenWRT</title>
      <dc:creator>Peeyush Man Singh</dc:creator>
      <pubDate>Fri, 07 Apr 2023 14:36:52 +0000</pubDate>
      <link>https://forem.com/pssingh21/vpn-access-to-usb-smb-server-on-openwrt-1k0j</link>
      <guid>https://forem.com/pssingh21/vpn-access-to-usb-smb-server-on-openwrt-1k0j</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;This post deals with accessing an SMB server on a USB mounted to your home router via Tailscale VPN. The purpose is to have a shared folder on your home network which stores files that can be accessed and be modified by devices on your home network, thus reducing dependency on third party cloud storage services. In contrast to cloud storage services, your files stay on your home network and need not be transferred over to a remote third party server. In addition, if you're not connected to your home network, but still require access to the shared files, it is possible to do so by connecting via a VPN to your home network.  &lt;/p&gt;

&lt;p&gt;This post is divided into three parts: Mounting a USB drive to a OpenWRT router, installing SMB server for file sharing and installing Tailscale as a VPN service. &lt;/p&gt;

&lt;p&gt;The prerequisites are: a router running OpenWRT as its operating system, and a USB port should be available on the router. My current setup is running OpenWRT v22.03.3 on a TP-Link Archer A9 AC1900 v6. The SMB (Server Message Block) server will run on Samba4. Alternatively, the SMB server can be installed and run on a Raspberry Pi or a NAS, however they are out of scope of this article as they require additional hardware. Here, the SMB server runs directly on the router itself and stores files on a USB mounted to the router. Tailscale VPN is chosen as a VPN service as my OpenWRT router sits behind a primary router which does not allow port forwarding. Alternatively, if you're running OpenWRT on a primary router, OpenVPN or WireGuard could be used as a VPN server.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mounting USB drive to OpenWRT
&lt;/h2&gt;

&lt;p&gt;Make sure to have the USB drive formatted to &lt;code&gt;FAT32&lt;/code&gt; format. Then plug it in to the router and create an ssh connection to the router.&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="nv"&gt;$ &lt;/span&gt;ssh root@192.168.1.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To use a USB device with OpenWRT, it needs to be configured with &lt;code&gt;ext4&lt;/code&gt; file system.&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="nv"&gt;$ &lt;/span&gt;opkg update
&lt;span class="nv"&gt;$ &lt;/span&gt;opkg &lt;span class="nb"&gt;install &lt;/span&gt;block-mount &lt;span class="se"&gt;\&lt;/span&gt;
kmod-fs-ext4 e2fsprogs parted &lt;span class="se"&gt;\&lt;/span&gt;
kmod-usb-storage kmod-usb-uhci &lt;span class="se"&gt;\&lt;/span&gt;
kmod-usb2 kmod-usb3 &lt;span class="se"&gt;\&lt;/span&gt;
kmod-usb-core kmod-usb-storage
&lt;span class="nv"&gt;$ &lt;/span&gt;parted &lt;span class="nt"&gt;-s&lt;/span&gt; /dev/sda &lt;span class="nt"&gt;--&lt;/span&gt; mklabel gpt mkpart extroot 2048s &lt;span class="nt"&gt;-2048s&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We now configure OpenWRT to use the USB to expand its root file system. OpenWRT will split the internal storage into &lt;code&gt;rootfs&lt;/code&gt; and &lt;code&gt;rootfs_data&lt;/code&gt; partitions, which are merged together into a single writable &lt;code&gt;overlay&lt;/code&gt; file system. &lt;code&gt;rootfs&lt;/code&gt; is a read only partition mounted on &lt;code&gt;/rom&lt;/code&gt;. &lt;code&gt;rootfs_data&lt;/code&gt; is a writable partition mounted on &lt;code&gt;/overlay&lt;/code&gt;. And &lt;code&gt;overlay&lt;/code&gt; is a hybrid of these two file systems mounted on &lt;code&gt;/&lt;/code&gt;, where the objects that appear in this file system do not always appear to belong to the same file system. Mostly, an object accessed in this union will be indistinguishable&lt;br&gt;
from accessing the corresponding object from the original file systems.&lt;/p&gt;

&lt;p&gt;We now configure the file system tables to mount &lt;code&gt;rootfs_data&lt;/code&gt; in another directory in case you need to access the original root overlay to change &lt;code&gt;extroot&lt;/code&gt; settings. &lt;code&gt;extroot&lt;/code&gt; works by setting another overlay partition in the external storage device, and during boot this new overlay partition will be mounted over the internal storage's overlay partition. This allows easy fallback in case the external storage device is removed, as your device will still have its own overlay partition and thus will load all configuration from there.&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="nv"&gt;$ DEVICE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"/&lt;/span&gt;&lt;span class="se"&gt;\s\/&lt;/span&gt;&lt;span class="s2"&gt;overlay&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="s2"&gt;.*&lt;/span&gt;&lt;span class="nv"&gt;$/&lt;/span&gt;&lt;span class="s2"&gt;s///p"&lt;/span&gt; /etc/mtab&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;uci &lt;span class="nt"&gt;-q&lt;/span&gt; delete fstab.rwm
&lt;span class="nv"&gt;$ &lt;/span&gt;uci &lt;span class="nb"&gt;set &lt;/span&gt;fstab.rwm&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"mount"&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;uci &lt;span class="nb"&gt;set &lt;/span&gt;fstab.rwm.device&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DEVICE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;uci &lt;span class="nb"&gt;set &lt;/span&gt;fstab.rwm.target&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/rwm"&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;uci commit fstab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check block partitions using the following 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="nv"&gt;$ &lt;/span&gt;block info
/dev/mtdblock8: &lt;span class="nv"&gt;UUID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"9fd43c61-c3f2c38f-13440ce7-53f0d42d"&lt;/span&gt; &lt;span class="nv"&gt;VERSION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"4.0"&lt;/span&gt; &lt;span class="nv"&gt;MOUNT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/rom"&lt;/span&gt; &lt;span class="nv"&gt;TYPE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"squashfs"&lt;/span&gt;
/dev/mtdblock9: &lt;span class="nv"&gt;MOUNT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/rwm"&lt;/span&gt; &lt;span class="nv"&gt;TYPE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"jffs2"&lt;/span&gt;
/dev/sda1: &lt;span class="nv"&gt;UUID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"fdacc9f1-0e0e-45ab-acee-9cb9cc8d7d49"&lt;/span&gt; &lt;span class="nv"&gt;LABEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"extroot"&lt;/span&gt; &lt;span class="nv"&gt;VERSION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"1.0"&lt;/span&gt; &lt;span class="nv"&gt;MOUNT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/overlay"&lt;/span&gt; &lt;span class="nv"&gt;TYPE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"ext4"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;mtdblock*&lt;/code&gt; are the devices in internal flash memory, and /dev/sda1 is the partition on the USB flash drive.&lt;br&gt;
We now create an &lt;code&gt;ext4&lt;/code&gt; file system on the first partition of the USB device – &lt;code&gt;/dev/sda1&lt;/code&gt;.&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="nv"&gt;$ DEVICE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/dev/sda1"&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;mkfs.ext4 &lt;span class="nt"&gt;-L&lt;/span&gt; extroot &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DEVICE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we configure the selected partition as new overlay via &lt;code&gt;fstab&lt;/code&gt;.&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="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;block info &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DEVICE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"UUID=&lt;/span&gt;&lt;span class="se"&gt;\S&lt;/span&gt;&lt;span class="s2"&gt;*"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;uci &lt;span class="nt"&gt;-q&lt;/span&gt; delete fstab.overlay
&lt;span class="nv"&gt;$ &lt;/span&gt;uci &lt;span class="nb"&gt;set &lt;/span&gt;fstab.overlay&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"mount"&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;uci &lt;span class="nb"&gt;set &lt;/span&gt;fstab.overlay.uuid&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;UUID&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;uci &lt;span class="nb"&gt;set &lt;/span&gt;fstab.overlay.target&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/overlay"&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;uci commit fstab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We now transfer the content of the current overlay to the external drive and reboot the device to apply changes.&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="nv"&gt;$ &lt;/span&gt;mount &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DEVICE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; /mnt
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-C&lt;/span&gt; /overlay &lt;span class="nt"&gt;-cvf&lt;/span&gt; - &lt;span class="nb"&gt;.&lt;/span&gt; | &lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-C&lt;/span&gt; /mnt &lt;span class="nt"&gt;-xf&lt;/span&gt; -
&lt;span class="nv"&gt;$ &lt;/span&gt;reboot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To test if it worked as expected, after the reboot, login to your Luci web portal and navigate to &lt;code&gt;System -&amp;gt; Mount Points&lt;/code&gt;. This should show the USB partition mounted as &lt;code&gt;overlay&lt;/code&gt;. And if you navigate to &lt;code&gt;System -&amp;gt; Software&lt;/code&gt;, it should show you the additional free space of the overlay partition from the USB drive. &lt;/p&gt;

&lt;h2&gt;
  
  
  File sharing with Samba4
&lt;/h2&gt;

&lt;p&gt;Install the following dependencies to start a Samba4 server.&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="nv"&gt;$ &lt;/span&gt;opkg update
&lt;span class="nv"&gt;$ &lt;/span&gt;opkg &lt;span class="nb"&gt;install &lt;/span&gt;kmod-usb-extras block-mount &lt;span class="se"&gt;\&lt;/span&gt;
ntfs-3g samba4-server luci-app-samba4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a &lt;code&gt;share/&lt;/code&gt; folder. This will be the folder that will be shared on the network. Also, change permissions of the folder so that any user can read and write to the folder.&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="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; /overlay/share
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;chmod &lt;/span&gt;a+rwX /overlay/share
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now login to Luci web portal and navigate to &lt;code&gt;Services -&amp;gt; Network share&lt;/code&gt; and configure as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Interface&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lan&lt;/span&gt;
&lt;span class="na"&gt;Workgroup&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;WORKGROUP&lt;/span&gt;
&lt;span class="na"&gt;Enable macOS compatible shares&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Check (Optional)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: &lt;strong&gt;Never expose SMB to the Internet. SMB servers should only be accessed over a VPN.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;On the &lt;code&gt;Shared directories&lt;/code&gt; section, add a directory with the following configurations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;share&lt;/span&gt;
&lt;span class="na"&gt;Path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/overlay/share&lt;/span&gt;
&lt;span class="na"&gt;Browsable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;True&lt;/span&gt;
&lt;span class="na"&gt;Allow guests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save and apply changes. Now we need to add new SMB users. Open &lt;code&gt;/etc/passwd&lt;/code&gt; on the router.&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="nv"&gt;$ &lt;/span&gt;vi /etc/passwd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Append at the end of file the following line.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;newuser:*:1000:65534:newuser:/var:/bin/false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace the two &lt;code&gt;newuser&lt;/code&gt; placeholders with a username of your choice. &lt;/p&gt;

&lt;p&gt;Create password for your &lt;code&gt;newuser&lt;/code&gt;.&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="nv"&gt;$ &lt;/span&gt;smbpasswd &lt;span class="nt"&gt;-a&lt;/span&gt; newuser
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then restart the Samba4 service.&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="nv"&gt;$ &lt;/span&gt;service samba4 restart
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again, login to Luci web portal and navigate to &lt;code&gt;Services -&amp;gt; Network share&lt;/code&gt;. On the &lt;code&gt;Shared directories&lt;/code&gt; section, on the &lt;code&gt;Allowed Users&lt;/code&gt; field, enter the username you selected earlier, uncheck &lt;code&gt;Allow guests&lt;/code&gt;, then save and apply.&lt;/p&gt;

&lt;p&gt;SMB server is now up and running. You can test this by connecting through another device on the same network. The URL should be &lt;code&gt;smb://192.168.1.1/share&lt;/code&gt; (for Windows &lt;code&gt;\\192.168.1.1\share&lt;/code&gt;). Then authenticate with the earlier defined username and password.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install Tailscale on OpenWRT
&lt;/h2&gt;

&lt;p&gt;Install the following dependencies for Tailscale.&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="nv"&gt;$ &lt;/span&gt;opkg update
&lt;span class="nv"&gt;$ &lt;/span&gt;okpg &lt;span class="nb"&gt;install &lt;/span&gt;tailscale iptables-nft
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now log in to Tailscale using the following command. Copy the login URL into a browser and use SSO to log in to Tailscale. Then register this router as one of your devices. Also, download and install Tailscale app on a second device, as Tailscale requires at least two devices to be registered to communicate.&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="nv"&gt;$ &lt;/span&gt;tailscale up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We need to advertise our local routes for other devices to be able to connect to our local network. You can define the IPv4 address space to be advertised to your devices. Additionally, we can also use this router as an exit node for VPN traffic. If you want split tunneling of your traffic and only require access to the local area network, you can leave out the exit node flag.&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="nv"&gt;$ &lt;/span&gt;tailscale up &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--advertise-routes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;192.168.0.0/16 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--advertise-exit-node&lt;/span&gt; &lt;span class="nt"&gt;--accept-routes&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--netfilter-mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;off
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Additionally, you need to enable Subnet route and exit node to be allowed on the Tailscale web portal. For this, navigate to the Tailscale web portal. Select &lt;code&gt;Edit route settings&lt;/code&gt; on OpenWRT, and enable &lt;code&gt;Subnet routes&lt;/code&gt; and &lt;code&gt;Exit node&lt;/code&gt; options. Also, you can disable key expiry for OpenWRT router on the web portal so that you need not login time and again via the router. &lt;/p&gt;

&lt;p&gt;To use OpenWRT router as an exit node, further configurations should be changed in OpenWRT. Log in to Luci web portal and navigate to &lt;code&gt;Network -&amp;gt; Firewall -&amp;gt; General Settings -&amp;gt; Add&lt;/code&gt; and set the following configurations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;General&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Tailscale&lt;/span&gt;
    &lt;span class="na"&gt;Input&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Accept&lt;/span&gt;
    &lt;span class="na"&gt;Output&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Accept&lt;/span&gt;
    &lt;span class="na"&gt;Forward&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Accept&lt;/span&gt;
    &lt;span class="na"&gt;Masquerading&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;True&lt;/span&gt;
    &lt;span class="na"&gt;MSS clamping&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;True&lt;/span&gt;
    &lt;span class="na"&gt;Covered Networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Unspecified&lt;/span&gt;
    &lt;span class="na"&gt;Allow forward to destination zones&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Lan, Wan&lt;/span&gt;
    &lt;span class="na"&gt;Allow forward from source zones&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Lan, Wan&lt;/span&gt;
&lt;span class="na"&gt;Advanced&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Covered devices&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tailscale0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Navigate to &lt;code&gt;Network -&amp;gt; Firewall -&amp;gt; NAT Rules -&amp;gt; Add&lt;/code&gt; and set the following configurations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;General&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Tailscale&lt;/span&gt; 
    &lt;span class="na"&gt;Protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Any&lt;/span&gt; 
    &lt;span class="na"&gt;Outbound zone&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Any zone&lt;/span&gt; 
    &lt;span class="na"&gt;Source address&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Any&lt;/span&gt; 
    &lt;span class="na"&gt;Destination address&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Any&lt;/span&gt; 
    &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;MASQUERADE&lt;/span&gt;
&lt;span class="na"&gt;Advanced&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Outbound device&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tailscale0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tailscale is now configured. Now you should be able to connect to the SMB server via the Tailscale VPN. Tailscale is available as a graphical user app for Windows, Mac, Android, and iOS. To connect to Tailscale from Ubuntu, use the following commands.&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="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;tailscale
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="c"&gt;#Connect to tailscale and use exit node&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;tailscale up &lt;span class="nt"&gt;--accept-routes&lt;/span&gt; &lt;span class="nt"&gt;--exit-node&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;openwrt
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="c"&gt;#Connect to tailscale with split tunneling&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;tailscale up &lt;span class="nt"&gt;--accept-routes&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="c"&gt;#Disconnect tailscale&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;tailscale down
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To start Tailscale automatically on router startup, the Tailscale up command needs to be configured in &lt;code&gt;/etc/init.d&lt;/code&gt;.&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="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /etc/init.d/tailscalevpn&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
#!/bin/sh /etc/rc.common
# Script to toggle tailscale up and down

START=80

start() {

    tailscale up --advertise-routes=192.168.0.0/16 --advertise-exit-node --accept-routes --netfilter-mode=off

}

stop() {

    tailscale down

}
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first line of a &lt;code&gt;init.d&lt;/code&gt; script must be &lt;code&gt;#!/bin/sh /etc/rc.common&lt;/code&gt;. &lt;code&gt;START=80&lt;/code&gt; determines at which point in the &lt;code&gt;init sequence&lt;/code&gt; this script gets executed. This means that the file will be symlinked as &lt;code&gt;/etc/rc.d/S80tailscalevpn&lt;/code&gt;. It will then start after the init scripts with &lt;code&gt;START=79 and below&lt;/code&gt;, but before &lt;code&gt;START=81 and above&lt;/code&gt;. The &lt;code&gt;start()&lt;/code&gt; command will be run when it is called with 'start' as its parameter (&lt;code&gt;/etc/init.d/tailscalevpn start&lt;/code&gt;). Likewise, the &lt;code&gt;stop()&lt;/code&gt; command will be run when it is called with 'stop' as its parameter (&lt;code&gt;/etc/init.d/tailscalevpn stop&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Make sure the file is executable.&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="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; +x /etc/init.d/tailscalevpn
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enable your script. In order to automatically start the init script on boot, it must be enabled. This will create one or more symlinks in &lt;code&gt;/etc/rc.d/&lt;/code&gt; which automatically execute at boot time and shutdown time. This makes the application behave as a system service, by starting when the device boots and stopping at shutdown, as configured in the init.d script. If you need to disable the script, use the &lt;code&gt;disable&lt;/code&gt; 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="nv"&gt;$ &lt;/span&gt;/etc/init.d/tailscalevpn &lt;span class="nb"&gt;enable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your script should now have a symlink in &lt;code&gt;/etc/rc.d&lt;/code&gt;. At boot time, the &lt;code&gt;init.d&lt;/code&gt; daemon just starts executing scripts it finds in &lt;code&gt;/etc/rc.d&lt;/code&gt; according to their file names. In this case, our filename will be &lt;code&gt;S80tailscalevpn&lt;/code&gt; as described above and will start at the 80th position.&lt;/p&gt;

&lt;p&gt;In order to confirm that your script is enabled in &lt;code&gt;init.d&lt;/code&gt;, run the following command. If the output of the script is &lt;code&gt;on&lt;/code&gt;, it should be enabled.&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="nv"&gt;$ &lt;/span&gt;/etc/init.d/tailscalevpn enabled &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo &lt;/span&gt;on
on
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is how you can use a USB on a OpenWRT router as a file sharing SMB server and access it via a VPN. Note that SMB is not optimal for streaming media over VPN. It is good for document access over a VPN. However, streaming within the LAN itself is performant. For streaming over VPN, other services such as Plex server should be considered. Apart from SMB, NFS (Network File Share) can also be used to share files on the LAN. &lt;/p&gt;

&lt;p&gt;Happy Hacking!&lt;/p&gt;

</description>
      <category>openwrt</category>
      <category>smb</category>
      <category>tailscale</category>
      <category>vpn</category>
    </item>
    <item>
      <title>Intrusion Detection using in-built Webcam</title>
      <dc:creator>Peeyush Man Singh</dc:creator>
      <pubDate>Fri, 06 Jan 2023 18:13:40 +0000</pubDate>
      <link>https://forem.com/pssingh21/intrusion-detection-using-in-built-webcam-326k</link>
      <guid>https://forem.com/pssingh21/intrusion-detection-using-in-built-webcam-326k</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;This post is about building an intrusion detection system on Ubuntu using the laptop's in-built camera. It can be used to detect intrusion while you are out of your room or when someone tries to access your computer while it is locked. Also, no additional hardware is required for this setup. &lt;/p&gt;

&lt;p&gt;We will be using &lt;a href="https://motion-project.github.io"&gt;Motion&lt;/a&gt; for motion detection. &lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;To install Motion on Debian based systems, use the following 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="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get update
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;motion
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Optionally, it can also be downloaded via Ubuntu Software Center, and it can be installed on other distros or operating systems by following the &lt;a href="https://motion-project.github.io/motion_build.html"&gt;installation guide&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring Motion
&lt;/h2&gt;

&lt;p&gt;Copy the root configuration file to your home folder.&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="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; ~/.motion
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo cp&lt;/span&gt; /etc/motion/motion.conf ~/.motion/motion.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open the configuration file for editing.&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="nv"&gt;$ &lt;/span&gt;nano ~/.motion/motion.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;daemon&lt;/code&gt; option can be changed to on if you want the process to be run in the background.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;daemon: off
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;target_dir&lt;/code&gt; specifies the directory location where images and/or videos will be saved to.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;target_dir  /home/user/survellience
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;log_file&lt;/code&gt; specifies the file location where the log file will be stored.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;log_file /home/user/survellience/log/motion/motion.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; specifies the width and height of images.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;width: 640
height: 480
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;threshold&lt;/code&gt; specifies the minimum number of pixels that needs to be changed between frames to trigger an event.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;threshold: 500
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;picture_output&lt;/code&gt; specifies whether to save pictures of the event.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;picture_output: on
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;movie_output&lt;/code&gt; specifies whether to save a movie clip of the event.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;movie_output: on
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;webcontrol_port&lt;/code&gt; specifies the localhost port number where the web portal will be shown.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;webcontrol_port 8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Running motion detection
&lt;/h2&gt;

&lt;p&gt;To run the program, use the following command. The &lt;code&gt;-c&lt;/code&gt; option defines the path to the configuration file.&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="nv"&gt;$ &lt;/span&gt;motion &lt;span class="nt"&gt;-c&lt;/span&gt; ~/.motion/motion.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can view the web portal on &lt;a href="http://localhost:8080/"&gt;http://localhost:8080/&lt;/a&gt;. Also notice image and/or movie files being created in the &lt;code&gt;target_folder&lt;/code&gt; when it detects motion.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sounding the Alarm
&lt;/h2&gt;

&lt;p&gt;To sound an alarm, you will need a mp3 file. Any mp3 file should work. &lt;a href="https://orangefreesounds.com/burglar-alarm-sound/"&gt;Here&lt;/a&gt; is a free alarm mp3 file to download.&lt;/p&gt;

&lt;p&gt;To play a mp3 file from the terminal, install the Sox command line utility. &lt;code&gt;libsox-fmt-all&lt;/code&gt; is suggested to be installed manually after installing Sox.&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="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get update
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;sox
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;libsox-fmt-all
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a bash script file in path &lt;code&gt;~/.motion&lt;/code&gt;.&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="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;touch&lt;/span&gt; ~/.motion/event_start_alarm.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add the following to the contents of the file.&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;#!/bin/bash&lt;/span&gt;
play /home/user/.motion/alarm.mp3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then make the file executable using &lt;code&gt;chmod&lt;/code&gt;.&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="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;chmod &lt;/span&gt;u+x ~/.motion/event_start_alarm.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now open the Motion config file and add the path to this script to the &lt;code&gt;on_event_start&lt;/code&gt; option. Note that this option is by default disabled using comment. Make sure to uncomment the line and add the path to the script file.&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="nv"&gt;$ &lt;/span&gt;nano ~/.motion/motion.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;on_event_start /home/user/.motion/event_start_alarm.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now start the program as before and when it detects a motion, it should sound the alarm, take pictures and videos and save them to the &lt;code&gt;target_folder&lt;/code&gt;.&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="nv"&gt;$ &lt;/span&gt;motion &lt;span class="nt"&gt;-c&lt;/span&gt; ~/.motion/motion.conf 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Optionally, the &lt;code&gt;target_folder&lt;/code&gt; could also be a network file location, so that you can view what motion the program detected when you are out of home. &lt;/p&gt;

&lt;p&gt;You can use the following command if you want Motion to set off after a fixed period of time. For example, if you run the command and go away, it will sound immediately as it detected the motion as you moved away. To avoid this, you can let it start once you leave your workstation, say after 5 minutes of running the 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="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sleep &lt;/span&gt;5m&lt;span class="p"&gt;;&lt;/span&gt; motion &lt;span class="nt"&gt;-c&lt;/span&gt; ~/.motion/motion.conf 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Motion also continues to work even while your computer is locked, so make sure to lock your computer before leaving. &lt;/p&gt;

&lt;p&gt;Happy Hacking!&lt;/p&gt;

</description>
      <category>webcam</category>
      <category>motion</category>
      <category>intrusion</category>
      <category>ubuntu</category>
    </item>
    <item>
      <title>OpenWRT</title>
      <dc:creator>Peeyush Man Singh</dc:creator>
      <pubDate>Fri, 23 Sep 2022 15:57:00 +0000</pubDate>
      <link>https://forem.com/pssingh21/openwrt-4917</link>
      <guid>https://forem.com/pssingh21/openwrt-4917</guid>
      <description>&lt;p&gt;OpenWRT is a free and open source Linux based operating system for embedded devices such as routers. It is mainly used to increase the router's performance and security as compared to the default firmware that comes pre-installed with the router.&lt;/p&gt;

&lt;p&gt;OpenWRT currently supports about 2000 router models. The complete list of routers that support OpenWRT can be found &lt;a href="https://openwrt.org/toh/start" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Alternatively, with OpenWRT you can also build your own router on an old PC, Raspberry Pi, VM or any hardware that is based on x86 architecture. &lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits of using OpenWRT
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reduce latency and increase network throughput.&lt;/strong&gt; OpenWRT reduces Bufferbloat (high latency caused due to excess buffering of packets) using Smart Queue Management(SQM), resulting in consistent latency even under high load.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Increased security.&lt;/strong&gt; There are no hidden backdoors left by hardware vendors. When security vulnerabilities are found, firmware updates are soon released to fix them. While many commercial vendors only provide updates to the newest hardware models, OpenWRT keeps supporting updates to all routers unless the RAM/Flash storage cannot accommodate the size of the new release. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Less attack vector.&lt;/strong&gt; The default OpenWRT configuration provides full internet connectivity without exposing the router or any connected devices to attacks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;AdBlock directly on the router.&lt;/strong&gt; Ads/abuse domains can be blocked directly on the router, thus preventing all connected devices from connecting to those servers. AdBlock need not be installed on individual devices.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Setup a VPN client or VPN server on the router.&lt;/strong&gt; Setting up a VPN client on the router allows all connected devices to access the internet through a VPN, thus preventing your ISP from snooping on your internet activity. Setting up a VPN server allows you to connect to your home router from a different network when you're away and access resources on the home network, such as shared storage, Network Attached Storage (NAS), Plex server, printer etc.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Secure DNS.&lt;/strong&gt; OpenWRT supports DNS over HTTPS and allows you to select any DNS server, preventing your ISP from snooping on your DNS requests by using their own DNS server. By using public DNS providers, you can escape DNS-based content filters and internet censorship from your ISP. Encrypted DNS over HTTPS prevents DNS leaks and DNS hijacking. You can force connected devices with hard-coded DNS servers to use your router's DNS to protect DNS traffic.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Create a guest network.&lt;/strong&gt; You can create a separate wireless network for guests to use. This allows them to access the internet via your router, but blocks them from accessing the devices on your network. Also, you need not share your router's main password with guests.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Prioritize traffic with QOS.&lt;/strong&gt; OpenWRT allows you to prioritize certain type of traffic or prioritize traffic going to specific devices and deprioritize going to other devices. For instance, you could give the highest priority to video streaming or gaming over web surfing, or give the highest priority to a work computer over mobile devices.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Monitor your network in real time.&lt;/strong&gt; It allows real time access to all connected devices, and you can log all packets travelling through your router and analyze them using Wireshark. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Time restriction and parental controls.&lt;/strong&gt; With time restrictions, you can block internet access for certain devices on week days during specific time intervals. Parental control allows you to restrict access to certain web pages.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;This is by far not a complete list of all the benefits of OpenWRT. OpenWrt provides more than 3000 packages ready to be installed, unlike vendor firmware that ships with a limited set of capabilities.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Installing OpenWRT
&lt;/h2&gt;

&lt;p&gt;Here is an example for installing OpenWRT on a &lt;a href="https://openwrt.org/toh/hwdata/tp-link/tp-link_archer_a9_v6" rel="noopener noreferrer"&gt;TP-Link Archer A9 AC 1900 v6&lt;/a&gt; router. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fbh03aojvnx44wmr3b996.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fbh03aojvnx44wmr3b996.jpg" alt="TP-Link Archer A9 AC 1900 v6"&gt;&lt;/a&gt;TP-Link Archer A9 AC 1900 v6&lt;/p&gt;

&lt;p&gt;Before installing OpenWRT, it is recommended to download the original firmware of your router. For TP-Link users: &lt;a href="https://www.tp-link.com/us/support/download/" rel="noopener noreferrer"&gt;https://www.tp-link.com/us/support/download/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Next, download the OpenWRT firmware for the corresponding router and the right version from &lt;a href="https://openwrt.org/toh/start" rel="noopener noreferrer"&gt;Table of Hardware&lt;/a&gt; by navigating to the corresponding tech data page and downloading files corresponding to "Firmware OpenWrt Install URL" and "Firmware OpenWrt Upgrade URL".&lt;/p&gt;

&lt;p&gt;Connect your laptop to the router using an ethernet cable and make sure that the Wi-Fi is turned off on the laptop.&lt;/p&gt;

&lt;p&gt;Login to your router's portal. Normally: &lt;a href="http://192.168.1.1" rel="noopener noreferrer"&gt;http://192.168.1.1&lt;/a&gt;. Select firmware upgrade option and upload the recently downloaded '...factory.bin' file.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fiifm4xoawwlgtqxcx3pv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fiifm4xoawwlgtqxcx3pv.png" alt="TP-Link portal"&gt;&lt;/a&gt; &lt;/p&gt;
TP-Link portal



&lt;p&gt;Wait for the firmware to be installed. &lt;/p&gt;

&lt;p&gt;Once the firmware installation is complete, the browser should be automatically redirected to &lt;a href="http://192.168.1.1" rel="noopener noreferrer"&gt;http://192.168.1.1&lt;/a&gt; OpenWRT portal.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fn94vbixijeq79rggaehp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fn94vbixijeq79rggaehp.png" alt="OpenWRT GUI login screen"&gt;&lt;/a&gt;&lt;/p&gt;
OpenWRT GUI login screen



&lt;p&gt;Login using username:root and Password:(empty).&lt;/p&gt;

&lt;p&gt;OpenWRT is now installed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Finw1i7ca6onp8s7kezvy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Finw1i7ca6onp8s7kezvy.png" alt="OpenWRT GUI dashboard"&gt;&lt;/a&gt;OpenWRT GUI dashboard&lt;/p&gt;

&lt;h2&gt;
  
  
  Terminal vs GUI
&lt;/h2&gt;

&lt;p&gt;You can access OpenWRT portal by using the GUI by connecting to &lt;code&gt;http://192.168.1.1&lt;/code&gt;. &lt;code&gt;Luci&lt;/code&gt; is the graphical user interface for OpenWRT. Alternatively, you can configure OpenWRT from the terminal using ssh.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh root@192.168.1.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.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%2Fnw7cq29umecrm3dggsnf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fnw7cq29umecrm3dggsnf.png" alt="OpenWRT in Terminal"&gt;&lt;/a&gt;&lt;/p&gt;
OpenWRT in Terminal



&lt;h2&gt;
  
  
  Post install
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Set password
&lt;/h3&gt;

&lt;p&gt;Set a strong password for OpenWRT portal. Password can be set by navigating to System-&amp;gt;Administration.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fnjcsgchnvzxkmfyjj2em.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fnjcsgchnvzxkmfyjj2em.png" alt="Set new password"&gt;&lt;/a&gt;&lt;/p&gt;
Set new password



&lt;h3&gt;
  
  
  Update OpenWRT firmware
&lt;/h3&gt;

&lt;p&gt;Navigate to System-&amp;gt;Flash Firmware and upload the "...sysupgrade.bin" file on the 'Flash new image' field. The router firmware should update to the latest version and reboot.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fn3p89mut5i64loz6u0a4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fn3p89mut5i64loz6u0a4.png" alt="Update OpenWRT firmware"&gt;&lt;/a&gt;&lt;/p&gt;
Update OpenWRT firmware



&lt;h3&gt;
  
  
  Enable Wi-Fi
&lt;/h3&gt;

&lt;p&gt;By default, Wi-Fi is disabled on OpenWRT due to security reasons. You can enable it by navigating to Network-&amp;gt;Wireless. Dual band routers can have two radios, one for each band that needs to be configured individually. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fwaku9hog0wwcwu52pbxi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fwaku9hog0wwcwu52pbxi.png" alt="Enable Wi-Fi on router"&gt;&lt;/a&gt;&lt;/p&gt;
Enable Wi-Fi on router



&lt;p&gt;Click on edit. Enter the desired Wi-Fi name on ESSID field. Navigate to Wireless Security tab. Choose desired encryption type, cipher, and enter a new password in the 'key' field.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fu9pg9iiohhn6kfox1abt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fu9pg9iiohhn6kfox1abt.png" alt="Wi-Fi configuration"&gt;&lt;/a&gt;&lt;/p&gt;
Wi-Fi configuration



&lt;p&gt;Click save and apply.&lt;/p&gt;

&lt;p&gt;Wi-Fi should now be available and can be connected using the entered Wi-Fi name and password.&lt;/p&gt;

&lt;h2&gt;
  
  
  Plugins and add-ons
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Adblock&lt;/strong&gt;: Adblock using plugins &lt;code&gt;adblock&lt;/code&gt; and &lt;code&gt;luci-app-adblock&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.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%2F69k3ju4l6xha30p7bahi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F69k3ju4l6xha30p7bahi.png" alt="Adblock in OpenWRT"&gt;&lt;/a&gt;Adblock in OpenWRT&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Encrypted DNS&lt;/strong&gt;: DNS over HTTPS with plugins &lt;code&gt;dnsmasq&lt;/code&gt; and &lt;code&gt;https-dns-proxy&lt;/code&gt;. Or DNS over TLS with plugin &lt;code&gt;unbound&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fhagu1x4inpdy4d49pyco.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fhagu1x4inpdy4d49pyco.png" alt="DNS over HTTPS"&gt;&lt;/a&gt;DNS over HTTPS&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;VPN&lt;/strong&gt;: OpenVPN client using plugins &lt;code&gt;openvpn-openssl&lt;/code&gt; and &lt;code&gt;luci-app-openvpn&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fmgplcm0iedme725fb4xt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fmgplcm0iedme725fb4xt.png" alt="NordVPN on OpenWRT"&gt;&lt;/a&gt;&lt;/p&gt;
NordVPN on OpenWRT



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;VPN-Split-tunneling&lt;/strong&gt;: Enable split tunneling with VPN with plugins &lt;code&gt;vpn-policy-routing&lt;/code&gt; and &lt;code&gt;luci-app-vpn-ploicy-routing&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.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%2F8qrlxj9pntql03umqmaj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F8qrlxj9pntql03umqmaj.png" alt="VPN split tunneling, policy-based routing"&gt;&lt;/a&gt;&lt;/p&gt;
VPN split tunneling, policy-based routing



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Statistics&lt;/strong&gt;: View real time statistics using plugin &lt;code&gt;luci-app-statistics&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.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%2F0f3jh53swk3om5y8nrc6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F0f3jh53swk3om5y8nrc6.png" alt="Statistics"&gt;&lt;/a&gt;&lt;/p&gt;
Statistics of router



&lt;p&gt;Happy hacking!&lt;/p&gt;

</description>
      <category>openwrt</category>
      <category>network</category>
      <category>router</category>
    </item>
    <item>
      <title>2FA with FIDO U2F / OTP / HOTP / TOTP</title>
      <dc:creator>Peeyush Man Singh</dc:creator>
      <pubDate>Thu, 16 Sep 2021 12:42:34 +0000</pubDate>
      <link>https://forem.com/pssingh21/2fa-with-fido-u2f-otp-hotp-totp-46ia</link>
      <guid>https://forem.com/pssingh21/2fa-with-fido-u2f-otp-hotp-totp-46ia</guid>
      <description>&lt;p&gt;Two-factor authentication (2FA) is an authentication method where the user is granted access only after successfully authenticating oneself via two mechanisms.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Knowledge: something the user knows (eg. password, PIN)&lt;/li&gt;
&lt;li&gt;Possession: something the user has (eg. physical key, smartphone)&lt;/li&gt;
&lt;li&gt;Inheritance: something the user is (eg. fingerprint, iris scan)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With 2FA, a compromise of one of these factors will not provide access to the account. So, even if your password is stolen or your phone is lost, it is highly unlikely for the attacker to gain access to your account. Generally a combination of username/password and a second authentication factor is used to authenticate the user to the service.&lt;/p&gt;

&lt;p&gt;Common 2FA authentication methods include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hardware tokens [FIDO U2F / HOTP]&lt;/li&gt;
&lt;li&gt;SMS / Voice based [OTP]&lt;/li&gt;
&lt;li&gt;Software tokens for 2FA [TOTP]&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Biometric (Fingerprint, Retina pattern, facial recognition)&lt;br&gt;
__&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;OTP - One Time Password&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;HOTP - Hash based One Time Password&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;TOTP - Time based One Time Password&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;FIDO U2F - Fast Identity Online Universal Second Factor&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  OTP
&lt;/h2&gt;

&lt;p&gt;The user receives an SMS or a voice call with their One Time Password. OTPs are generated with algorithms generating random numbers. It is therefore also resistant to replay attacks since one OTP is only tied to one session. Industry standard algorithms such as SHA-1 generate OTPs with a shared secret and a moving factor. &lt;/p&gt;

&lt;p&gt;Many services use SMS OTP as a second form of authentication. It might be more convenient, but is less secure. Sim porting attacks allows an attacker to take over the victim's number to their own device and receive SMS destined to the victim. &lt;/p&gt;

&lt;h2&gt;
  
  
  HOTP
&lt;/h2&gt;

&lt;p&gt;Similar to OTP, HOTP is generated with a shared secret and the moving factor  is based on a counter. Each time HOTP is requested and validated, the counter is incremented. The HOTP generator and the server are synced each time the code is validated. To calculate an OTP, the shared secret and the counter are fed into the HMAC algorithm, which uses SHA-1 as a hash function. &lt;/p&gt;

&lt;p&gt;The HOTP code is valid until a new code is generated, which is now seen as a vulnerability. Yubico's Yubikey is an example of OTP generator that uses HOTP. &lt;/p&gt;

&lt;h2&gt;
  
  
  TOTP
&lt;/h2&gt;

&lt;p&gt;TOTP is used to generate a regularly changing code based on a shared secret and current time. It is similar to HOTP, but the counter is replaced with timestamp values. Each code is generally valid for 30 seconds. If the code is not used in this window, it will become invalid and a new code has to be generated. The server should additionally account for time drifts. &lt;/p&gt;

&lt;p&gt;Authenticator apps such as Google Authenticator, Authy, 1Password can be used to generate TOTP. &lt;/p&gt;

&lt;p&gt;It is impossible for the attacker to guess the secret keys based on any OTP. OTP,  HOTP and TOTP are still susceptible to phishing attacks. If a victim enters the username/password and the OTP into a malicious page, the attacker can quickly use them on the target site, thus gaining control of the user's account. &lt;/p&gt;

&lt;h2&gt;
  
  
  FIDO U2F
&lt;/h2&gt;

&lt;p&gt;FIDO U2F is an open authentication standard, which allows users to access online services with a physical security key. It works out of the box without any device drivers or software installations. The user also does not have to type in the key unlike OTPs.&lt;/p&gt;

&lt;p&gt;When the user first wants to register a key with an account, the security key generates a private key with a random number (&lt;em&gt;nonce&lt;/em&gt;) and uses a secure hashing function to hash the nonce, domain of the website that the user is in in and a secret key. FIDO U2F uses HMAC-SHA-256 which is more secure than TOTP hash function (&lt;em&gt;SHA-1&lt;/em&gt;). From this private key, a public key is generated with a checksum, also secured by secure hash and sends this to the server along with the nonce. The secret key never leaves the device.&lt;/p&gt;

&lt;p&gt;For logging in after registration, the user needs to plug in the key and press the button. The server generates a challenge - a random number and passes this along with the nonce and checksum generated on registration. The security key applies the same process to generate the same private key and uses the checksum to confirm that the nonce did come from the device. The device then signs the challenge with the private key using ECDSA (&lt;em&gt;Elliptic Curve Digital Signature Algorithm&lt;/em&gt;) and sends this to the server. The server verifies the signature using the public key.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.yubico.com%2Fwp-content%2Fuploads%2F2021%2F02%2FMatrix-1024x683.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.yubico.com%2Fwp-content%2Fuploads%2F2021%2F02%2FMatrix-1024x683.jpg" title="Yubico Yubikey" alt="Yubico Yubikey"&gt;&lt;/a&gt;&lt;/p&gt;
Yubico Yubikey



&lt;p&gt;Since the domain of the website is used to generate the key, during a phishing attack it will generate a different key and the checksum will fail. So the attacker cannot gain access to the real signature. &lt;/p&gt;

&lt;p&gt;It is a hardware security token, so even if the computer is infected with malware, attackers wont be able to steal the secret key in it. The key also requires a human to physically press the button (&lt;em&gt;HID protocol&lt;/em&gt;), so it cannot be activated remotely. &lt;/p&gt;

&lt;p&gt;Even if an attacker manages to infect the server and steal the public key from the server, they would still not be able to sign the challenge and login. The private key is still stored in the security key. The challenge response mechanism also prevents replay attacks and the signature from the key is also single use. &lt;/p&gt;

&lt;p&gt;The same U2F device can be used to authenticate for multiple services. There is no way for anyone to know it was the same device, even if they had access to both databases.&lt;/p&gt;

&lt;p&gt;Most keys aren't Bluetooth enabled, so they don't require batteries or maintenance.&lt;/p&gt;

&lt;p&gt;If the USB token is lost or stolen, there is no user information that is saved on it. They also can't be cloned, as the private information on the key can't be extracted. So it is impossible for an attacker to determine who it could be used for and on what services. Users can register two U2F devices with every service, so even if one key is lost the other one can be used to unlock the account.&lt;/p&gt;

&lt;p&gt;However, the downside is that it costs money to buy a dedicated security key, unlike TOTP, which is free. Also you have to carry around a key and there are chances it might get lost or misplaced, so you need to have an additional key in a secure location, so that you don't get locked out of your account.  &lt;/p&gt;

&lt;p&gt;Yubico's Yubikey is a popular implementation of FIDO U2F. It works over USB and NFC. &lt;/p&gt;

&lt;p&gt;FIDO U2F offers strong security with easy-to-use method, but comes at a cost, although relatively cheap (Yubikeys starting at €45). TOTP also offers good security for free of cost. Password and SMS OTP is still better than password alone. 2FA should be used as an additional security layer and not as to weaken existing ones, such as using weak password or using the same password everywhere.&lt;/p&gt;

&lt;p&gt;Happy hacking! &lt;/p&gt;

</description>
      <category>security</category>
      <category>cryptography</category>
      <category>2fa</category>
      <category>u2f</category>
    </item>
    <item>
      <title>WebSockets bypassing SOP/CORS</title>
      <dc:creator>Peeyush Man Singh</dc:creator>
      <pubDate>Sat, 24 Jul 2021 00:16:42 +0000</pubDate>
      <link>https://forem.com/pssingh21/websockets-bypassing-sop-cors-5ajm</link>
      <guid>https://forem.com/pssingh21/websockets-bypassing-sop-cors-5ajm</guid>
      <description>&lt;h2&gt;
  
  
  Same-Origin-Policy (SOP)
&lt;/h2&gt;

&lt;p&gt;Same-Origin-Policy is a mechanism in browsers to protect the users from dynamically loaded document or script. It prevents running malicious scripts in browser to retrieve data from third party services. SOP specifies that dynamic requests can only be sent to URLs with the same Origin as the page they are requested from. Two URLs have the same origin if they share the same &lt;strong&gt;&lt;em&gt;protocol&lt;/em&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;em&gt;host&lt;/em&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;em&gt;port&lt;/em&gt;&lt;/strong&gt;. SOP assures that untrusted sites cannot perform authorized requests with the user's cookies, browser secrets or session identifiers by preventing requests to third parties. It only allows pages to call APIs in its own origin and blocks all other cross-origin requests. By default, modern browsers follow the SOP standards as a security mechanism.&lt;/p&gt;

&lt;p&gt;Example: A user visiting &lt;code&gt;https://untrustedsite.com&lt;/code&gt; prevents the site from calling &lt;code&gt;https://api.trustedsite.com&lt;/code&gt;. The untrusted site pretends to call the trusted site on behalf of the user or without the user's permission. Such requests are blocked by SOP.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cross-Origin-Resource-Sharing (CORS)
&lt;/h2&gt;

&lt;p&gt;While SOP is an important security measure, it also restricts legitimate cross-origin API calls. CORS relaxes the SOP so that it can be called from a trusted origin that is in a different domain than that of what is currently being called from. CORS policy informs the browser which domains are allowed to access the response object of a request, which HTTP methods are allowed and if cookies should be sent with requests. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The response header &lt;code&gt;Access-Control-Allow-Origin&lt;/code&gt; specifies which origins are allowed to access the response objects from cross-origin requests.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;Access-Control-Allow-Credentials&lt;/code&gt; specifies if cookies need to be attached. Boolean value.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;Access-Control-Allow-Methods&lt;/code&gt; and &lt;code&gt;Access-Contol-Allow-Headers&lt;/code&gt; header specifies which methods and headers are allowed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All requests made from the browser should have a &lt;code&gt;Origin&lt;/code&gt; header.&lt;/p&gt;

&lt;p&gt;Example: If &lt;code&gt;Access-Control-Allow-Origin: https://trustedclient.com&lt;/code&gt; is set on &lt;code&gt;https://api.trustedserver.com&lt;/code&gt;. Only the trusted client is able to access the response from the server. Calls from all other origins are blocked by the SOP.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Access-Control-Allow-Origin: *&lt;/code&gt; is set to grant resource access to all domains. &lt;/p&gt;

&lt;h2&gt;
  
  
  Preflight requests
&lt;/h2&gt;

&lt;p&gt;Since &lt;code&gt;Access-Control-Allow-Methods&lt;/code&gt; and &lt;code&gt;Access-Contol-Allow-Headers&lt;/code&gt; are response headers, there should first be a request made to fetch allowed methods and headers before sending out the actual request. Thus, browsers send a &lt;strong&gt;&lt;strong&gt;preflight request&lt;/strong&gt;&lt;/strong&gt;. The preflight request is an &lt;code&gt;OPTIONS&lt;/code&gt; request with the headers &lt;code&gt;Access-Control-Request-Method&lt;/code&gt; and &lt;code&gt;Origin&lt;/code&gt;. The API then responds with an empty response (HTTP 204) with the appropriate response headers. If the API does not implement CORS then the browser falls back to SOP and the cross-origin request is denied. Requests to resources on the same origin as the requesting site, however, are not preflighted and are also not subjected to SOP. &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests"&gt;Simple requests&lt;/a&gt; are also not preflighted, but do still require CORS headers to be set on response and will restrict access to response data if CORS policy does not allow.&lt;/p&gt;

&lt;h2&gt;
  
  
  WebSocket protocols (WS/WSS) and Cross-Site WebSocket Hijacking (CSWSH)
&lt;/h2&gt;

&lt;p&gt;Cross-origin restrictions imposed by SOP and CORS policies do not apply to WebSockets because those restrictions are placed on HTTP responses while WebSockets work over &lt;code&gt;WS&lt;/code&gt;(WebScoket) or &lt;code&gt;WSS&lt;/code&gt;(WebSocketSecure) protocols. To initiate a WebSocket connection, however, the client has to connect to the server over HTTP. Yet, SOP and CORS do not have any effect because no HTTP response data is required to complete WS handshake and data transfer afterwards is completely over the WebSocket protocol WS/WSS. The initial handshake occurs via &lt;code&gt;HTTP Upgrade&lt;/code&gt; request, the response body is disregarded and the &lt;code&gt;HTTP/HTTPS&lt;/code&gt; protocol is upgraded to &lt;code&gt;WS/WSS&lt;/code&gt; protocol. Since CORS only restricts access to response and SOP cannot restrict access on WebSocket protocol, attackers could potentially establish a cross-origin WS connection and send malicious data or receive data from a subscribed channel. If a webserver supports WebSockets, an attacker could create a cross-origin WS connection to the server. Even though the server does not respond with CORS header, WebSocket connection will be established if the server supports WebSockets and sends a &lt;code&gt;101 Switching Protocol&lt;/code&gt; status. From there on, the attacker can simply send and subscribe to data from the server. This is similar to &lt;code&gt;Cross-Site Request Forgery (CSRF)&lt;/code&gt; but is extended from write-only CSRF attack to full read/write communication via WebSockets.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Upgrade HTTP to WebSocket
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Connection: Upgrade
Upgrade: websocket
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;Upgrade&lt;/code&gt; header field is used by clients to switch protocols with the server. The server responds with &lt;code&gt;101 Switching Protocols&lt;/code&gt; response and the client-server can begin communicating in the new protocol. WebSockets is the most common use case for upgrading an HTTP connection.&lt;/p&gt;

&lt;h2&gt;
  
  
  Securing WebSockets
&lt;/h2&gt;

&lt;p&gt;Since SOP and CORS are ineffective for WebSockets, the server implementation should verify the &lt;code&gt;Origin&lt;/code&gt; header on the &lt;code&gt;Upgrade&lt;/code&gt; request to prevent cross-site WS connections.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;io&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;socket.io&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="nx"&gt;httpServer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;allowRequest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isOriginValid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isOriginValid&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Authentication/authorization should also be performed while establishing connection eg. via token.&lt;/p&gt;

&lt;p&gt;As a developer, it is necessary to be aware of this attack and to know how to prevent it.&lt;/p&gt;

&lt;p&gt;Happy Hacking!&lt;/p&gt;

</description>
      <category>cors</category>
      <category>sop</category>
      <category>ws</category>
      <category>wss</category>
    </item>
    <item>
      <title>Docker</title>
      <dc:creator>Peeyush Man Singh</dc:creator>
      <pubDate>Wed, 07 Jul 2021 09:36:43 +0000</pubDate>
      <link>https://forem.com/pssingh21/docker-97j</link>
      <guid>https://forem.com/pssingh21/docker-97j</guid>
      <description>&lt;h2&gt;
  
  
  What is Docker?
&lt;/h2&gt;

&lt;p&gt;Docker is a tool that allows developers to package applications and all their dependencies in a container (sandbox) and deploy and run the application on host operating system (Linux). &lt;/p&gt;

&lt;h2&gt;
  
  
  What are Containers, Images?
&lt;/h2&gt;

&lt;p&gt;A container is a discrete process that has been isolated from all other processes on the host machine. This is made possible by &lt;a href="https://medium.com/@saschagrunert/demystifying-containers-part-i-kernel-space-2c53d6979504"&gt;Kernel Namespaces and Cgroups&lt;/a&gt;. This decoupling allows applications to run consistently anywhere isolated from the rest of the applications. Containers run images, which contain everything required to run: application code, runtime environment, dependencies, scripts, etc. Containers run layers of stacked images (eg. a base linux image (mostly alpine due to its compact size), node image and application image on top). &lt;/p&gt;

&lt;h2&gt;
  
  
  Docker vs VMs
&lt;/h2&gt;

&lt;p&gt;Note that docker containers do not run in their own virtual machines. VMs run on virtual hardware provided by host OS, whereas containers share the host kernel, thus avoiding computation overhead for virtualizing hardware. Also note that Docker requires Linux runtime environment, so running Docker on Windows/Mac requires a single Linux virtual machine that is shared among all the containers run in the system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;Download and install docker from &lt;a href="https://docs.docker.com/get-docker/"&gt;Docker docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Check if installation was successful using&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Docker Hub
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://hub.docker.com/"&gt;Docker hub&lt;/a&gt; is the official public repository from docker hosting images of widely used applications. &lt;/p&gt;

&lt;h2&gt;
  
  
  Pull from docker repository
&lt;/h2&gt;

&lt;p&gt;Pull image from repository (by default Docker hub unless specified otherwise).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker pull redis
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  List all images
&lt;/h2&gt;

&lt;p&gt;View all locally available images.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker images
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker image &lt;span class="nb"&gt;ls&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Run container
&lt;/h2&gt;

&lt;p&gt;Creates a new container from an image, and execute the container. Pulls image from repository (Docker Hub) if container is not found locally. Notice that different layers are pulled separately from the repository. Splitting the layers provides the advantage that if some layers already exist locally, they are skipped from downloading again.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run postgres:9.6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run docker/whalesay cowsay Hello World!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run in detached mode. Returns id of the container and starts running the container.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; postgres:9.6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Re-attach detached container. Requires id of detached container.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker attach ee8f2eb0b433
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  docker ps
&lt;/h2&gt;

&lt;p&gt;View all currently running containers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker ps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;View all running and stopped containers (history). Containers can be restarted using the given container id.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker ps &lt;span class="nt"&gt;-a&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Stop container
&lt;/h2&gt;

&lt;p&gt;Stops the running container. Requires id/name of container. Returns id/name of stopped container.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker stop ee8f2eb0b433
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Start container
&lt;/h2&gt;

&lt;p&gt;Can be used to restart stopped container. Requires id/name of stopped container. Returns id/name of started container. It does not create a new container, unlike &lt;code&gt;docker run&lt;/code&gt;. All configurations are restored which were set while running &lt;code&gt;doc run&lt;/code&gt; command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker start ee8f2eb0b433
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Port Mapping [Host port : Container port]
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;docker ps&lt;/code&gt; displays the port the application is listening inside the container. To connect to this port inside the container, we need the IP the application is running in. Every Docker container gets an IP assigned by default. This is an internal IP and can only be accessed from the host machine. Users outside of the docker host cannot access using this IP. For this, we need to use the IP of the docker host and map a free port from the docker host to the container port. You can also run multiple instances of application and map them to different ports on the host machine.&lt;/p&gt;

&lt;p&gt;There should be a binding between the host port and container port. Conflicts will occur if you open two same ports on your host machine. Different containers can however listen on the same port because these two containers are completely isolated of one another.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-p6000&lt;/span&gt;:6379 redis
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Port 6000 of host machine is binded with port 6379 of container running redis. Redis runs on port 6479. This can be viewed using &lt;code&gt;docker ps&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Display logs
&lt;/h2&gt;

&lt;p&gt;View logs of docker container (eg. while using in detached mode). Requires id/name of running container.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker logs 777f0e06c4c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker logs 777f0e06c4c | &lt;span class="nb"&gt;tail&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Custom naming containers
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; my-custom-name redis
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  docker exec
&lt;/h2&gt;

&lt;p&gt;Get the terminal of the running container as a root user. &lt;code&gt;-it&lt;/code&gt; stands for interactive terminal. &lt;code&gt;-i&lt;/code&gt; maps the standard input of the host to the Docker container. &lt;code&gt;-t&lt;/code&gt; stands for pseudo terminal,which displays prompts from the terminal. Requires id/name of container. You can even navigate around the virtual file system, check logs, manage environment, etc.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; 777f0e06c4c /bin/sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec &lt;/span&gt;777f0e06c4c &lt;span class="nb"&gt;cat&lt;/span&gt; /etc/hosts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Docker network
&lt;/h2&gt;

&lt;p&gt;Docker creates it's own isolated network where the containers are running in. When two containers are deployed in the same docker network, they can refer to each other using just the container name because they are in the same network. Applications running outside of docker connect to this network using localhost:port-number. &lt;/p&gt;

&lt;h2&gt;
  
  
  Display docker networks
&lt;/h2&gt;

&lt;p&gt;Displays all docker networks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker network &lt;span class="nb"&gt;ls&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create new docker network
&lt;/h2&gt;

&lt;p&gt;Creates new docker network&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker network create my-network
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Docker run with network option
&lt;/h2&gt;

&lt;p&gt;To run containers in custom docker network, it should be specified in the docker run command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-p27017&lt;/span&gt;:27017 &lt;span class="se"&gt;\ &lt;/span&gt;
&lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;MONGO_INITDB_ROOT_USERNAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;admin &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;MONGO_INITDB_ROOT_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;password &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--name&lt;/span&gt; mongodb &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--net&lt;/span&gt; my-network &lt;span class="se"&gt;\&lt;/span&gt;
mongo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-p8081&lt;/span&gt;:8081 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;ME_CONFIG_MONGODB_ADMINUSERNAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;admin &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;ME_CONFIG_MONGODB_ADMINPASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;password &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--net&lt;/span&gt; my-network &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--name&lt;/span&gt; mongo-express &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;ME_CONFIG_MONGODB_SERVER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;mongodb &lt;span class="se"&gt;\&lt;/span&gt;
mongo-express

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

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;-e&lt;/code&gt; sets the required environment variables.&lt;/p&gt;

&lt;h2&gt;
  
  
  Docker inspect
&lt;/h2&gt;

&lt;p&gt;View details of a container in JSON format such as mounts, configuration settings, network settings, etc. Requires id/name of container.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker inspect dreamy_hellman
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Docker Compose
&lt;/h2&gt;

&lt;p&gt;With docker compose, docker commands can be mapped to a file, so that configurations are well structured. Note that format of Docker-compose yaml file depends on the version of docker-yaml.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3'&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;mongodb&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mongo&lt;/span&gt;
        &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;27017:27017&lt;/span&gt;
        &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;MONGO_INITDB_ROOT_USERNAME=admin&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;MONGO_INITDB_ROOT_PASSWORD=password&lt;/span&gt;
    &lt;span class="na"&gt;mongo-express&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mongo-express&lt;/span&gt;
        &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;8080:8081&lt;/span&gt;
        &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ME_CONFIG_MONGODB_ADMINUSERNAME=admin&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ME_CONFIG_MONGODB_ADMINPASSWORD=password&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ME_CONFIG_MONGODB_SERVER=mongodb&lt;/span&gt;
        &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;mongodb&lt;/span&gt;


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

&lt;/div&gt;



&lt;p&gt;The network configuration is not included in docker compose. Docker compose will automatically create a common network for all services listed in the docker compose file. Save it as a .yaml file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Docker compose yaml file
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Start a container
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose &lt;span class="nt"&gt;-f&lt;/span&gt; my-docker-compose-file.yaml up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Stop a container
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose &lt;span class="nt"&gt;-f&lt;/span&gt; my-docker-compose-file.yaml down
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Dockerfile
&lt;/h2&gt;

&lt;p&gt;A dockerfile is a document for building images. Filename must be &lt;code&gt;Dockerfile&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node&lt;/span&gt;

&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; MONGO_INITDB_ROOT_USERNAME=admin \&lt;/span&gt;
    MONGO_INITDB_ROOT_PASSWORD=password

&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /home/app

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . /home/app&lt;/span&gt;

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /home/app&lt;/span&gt;

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["node","server.js"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;FROM&lt;/code&gt; &lt;em&gt;image&lt;/em&gt; - build on a base image&lt;br&gt;
&lt;code&gt;ENV&lt;/code&gt; - set environment variables&lt;br&gt;
&lt;code&gt;RUN&lt;/code&gt; - execute any Linux commands on the container environment&lt;br&gt;
&lt;code&gt;COPY&lt;/code&gt; - executes on the host. Copies file from host to the container&lt;br&gt;
&lt;code&gt;WORKDIR&lt;/code&gt; - set current working directory so that you don't need to provide full path from /home.&lt;br&gt;
&lt;code&gt;CMD&lt;/code&gt; - executes an entry point. There can be multiple RUN commands, but only one CMD command. The command and parameters should be separate entries in the list.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; ubuntu&lt;/span&gt;

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; sleep 5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running &lt;code&gt;docker run sleeper sleep 10&lt;/code&gt;, the &lt;code&gt;sleep 10&lt;/code&gt; will overwrite the command specified on &lt;code&gt;CMD&lt;/code&gt;. To provide custom arguments, use the &lt;code&gt;ENTRYPOINT&lt;/code&gt; command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; ubuntu&lt;/span&gt;

&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["sleep"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running &lt;code&gt;docker run sleeper 10&lt;/code&gt; will append the argument &lt;code&gt;10&lt;/code&gt; to the list of &lt;code&gt;ENTRYPOINT&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;To set a default value for argument, use the combination of both &lt;code&gt;ENTRYPOINT&lt;/code&gt; and &lt;code&gt;CMD&lt;/code&gt;. Both &lt;code&gt;ENTRYPOINT&lt;/code&gt; and &lt;code&gt;CMD&lt;/code&gt; should be specified in JSON format.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; ubuntu&lt;/span&gt;

&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["sleep"]&lt;/span&gt;

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["5"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If no arguments is provieded, argument from &lt;code&gt;CMD&lt;/code&gt; will be appended to &lt;code&gt;ENTRYPOINT&lt;/code&gt;. If arguments are provided, they will be appended to &lt;code&gt;ENTRYPOINT&lt;/code&gt; and the values on &lt;code&gt;CMD&lt;/code&gt; will be disregarded. You can also overwrite the whole entrypoint command using&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--entrypoint&lt;/span&gt; somethine-else sleeper 10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Building image from Dockerfile
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; my-app:1.0 &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;my-app - image name&lt;br&gt;
1.0 - tag&lt;br&gt;
. - path to &lt;code&gt;Dockerfile&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Delete image
&lt;/h2&gt;

&lt;p&gt;Remove image from local host. Requires image id. Image id can be found running &lt;code&gt;docker images&lt;/code&gt;. Image can be deleted if all containers built from the image are deleted.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker rmi e455275b486c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Delete container
&lt;/h3&gt;

&lt;p&gt;Remove container from local host. Requires container id/name. Container id/name can be found running &lt;code&gt;docker ps&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;rm &lt;/span&gt;silly_gagarin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Data persistence using Docker volumes
&lt;/h3&gt;

&lt;p&gt;Data from virtual file system of container is lost when the container is restarted or removed. Docker volumes is used where changes needs to be persisted between restarts. Using Docker volumes, a folder in the physical file system is mounted in the virtual file system of the container. The data is automatically replicated between host file system and virtual file system. Thus, data is persisted even when the container is turned down. &lt;/p&gt;

&lt;h2&gt;
  
  
  Docker Volume types
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Host volumes
&lt;/h3&gt;

&lt;p&gt;Host volumes allows you to determine where on the host file system the data is replicated.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-v&lt;/span&gt; /home/mount/data:/var/lib/mysql/data
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is in the form host-file-system-path:virtual-file-system-path.&lt;/p&gt;

&lt;h3&gt;
  
  
  Anonymous Volumes
&lt;/h3&gt;

&lt;p&gt;Only path in the virtual file system is provided. Docker automatically maintains where in the host file system the replica should reside. For each container, a folder is generated in the host file system path &lt;code&gt;/var/lib/docker/volumes/{hash}/_data&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-v&lt;/span&gt; /var/lib/mysql/data
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Named Volumes
&lt;/h3&gt;

&lt;p&gt;This is similar to anonymous volumes, but you can specify the name of the folder on the host file system. This type of volume can be referenced simply using the name, so you don't have to know the path.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-v&lt;/span&gt; name:/var/lib/mysql/data
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Volumes in docker-compose
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3'&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;mongodb&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mongo&lt;/span&gt;
        &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;27017:27017&lt;/span&gt;
        &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;MONGO_INITDB_ROOT_USERNAME=admin&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;MONGO_INITDB_ROOT_PASSWORD=password&lt;/span&gt;
        &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;my-volume:/data/db&lt;/span&gt;
    &lt;span class="na"&gt;mongo-express&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mongo-express&lt;/span&gt;
        &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;8080:8080&lt;/span&gt;
        &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ME_CONFIG_MONGODB_ADMINUSERNAME=admin&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ME_CONFIG_MONGODB_ADMINPASSWORD=password&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ME_CONFIG_MONGODB_SERVER=mongodb&lt;/span&gt;
&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;my-volume&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;driver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;local&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that here we have used named volumes. Also note that we can mount the reference of the same folder on the host file system to more than one container, for example if the containers need to share the same data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Container Orchestration
&lt;/h2&gt;

&lt;p&gt;Container orchestration contains of multiple docker hosts that can host containers, so that if one fails, the application is still available through the others. Some orchestration solutions can help automatically scale up the number of container instances when users increase and scale down when the demand decreases. They also help in load balancing requests across hosts. Some container orchestration solutions are docker swarm, kubernetes and mesos.&lt;/p&gt;

&lt;p&gt;Happy Hacking!&lt;/p&gt;

</description>
      <category>docker</category>
      <category>devops</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Safe Navigation Operator? Bang! Bang Bang!!</title>
      <dc:creator>Peeyush Man Singh</dc:creator>
      <pubDate>Fri, 12 Mar 2021 18:51:31 +0000</pubDate>
      <link>https://forem.com/pssingh21/safe-navigation-operator-bang-bang-bang-192j</link>
      <guid>https://forem.com/pssingh21/safe-navigation-operator-bang-bang-bang-192j</guid>
      <description>&lt;h1&gt;
  
  
  Safe Navigation Operator
&lt;/h1&gt;

&lt;p&gt;Safe navigation operator or optional chaining is now available in JavaScript and TypeScript &amp;gt;= v3.7🎉.&lt;/p&gt;

&lt;p&gt;It provides easy access to deeply nested values, so checking for &lt;code&gt;nullish&lt;/code&gt; (&lt;code&gt;undefined&lt;/code&gt; or &lt;code&gt;null&lt;/code&gt;) values is simplified. We avoid hitting the classic JavaScript error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;Uncaught&lt;/span&gt; &lt;span class="nt"&gt;TypeError&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nt"&gt;Cannot&lt;/span&gt; &lt;span class="nt"&gt;read&lt;/span&gt; &lt;span class="nt"&gt;property&lt;/span&gt; &lt;span class="s2"&gt;'foo'&lt;/span&gt; &lt;span class="nt"&gt;of&lt;/span&gt; &lt;span class="nt"&gt;undefined&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A common workaround would be to short-circuit using the &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; operator. However, this would quickly unwind to long repetitive chains if we need to check for a deeply nested object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A lodash solution might look like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;b.c.d[0]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The safe navigation operator approach looks like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Returns &lt;code&gt;undefined&lt;/code&gt; if the value does not exist.&lt;/p&gt;

&lt;p&gt;This approach is recommended since it has now been added to the language and is browser supported. //! Except Internet Explorer&lt;/p&gt;

&lt;p&gt;This also works with function calls, array indexes and chaining dynamic expressions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="c1"&gt;//accessing object property&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;?.[&lt;/span&gt;&lt;span class="nx"&gt;expr&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;//accessing through dynamic expression&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;?.[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;//accessing array index&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;?.(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;//conditional function call&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Warning: This operator is not valid on the left-hand-side of an assignment operator.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;const&lt;/span&gt; &lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="nc"&gt;.b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nt"&gt;foo&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="nt"&gt;Invalid&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: &lt;code&gt;?.&lt;/code&gt; acts differently than &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; operator, since the &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; operator acts on &lt;code&gt;falsy&lt;/code&gt; values(including &lt;code&gt;0&lt;/code&gt;, &lt;code&gt;NaN&lt;/code&gt;, &lt;code&gt;""&lt;/code&gt;, &lt;code&gt;false&lt;/code&gt;), but &lt;code&gt;?.&lt;/code&gt; acts on &lt;code&gt;nullish&lt;/code&gt; values (&lt;code&gt;null&lt;/code&gt; and &lt;code&gt;undefined&lt;/code&gt;).&lt;/p&gt;

&lt;h1&gt;
  
  
  TypeScript Bang! (non-null assertion operator)
&lt;/h1&gt;

&lt;p&gt;Warning: &lt;code&gt;!.&lt;/code&gt; is not the same as &lt;code&gt;?.&lt;/code&gt; . The &lt;code&gt;!&lt;/code&gt; postfix expression is valid in TypeScript &amp;gt;= v2.0. The &lt;code&gt;a!&lt;/code&gt; operator produces a value &lt;code&gt;a&lt;/code&gt; with &lt;code&gt;null&lt;/code&gt; and &lt;code&gt;undefined&lt;/code&gt; excluded. Meaning, this will explicitly tell the compiler that you are sure the type of value is not &lt;code&gt;null&lt;/code&gt; or &lt;code&gt;undefined&lt;/code&gt;. The compiler will thus not check if the value is &lt;code&gt;null&lt;/code&gt; or &lt;code&gt;undefined&lt;/code&gt; in compile time.&lt;/p&gt;

&lt;p&gt;This could come in handy while working with maps.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;key&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;key&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, the compiler does not keep track that map.has() has been evaluated while evaluating map.get(). So the compiler can't determine if the map returns a safe value. &lt;/p&gt;

&lt;p&gt;This can also be used in terms of calling a possibly undefined function and array indexes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;func&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example it could be used when using React refs. When using refs, the current value may be null if the element is unmounted.&lt;/p&gt;

&lt;h1&gt;
  
  
  JavaScript Bang! (prefix operator)
&lt;/h1&gt;

&lt;p&gt;In JavaScript every value is assocaiated as either a &lt;code&gt;truthy&lt;/code&gt; value or a &lt;code&gt;falsy&lt;/code&gt; value. So, a bang(&lt;code&gt;!&lt;/code&gt;) as a prefix on a value acts as a logical "not" operator on that value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;//returns false&lt;/span&gt;
&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;//returns true&lt;/span&gt;

&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="c1"&gt;//returns false&lt;/span&gt;
&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="c1"&gt;//returns false&lt;/span&gt;

&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="c1"&gt;//returns true&lt;/span&gt;
&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="kc"&gt;NaN&lt;/span&gt; &lt;span class="c1"&gt;//returns true&lt;/span&gt;
&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="c1"&gt;//returns true&lt;/span&gt;
&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="c1"&gt;//returns true&lt;/span&gt;

&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="c1"&gt;//returns false (points to a reference)&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bar&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;foo&lt;/span&gt; &lt;span class="c1"&gt;//returns false&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;baz&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;baz&lt;/span&gt; &lt;span class="c1"&gt;//returns true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  JavaScript Bang Bang!!
&lt;/h1&gt;

&lt;p&gt;Since a bang (&lt;code&gt;!&lt;/code&gt;) acts as a logical "not" on a value, a double bang negates the result of the logical "not" operation. So, a double bang will first change the value to a boolean opposite, and return the opposite of that. In other words, it converts any value into a boolean type. &lt;/p&gt;

&lt;p&gt;Note: The &lt;code&gt;!&lt;/code&gt; operator operates on &lt;code&gt;truthy&lt;/code&gt; and &lt;code&gt;falsy&lt;/code&gt; values and is not limited to &lt;code&gt;nullish&lt;/code&gt; values. So, &lt;code&gt;!''&lt;/code&gt; should resolve to &lt;code&gt;true&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="c1"&gt;//returns true&lt;/span&gt;
&lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="c1"&gt;//returns false&lt;/span&gt;

&lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="c1"&gt;//returns false&lt;/span&gt;
&lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="c1"&gt;//returns false&lt;/span&gt;
&lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="kc"&gt;NaN&lt;/span&gt; &lt;span class="c1"&gt;//returns false&lt;/span&gt;

&lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="mi"&gt;34&lt;/span&gt; &lt;span class="c1"&gt;//returns true&lt;/span&gt;
&lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="c1"&gt;//returns false&lt;/span&gt;

&lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;foo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;//returns true&lt;/span&gt;
&lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt; &lt;span class="c1"&gt;//returns false&lt;/span&gt;

&lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;foo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;//returns true&lt;/span&gt;
&lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="c1"&gt;//returns true (points to a reference)&lt;/span&gt;

&lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;//returns true&lt;/span&gt;
&lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="c1"&gt;//returns true (points to a reference)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Happy Hacking!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>typescript</category>
    </item>
    <item>
      <title>PWA Caching Strategies</title>
      <dc:creator>Peeyush Man Singh</dc:creator>
      <pubDate>Sun, 27 Dec 2020 21:54:56 +0000</pubDate>
      <link>https://forem.com/pssingh21/pwa-caching-strategies-1d7c</link>
      <guid>https://forem.com/pssingh21/pwa-caching-strategies-1d7c</guid>
      <description>&lt;p&gt;Caching strategies determine how a PWA behaves when the app makes a network request and how it deals with network failures. Workbox is a commonly used library for creating PWA; &lt;code&gt;workbox-strategies&lt;/code&gt; provides the following caching strategies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stale-While-Revalidate
&lt;/h2&gt;

&lt;p&gt;The service worker will serve the cached assets first, and update the cache with the latest version afterwards. On cache-hit, it responds to the request as quickly as possible. On cache-miss, the request falls back to network request. The response from network request is then used to update the cache. This strategy is useful in situation where receiving a response has higher priority over having most up-to-date results.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cache First
&lt;/h2&gt;

&lt;p&gt;The service worker will serve the cached assets and will only query the network if the cache is not available. On cache-hit, it will not update the cache in background; the network will not be used at all. On cache-miss, the request will be sent over the network and the response will be cached. The next request will then be served from the cache. This strategy is useful for requests for static assets, which do not change frequently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If no caching strategy is defined, Workbox will use Cache First as default.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Network First
&lt;/h2&gt;

&lt;p&gt;The service worker will by default try to fetch the response over the network. If the network request fails, it will serve the response from the cache. On successful response over the network, it will cache the response for future use. This strategy can be useful in requests that update frequently. &lt;/p&gt;

&lt;h2&gt;
  
  
  Network Only
&lt;/h2&gt;

&lt;p&gt;The service worker will always query the network for response. This can be useful if you require to query the network strictly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cache only
&lt;/h2&gt;

&lt;p&gt;The service worker will always query the cache for response. You need to make sure that you pre-cache resources before requesting. This strategy is less used in practice.&lt;/p&gt;

&lt;h1&gt;
  
  
  Example Usage
&lt;/h1&gt;

&lt;p&gt;On your &lt;code&gt;service-worker.ts&lt;/code&gt;, add a custom strategy for a fetch event.&lt;br&gt;
Note: You could also define custom events for different fetch requests by filtering depending on URL origin or path.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { StaleWhileRevalidate } from "workbox-strategies";

...

//! Stale-While-Revalidate for all fetch events
self.addEventListener("fetch", (event) =&amp;gt; {
    const { request } = event;

    event.respondWith(new StaleWhileRevalidate().handle({ event, request }));
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Workbox also allows you to define custom strategies. All of these strategies also allow you to configure name of cache, cache expiration and an array of additional workbox plugins.&lt;/p&gt;

&lt;p&gt;Happy Hacking!&lt;/p&gt;

</description>
      <category>pwa</category>
      <category>javascript</category>
      <category>typescript</category>
      <category>react</category>
    </item>
    <item>
      <title>PWA Metadata in manifest.json</title>
      <dc:creator>Peeyush Man Singh</dc:creator>
      <pubDate>Fri, 25 Dec 2020 19:30:25 +0000</pubDate>
      <link>https://forem.com/pssingh21/pwa-metadata-in-manifest-json-3j2m</link>
      <guid>https://forem.com/pssingh21/pwa-metadata-in-manifest-json-3j2m</guid>
      <description>&lt;p&gt;Every PWA should have a manifest file, a JSON file specifying metadata of the app. Manifest.json is required to add PWA to the homescreen. It defines how the app should look like and configures the app's behavior on launch.&lt;/p&gt;

&lt;p&gt;You can find the &lt;code&gt;manifest.json&lt;/code&gt; file in &lt;code&gt;public/&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;It should be linked in &lt;code&gt;public/index.html&lt;/code&gt; by default.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;link rel="manifest" href="%PUBLIC_URL%/manifest.json" /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Details on manifest.json config
&lt;/h1&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;short_name&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;Name of your app on home screen.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;name&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;Name of app used on prompt while installing. If not present, short_name will be used.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;icons&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;It is an array of image objects that is displayed in the home screen. Each of the object in the array must have properties &lt;code&gt;src&lt;/code&gt;, &lt;code&gt;sizes&lt;/code&gt; and &lt;code&gt;type&lt;/code&gt;. You may need to add additional property &lt;code&gt;"purpose": "any maskable"&lt;/code&gt; for android devices. For Chrome, you need to provide icons of size 192x192 and 512x512 for auto scaling of icons. They are provided by default while creating PWA with create-react-app. &lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;start_url&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;The home URL of page, so that it does not start from the page the user used to add the app to home screen. By default, it is set to &lt;code&gt;.&lt;/code&gt;(home directory). You may modify it according to your needs.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;display&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;It customizes the browser view for your app. It can take the following values:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;fullscreen&lt;/em&gt;: Open the app in full screen. Browser UI such as address bar and navigation are hidden. Android status bar is also hidden. &lt;/li&gt;
&lt;li&gt;
&lt;em&gt;standalone&lt;/em&gt;: The app runs in its own window, separate from the browser. Browser UI elements like address bar and navigation are hidden. Android status bar is not hidden. &lt;/li&gt;
&lt;li&gt;
&lt;em&gt;minimal-ui&lt;/em&gt;: It is similar to the standalone mode, but minimal set of UI elements for controlling navigation are displayed. However, the UI elements may differ from browser to browser. &lt;/li&gt;
&lt;li&gt;
&lt;em&gt;browser&lt;/em&gt;: Standard browser behavior. All browser UI are displayed. However, "Add to Home screen" is not displayed.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;theme_color&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;Sets the color of browser toolbar. It also displays this color in browser tabs while tab switching.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;background_color&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;Color to be displayed in splash screen when the app is first launched. &lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;scope&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;Defines the scope of PWA. If the user navigates out of scope, the page will be served as a normal site. The start_url should be inside of scope. If the user clicks on a link outside of the scope, it will be rendered in the PWA. To open a outside link on a browser window, add &lt;code&gt;target="_blank"&lt;/code&gt; to the anchor tag. &lt;br&gt;
If the scope is a relative path, the base location will be where the manifest file is located.&lt;/p&gt;

&lt;h1&gt;
  
  
  Testing manifest.json
&lt;/h1&gt;

&lt;p&gt;To test if your manifest.json is setup correctly, use the Chrome dev tools. In application section, navigate to Manifest subsection. &lt;/p&gt;

&lt;p&gt;Happy Hacking!&lt;/p&gt;

</description>
      <category>pwa</category>
      <category>typescript</category>
      <category>javascript</category>
      <category>react</category>
    </item>
    <item>
      <title>PWA with create-react-app</title>
      <dc:creator>Peeyush Man Singh</dc:creator>
      <pubDate>Thu, 24 Dec 2020 22:35:02 +0000</pubDate>
      <link>https://forem.com/pssingh21/pwa-with-create-react-app-2ihf</link>
      <guid>https://forem.com/pssingh21/pwa-with-create-react-app-2ihf</guid>
      <description>&lt;h1&gt;
  
  
  Setting up PWA with create-react-app and typescript.
&lt;/h1&gt;

&lt;p&gt;Install create-react-app if you haven't already.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i create-react-app -g
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a react app with TypeScript and PWA support. Also, we are using NPM as package manager. Alternatively, you may use yarn.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;create-react-app frontend --use-npm --template cra-template-pwa-typescript
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To build the project run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To run the build folder, we are using http-server. You may use any server. &lt;/p&gt;

&lt;p&gt;Install http-server if you haven't already.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i http-server -D
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add script scripts section of package.json file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"scripts": {
    ...
    "start-sw": "http-server ./build"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To run the script, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm run start-sw
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Go to the browser and type the url with the associated port number.&lt;/p&gt;

&lt;p&gt;To check the status of service workers, open chrome dev tools. Under the application section, go to "service workers" subsection.&lt;br&gt;
If no service workers are registered, you need to enable them in the code.&lt;/p&gt;

&lt;p&gt;Navigate to index.tsx and change &lt;code&gt;serviceWorkerRegistration.unregister();&lt;/code&gt; to &lt;code&gt;serviceWorkerRegistration.register();&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;Rebuild the project and restart the server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm run build &amp;amp;&amp;amp; npm run start-sw
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you should see registered service workers.&lt;/p&gt;

&lt;p&gt;You may also try stopping the server and reloading the site, or use chrome dev tools on Application section to simulate offline mode. Check the Offline checkbox on the Service workers section.&lt;/p&gt;

&lt;p&gt;The site should reload without displaying a "No internet" error message.&lt;/p&gt;

&lt;p&gt;Happy Hacking!&lt;/p&gt;

</description>
      <category>pwa</category>
      <category>typescript</category>
      <category>javascript</category>
      <category>react</category>
    </item>
    <item>
      <title>Internationalization using React-i18next legacy version (v9)</title>
      <dc:creator>Peeyush Man Singh</dc:creator>
      <pubDate>Fri, 10 Jul 2020 14:09:59 +0000</pubDate>
      <link>https://forem.com/pssingh21/internationalization-using-react-i18next-legacy-version-v9-e2p</link>
      <guid>https://forem.com/pssingh21/internationalization-using-react-i18next-legacy-version-v9-e2p</guid>
      <description>&lt;h1&gt;
  
  
  What is i18next?
&lt;/h1&gt;

&lt;p&gt;i18next is a popular framework for internationalization. React-i18next is the version of i18next for React applications.&lt;/p&gt;

&lt;h1&gt;
  
  
  Why legacy version React-i18next?
&lt;/h1&gt;

&lt;p&gt;To use the latest version of React-i18next, the requirements are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;react &amp;gt;= v16.8.0&lt;/li&gt;
&lt;li&gt;react-dom &amp;gt;= v16.8.0&lt;/li&gt;
&lt;li&gt;react-native &amp;gt;= v0.59.0&lt;/li&gt;
&lt;li&gt;i18next &amp;gt;= v10.0.0(typescript users: &amp;gt;= v17.0.9)&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Requirements for React-i18next v9
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;react &amp;gt;= v0.14.0&lt;/li&gt;
&lt;li&gt;i18next &amp;gt;= v2.0.0&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Installation
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install react-i18next@legacy i18next --save
npm install i18next-browser-languagedetector --save
npm install i18next-xhr-backend --save
npm install i18next --save
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For TypeScript users, install the type definitions manually.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Warning: Type definitions for &lt;code&gt;i18next-xhr-backend&lt;/code&gt; and &lt;code&gt;i18next-browser-languagedetector&lt;/code&gt; are deprecated.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install @types/i18next-xhr-backend --save
npm install @types/i18next-browser-languagedetector --save
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Folder structure
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;i18n-project/
├── src/
│   ├── components/
│   │   ├── component1/
│   │   │   ├── locales/
│   │   │   │   ├── default.de.json
│   │   │   │   └── default.en.json
│   │   │   └── Component1.tsx
│   │   ├── component2/
│   │   │   ├── locales/
│   │   │   │   ├── default.de.json
│   │   │   │   └── default.en.json
│   │   │   └── Component2.tsx
│   │   └── App.tsx
│   ├── i18n/
│   │   ├── locales/
│   │   │   ├── default.de.json
│   │   │   ├── default.en.json
│   │   │   └── index.tsx
│   │   └── index.tsx
│   ├── types/
│   │   └── module.d.ts
│   └── index.tsx
│
├── package.json
└── tsconfig.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Configure TypeScript to import JSON files
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;i18n-project/src/types/module.d.ts&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;declare&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;*.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;any&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;i18n-project/tsconfig.json&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;compilerOptions&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
        &lt;span class="p"&gt;...&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;resolveJsonModule&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Initialize main translation files
&lt;/h1&gt;

&lt;p&gt;All other translation files are later concatenated onto the main translation file as we will see later.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;i18n-project/src/i18n/locales/default.de.json&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;de&lt;/span&gt;&lt;span class="dl"&gt;"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;i18n-project/src/i18n/locales/default.en.json&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  i18next Configuration file
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;i18n-project/src/i18n/index.tsx&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;i18n&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;i18next&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;detector&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;i18next-browser-languagedetector&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Backend&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;i18next-xhr-backend&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;de&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;en&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./locales&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;i18n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Backend&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;detector&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;//Browser Language Detector&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;init&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;interpolation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;escapeValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;

        &lt;span class="na"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

        &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;de&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;common&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;de&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;de&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;en&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;common&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;en&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;en&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;

        &lt;span class="na"&gt;fallbackLng&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;//Fallback Language: English&lt;/span&gt;

        &lt;span class="na"&gt;ns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;common&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;

        &lt;span class="na"&gt;defaultNS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;common&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

        &lt;span class="na"&gt;react&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;bindI18n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;languageChanged loaded&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;bindStore&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;added removed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;nsMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;default&lt;/span&gt;&lt;span class="dl"&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;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;i18n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Setup provider in App
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;i18n-project/src/index.tsx&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;ReactDOM&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-dom&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Provider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-redux&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;I18nextProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-i18next&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;i18n&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./i18n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;ReactDOM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;I18nextProvider&lt;/span&gt; &lt;span class="na"&gt;i18n&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;i18n&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt; &lt;span class="na"&gt;store&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            ...
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;I18nextProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;,&lt;/span&gt;
    &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Configure local translation files for each component
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;i18n-project/src/components/component1/locales/default.de.json&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;de&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;header&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Willkommen in Comp1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;body&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Comp1 ist auf Deutsch.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;i18n-project/src/components/component1/locales/default.en.json&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;header&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Welcome in Comp1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;body&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Comp1 is in English.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;i18n-project/src/components/component2/locales/default.de.json&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;de&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;header&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Willkommen in Comp2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;link&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Comp2 ist auf &amp;lt;1&amp;gt;Deutsch&amp;lt;/1&amp;gt;.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;i18n-project/src/components/component2/locales/default.en.json&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;header&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Welcome in Comp2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;link&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Comp2 is in &amp;lt;1&amp;gt;English&amp;lt;/1&amp;gt;.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Notice we used &lt;code&gt;&amp;lt;1&amp;gt;...&amp;lt;/1&amp;gt;&lt;/code&gt; tags to feature Trans component. To learn more about the numbering, checkout this fantastic resource:&lt;/em&gt;&lt;br&gt;
&lt;a href="https://github.com/arkross/arkross.github.io/wiki/Using-react-i18next-Trans-Component"&gt;https://github.com/arkross/arkross.github.io/wiki/Using-react-i18next-Trans-Component&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  Change constants from each component to load from i18n
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;i18n-project/src/components/component1/Component1.tsx&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;i18n&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./../../i18n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;Component1&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PureComponent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;...,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;render&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="p"&gt;(&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;i18n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Component1.header&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;i18n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Component1.body&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;i18n-project/src/components/component2/Component2.tsx&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;i18n&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./../../i18n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Trans&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-i18next&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;Component2&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PureComponent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;...,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;render&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="p"&gt;(&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;i18n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Component2.header&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Trans&lt;/span&gt; &lt;span class="na"&gt;i18nKey&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Component2.link"&lt;/span&gt; &lt;span class="na"&gt;i18n&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;i18n&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                Comp2 is in &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;English&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;.
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Trans&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Notice we used &lt;code&gt;&amp;lt;a&amp;gt;...&amp;lt;/a&amp;gt;&lt;/code&gt; tags in place of &lt;code&gt;&amp;lt;1&amp;gt;...&amp;lt;/1&amp;gt;&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Combine all translation files onto main translation file
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;i18n-project/src/i18n/locales/index.tsx&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;de&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;any&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./default.de.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;en&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;any&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./default.en.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Component1De&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./../../components/component1/locales/default.de.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Component1En&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./../../components/component1/locales/default.en.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Component2De&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./../../components/component2/locales/default.de.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Component2En&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./../../components/component2/locales/default.en.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="nx"&gt;de&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;de&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;Component1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Component1&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;de&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="nx"&gt;en&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;Component1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Component1&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="nx"&gt;de&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;de&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;Component2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Component2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;de&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="nx"&gt;en&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;Component2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Component2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en&lt;/span&gt;&lt;span class="dl"&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;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;de&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;en&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Language Change feature (optional)
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;i18next-project/src/components/component-of-your-choice&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;i18n&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./../i18n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ChangeLngState&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;language&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;ChangeLng&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;...,&lt;/span&gt; &lt;span class="nx"&gt;ChangeLngState&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;i18n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;language&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Input&lt;/span&gt;
                    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"select"&lt;/span&gt;
                    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"language"&lt;/span&gt;
                    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"language"&lt;/span&gt;
                    &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;languageChanged&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                    &lt;span class="na"&gt;defaultValue&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getDefaultValue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;option&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Deutsch&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;option&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;option&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;English&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;option&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onApply&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                    Apply
                &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        );
    }

    languageChanged(event: any) &lt;span class="si"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Deutsch&lt;/span&gt;&lt;span class="dl"&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;de&lt;/span&gt;&lt;span class="dl"&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;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
            &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="si"&gt;}&lt;/span&gt;

    getDefaultValue() &lt;span class="si"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i18n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;language&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;de&lt;/span&gt;&lt;span class="dl"&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Deutsch&lt;/span&gt;&lt;span class="dl"&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;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;English&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="si"&gt;}&lt;/span&gt;

    onApply() &lt;span class="si"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i18n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;language&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;language&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;i18n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;changeLanguage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;language&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reload&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="si"&gt;}&lt;/span&gt;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  &lt;strong&gt;&lt;em&gt;Bonus: Change title according to language&lt;/em&gt;&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;i18next-project/src/components/App.tsx&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;i18n&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./../i18n&lt;/span&gt;&lt;span class="dl"&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;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;componentDidMount&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&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="nx"&gt;i18n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;language&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;de&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Titel auf Deutsch&lt;/span&gt;&lt;span class="dl"&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;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Title in English&lt;/span&gt;&lt;span class="dl"&gt;"&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="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;h1&gt;
  
  
  Advantages of using this approach
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Translations can be split into multiple files for multiple languages.&lt;/li&gt;
&lt;li&gt;Translation files are split for every component inside the component folder.&lt;/li&gt;
&lt;li&gt;Automatic browser default language detection.&lt;/li&gt;
&lt;li&gt;Change language with ease.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Drawbacks of the approach
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;React version must be greater than 16.8.0 to use latest version of i18next.&lt;/li&gt;
&lt;li&gt;Splitted translations should be combined in a main translation file.&lt;/li&gt;
&lt;li&gt;Translation keys must match exactly for translation to work.&lt;/li&gt;
&lt;li&gt;All translation keys must exist on fallback language.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  References:
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Official documentation for React-i18next legacy version: &lt;a href="https://react.i18next.com/legacy-v9/step-by-step-guide"&gt;https://react.i18next.com/legacy-v9/step-by-step-guide&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Language codes can be found in:
&lt;a href="https://www.w3.org/International/O-charset-lang.html"&gt;https://www.w3.org/International/O-charset-lang.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/rd-shipit/internationalizing-a-front-end-application-88f1baae3d82"&gt;https://medium.com/rd-shipit/internationalizing-a-front-end-application-88f1baae3d82&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Github: &lt;a href="https://github.com/pssingh21"&gt;https://github.com/pssingh21&lt;/a&gt;&lt;br&gt;
&lt;code&gt;#first_post&lt;/code&gt;😉&lt;/p&gt;

</description>
      <category>react</category>
      <category>typescript</category>
      <category>i18next</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
