<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Wildan Mubarok</title>
    <description>The latest articles on DEV Community by Wildan Mubarok (@willnode).</description>
    <link>https://dev.to/willnode</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%2F252792%2F91582ba6-26b9-4240-8581-4cbb857ab723.jpeg</url>
      <title>DEV Community: Wildan Mubarok</title>
      <link>https://dev.to/willnode</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/willnode"/>
    <language>en</language>
    <item>
      <title>How to upload any website to the Internet, quickly</title>
      <dc:creator>Wildan Mubarok</dc:creator>
      <pubDate>Thu, 13 Jul 2023 21:33:27 +0000</pubDate>
      <link>https://dev.to/willnode/how-to-upload-any-website-to-the-internet-quickly-1nio</link>
      <guid>https://dev.to/willnode/how-to-upload-any-website-to-the-internet-quickly-1nio</guid>
      <description>&lt;p&gt;So you have created a website on your computer? Great! Now, we come to the following problem: how to make it accessible to the public?&lt;/p&gt;

&lt;p&gt;There are many great options for web hosting (we call them PaaS), and they also offer a free account to get you started without losing any money.&lt;/p&gt;

&lt;p&gt;I created a PaaS where it should take less than ten clicks (less than 10 minutes) to set up any website over the Internet. Let's get it started:&lt;/p&gt;

&lt;h2&gt;
  
  
  First Step: Create an Account
&lt;/h2&gt;

&lt;p&gt;Go to &lt;a href="https://domcloud.co/"&gt;domcloud.co&lt;/a&gt; and create an account using Google/GitHub Sign In. With 3rd party sign-in, you don't have to confirm your email to get in.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zQjJ7fjw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1688796071509/00f1478e-1506-4294-9d52-2389b7c8e6fd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zQjJ7fjw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1688796071509/00f1478e-1506-4294-9d52-2389b7c8e6fd.png" alt="" width="800" height="486"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After that, a welcome page will be shown. Click &lt;strong&gt;Create a Website&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FvCUBi9V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1688797291551/46331f2d-e9ae-4c9b-9e88-5f6f55370a66.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FvCUBi9V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1688797291551/46331f2d-e9ae-4c9b-9e88-5f6f55370a66.png" alt="" width="600" height="496"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Uploading a website
&lt;/h2&gt;

&lt;p&gt;This page contains two modes: &lt;strong&gt;Start from a template&lt;/strong&gt; or &lt;strong&gt;Upload or clone from the Internet&lt;/strong&gt;. We choose the latter.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mXU0BWKq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1688797721389/0df3417a-2377-4639-872e-7687833c1732.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mXU0BWKq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1688797721389/0df3417a-2377-4639-872e-7687833c1732.png" alt="" width="800" height="478"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The next step is to drop your project folder into the uploader, then choose what's the kind of framework you're using in that project, &lt;a href="https://www.youtube.com/shorts/0WFk-qh2Cc0"&gt;like in the video below&lt;/a&gt;. It will generate a script about how the project will be initiated.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/0WFk-qh2Cc0"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Then fill in the unique name, website region, also with a custom domain name (if you own one), then click &lt;strong&gt;Add a website&lt;/strong&gt;. (Read more about &lt;a href="https://domcloud.co/docs/features/dns"&gt;using a custom domain&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FBgzgC37--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1688853801710/a524aadc-f117-4763-81d5-c5dce2beb73b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FBgzgC37--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1688853801710/a524aadc-f117-4763-81d5-c5dce2beb73b.png" alt="" width="581" height="700"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Done!
&lt;/h2&gt;

&lt;p&gt;The next screen tells the progress as it happens in almost real-time. It should only take a few minutes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--r7ZjzjxY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://domcloud.co/assets/ss/new-progress-b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--r7ZjzjxY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://domcloud.co/assets/ss/new-progress-b.png" alt="" width="800" height="523"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After it is finished, your website should be accessible over the Internet!&lt;/p&gt;

&lt;h2&gt;
  
  
  Continue Editing
&lt;/h2&gt;

&lt;p&gt;Continue editing the website online via tools like an online file browser and Visual Studio Code remote development using SSH (my favorite). &lt;a href="https://domcloud.co/docs/intro/getting-started#managing-website"&gt;Read more about it in the documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If your website setup comes into a problem, there is &lt;a href="https://domcloud.co/blog/improving-ux-for-newbies#connection-check-api"&gt;a tool to check its connection&lt;/a&gt;. It should be able to troubleshoot common HTTPS and DNS problems.&lt;/p&gt;

&lt;p&gt;This tutorial doesn't cover database migration, but some framework scripts do already handle that (check the script!). If in the end, your website has a database problem, you might need to initiate the database yourself. &lt;a href="https://domcloud.co/docs/features/database/"&gt;Check the documentation&lt;/a&gt; for that.&lt;/p&gt;

&lt;p&gt;That's it! I hope this brings new excitement into learning website development. Let me know what you think about it 🤓&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Stuck Trying to Migrate from CentOS Linux to Rocky Linux after EOL?</title>
      <dc:creator>Wildan Mubarok</dc:creator>
      <pubDate>Mon, 31 Jan 2022 13:23:01 +0000</pubDate>
      <link>https://dev.to/willnode/stuck-trying-to-migrate-from-centos-linux-to-rocky-linux-after-eol-2b2e</link>
      <guid>https://dev.to/willnode/stuck-trying-to-migrate-from-centos-linux-to-rocky-linux-after-eol-2b2e</guid>
      <description>&lt;p&gt;So CentOS Linux is &lt;a href="https://blog.centos.org/2020/12/future-is-centos-stream/"&gt;already passed their End of Life&lt;/a&gt; and I forgot to migrate my system to &lt;a href="https://rockylinux.org/"&gt;Rocky Linux&lt;/a&gt;. What could be worse?&lt;/p&gt;

&lt;p&gt;I run &lt;a href="https://github.com/rocky-linux/rocky-tools/tree/main/migrate2rocky"&gt;the migration script today&lt;/a&gt; and I encountered this pellicular error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Error: Error downloading packages:  No URLs in mirrorlist
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---GRcVzhE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0nbkoyi6tlogys5x6tmz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---GRcVzhE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0nbkoyi6tlogys5x6tmz.png" alt="Error screenshot" width="734" height="575"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I thought it was just a random network error, well it also failed with &lt;code&gt;dnf update&lt;/code&gt;. Things go dark from here.&lt;/p&gt;

&lt;p&gt;After a few hours of trial and error debugging the network. I successfully fixed it by changing the CentOS' YUM repo server to one of the mirror servers. What this is means is that the canonical  CentOS YUM repo server list (&lt;code&gt;mirrorlist.centos.org&lt;/code&gt;) is simply no longer be usable anymore and we need to change it to one of the usable mirrors left in the world.&lt;/p&gt;

&lt;p&gt;One of the mirrors that worked for me when I wrote this is &lt;code&gt;http://repo.uk.bigstepcloud.com/centos-vault/&lt;/code&gt;. There are lots of other mirrors to choose from &lt;a href="https://mirror-status.centos.org/"&gt;listed here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To change the CentOS YUM repo server used, you need to modify these files using &lt;code&gt;vim&lt;/code&gt; or &lt;code&gt;nano&lt;/code&gt; (your list may be more or less, you need to check which yum repos enabled in your machine using &lt;code&gt;yum repolist --enabled&lt;/code&gt;) :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/etc/yum.repos.d/CentOS-Linux-AppStream.repo
/etc/yum.repos.d/CentOS-Linux-BaseOS.repo
/etc/yum.repos.d/CentOS-Linux-Extras.repo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You need to comment out the &lt;code&gt;mirrorlist&lt;/code&gt; and uncomment the &lt;code&gt;baseurl&lt;/code&gt; with changing the mirror base URL. The changes are done like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="err"&gt;[baseos]&lt;/span&gt;
name=CentOS Linux $releasever - BaseOS
&lt;span class="gd"&gt;- mirrorlist=http://mirrorlist.centos.org/?release=$releasever&amp;amp;arch=$basearch&amp;amp;repo=BaseOS&amp;amp;infra=$infra
&lt;/span&gt;&lt;span class="gi"&gt;+ #mirrorlist=http://mirrorlist.centos.org/?release=$releasever&amp;amp;arch=$basearch&amp;amp;repo=BaseOS&amp;amp;infra=$infra
&lt;/span&gt;&lt;span class="gd"&gt;- #baseurl=http://mirrorlist.centos.org/$contentdir/$releasever/BaseOS/$basearch/os/
&lt;/span&gt;&lt;span class="gi"&gt;+ baseurl=http://repo.uk.bigstepcloud.com/centos-vault/$contentdir/$releasever/BaseOS/$basearch/os/
&lt;/span&gt;&lt;span class="p"&gt;gpgcheck=1
enabled=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I run the migration system again and things work so well. guess I need to share this small tip so I can save someone else's hours haha. Hope it is useful!&lt;/p&gt;




&lt;p&gt;Blog Changes 2022-02-02: Prepended path &lt;code&gt;/centos-vault/&lt;/code&gt; to the mirror URL.&lt;/p&gt;

</description>
      <category>linux</category>
    </item>
    <item>
      <title>The most reliable way to avoid relative imports in Node.js</title>
      <dc:creator>Wildan Mubarok</dc:creator>
      <pubDate>Fri, 15 Oct 2021 08:52:23 +0000</pubDate>
      <link>https://dev.to/willnode/the-most-reliable-way-to-avoid-relative-imports-in-nodejs-334n</link>
      <guid>https://dev.to/willnode/the-most-reliable-way-to-avoid-relative-imports-in-nodejs-334n</guid>
      <description>&lt;p&gt;Writing relative imports in Node.js is something I tend to avoid especially when it's growing larger in functionality. However, For something this basic yet it's so hard to get right. There are just many ways of doing that on the internet.&lt;/p&gt;

&lt;p&gt;There are many ways to avoid relative imports in Node.js. One of them is either:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add &lt;code&gt;NODE_PATH=./&lt;/code&gt; env ( &lt;a href="https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders"&gt;reference&lt;/a&gt; )&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;"baseUrl"&lt;/code&gt; in &lt;code&gt;(js|ts)config.json&lt;/code&gt; ( &lt;a href="https://dev.to/ruppysuppy/how-pros-get-rid-of-relative-imports-in-js-ts-2i3f"&gt;reference&lt;/a&gt; )&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;require.main.require&lt;/code&gt; ( &lt;a href="https://stackoverflow.com/a/26163910/3908409"&gt;reference&lt;/a&gt; )&lt;/li&gt;
&lt;li&gt;Directly write into &lt;code&gt;node_modules&lt;/code&gt; ( &lt;a href="https://github.com/browserify/browserify-handbook#avoiding-"&gt;reference&lt;/a&gt; )&lt;/li&gt;
&lt;li&gt;Use NPM/Yarn workspaces  ( &lt;a href="https://classic.yarnpkg.com/lang/en/docs/workspaces/"&gt;reference&lt;/a&gt; )&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There are many downsides to each approach.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Adding an environment variable requires adding &lt;code&gt;cross-env NODE_PATH=./&lt;/code&gt; to all &lt;code&gt;package.json&lt;/code&gt; scripts and every time you need to run the script yourself. This behavior is also somewhat unreliable during my testing, also VSCode Intellisense won't understand what you're trying to import.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;baseUrl&lt;/code&gt; option from &lt;code&gt;(js|ts)config.json&lt;/code&gt; seems to work out of the box, only for VSCode Intellisense. Node.JS won't understand them so I need a babel compiler to set up, it's  &lt;a href="https://medium.com/weekly-webtips/say-good-bye-relative-imports-in-nodejs-projects-65513bcdae6c"&gt;explained here anyway&lt;/a&gt; but to me, this is way too complicated. &lt;/li&gt;
&lt;li&gt;Using &lt;code&gt;require.main.require&lt;/code&gt; seems like a hack to me, it enforces me to use that in all the scripts rather than the usual &lt;code&gt;require&lt;/code&gt;, which of course it's something that I don't like.&lt;/li&gt;
&lt;li&gt;Directly writing to &lt;code&gt;node_modules&lt;/code&gt; is something against its purpose, also would you rather be willing to move your scripts to mode_modules? I wouldn't want it. It would become a nightmare to maintain.&lt;/li&gt;
&lt;li&gt;Using NPM/Yarn workspaces seems promising at first glance but it enforces me to thinking in the way it was designed for "monorepo". Monorepo is good if you have multiple projects that share code, but really it's just too much because I just work on one big node app. Note this was Yarn only feature, NPM add support too but my last experience using it was &lt;a href="https://github.com/npm/cli/issues/3637#issuecomment-898975594"&gt;buggy&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I have found a less popular but way more reliable: &lt;code&gt;symlink-dir&lt;/code&gt;. Let's me summarize their explanation on &lt;a href="https://www.npmjs.com/package/symlink-dir"&gt;NPM&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Lets suppose you'd like to self-require your package. You can link it to its own node_modules:&lt;br&gt;
&lt;code&gt;symlink-dir . node_modules/my-package&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What is by mean to "link"? It's basically creating a directory shortcut. You can &lt;a href="https://www.freecodecamp.org/news/symlink-tutorial-in-linux-how-to-create-and-remove-a-symbolic-link/"&gt;read it more here&lt;/a&gt;. NPM/Yarn workspaces internally also doing this way. &lt;/p&gt;

&lt;p&gt;So to use &lt;code&gt;symlink-dir&lt;/code&gt;, I just need to add these values in &lt;code&gt;package.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"postinstall"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"symlink-dir src node_modules/src"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; 
  &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"symlink-dir"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"latest"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a symlink from &lt;code&gt;src&lt;/code&gt; folder to &lt;code&gt;node_modules&lt;/code&gt; in my project. After &lt;code&gt;npm i&lt;/code&gt; I can use &lt;code&gt;require('src/module.js')&lt;/code&gt; instead of  &lt;code&gt;require('../../../src/module.js')&lt;/code&gt;. Works with ESM imports too!&lt;/p&gt;

&lt;p&gt;You can also add more symlinks by just appending the &lt;code&gt;postinstall&lt;/code&gt; like &lt;code&gt;"symlink-dir src node_modules/src &amp;amp;&amp;amp; symlink-dir lib node_modules/src/libraries"&lt;/code&gt; and redoing &lt;code&gt;npm i&lt;/code&gt;. Out of all solutions previously, this method works best to me. Hope you like it too!&lt;/p&gt;

</description>
      <category>node</category>
      <category>javascript</category>
    </item>
    <item>
      <title>One code liner in Python 🐍</title>
      <dc:creator>Wildan Mubarok</dc:creator>
      <pubDate>Wed, 08 Sep 2021 23:11:31 +0000</pubDate>
      <link>https://dev.to/willnode/one-code-liner-in-python-1k3l</link>
      <guid>https://dev.to/willnode/one-code-liner-in-python-1k3l</guid>
      <description>&lt;p&gt;During college, my lecturer gave me a task to find the shortest code to create this string using python:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;****
***
**
*
**
***
****
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So how you would do that? Here's a typical code in Python we end up:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'*'&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'*'&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For those who wonder, &lt;code&gt;range(a, b, c)&lt;/code&gt; creates an iterator loop from &lt;code&gt;a&lt;/code&gt; to &lt;code&gt;b&lt;/code&gt;  by &lt;code&gt;c&lt;/code&gt;. the &lt;code&gt;a&lt;/code&gt; is inclusive but &lt;code&gt;b&lt;/code&gt; is not. If &lt;code&gt;c&lt;/code&gt; is 1, you can omit it since it's the default anyway. Thus &lt;code&gt;range(4, 1, -1)&lt;/code&gt; generates &lt;code&gt;[4,3,2]&lt;/code&gt; while &lt;code&gt;range(1, 5)&lt;/code&gt; generates &lt;code&gt;[1,2,3,4]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;And then we take that &lt;code&gt;i&lt;/code&gt; to multiply with &lt;code&gt;'*'&lt;/code&gt; because python multiplication with string causes that string to be repeated &lt;code&gt;i&lt;/code&gt; times, e.g.  &lt;code&gt;'*' * 3&lt;/code&gt; generates &lt;code&gt;'***'&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This is already short in fact 😅 that's really awesome about Python, isn't it?&lt;/p&gt;

&lt;p&gt;But wait, there's more! We can reduce our python code into one single &lt;code&gt;for&lt;/code&gt; loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&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="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'*'&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;i&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;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'*'&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What does this code do? It transforms &lt;code&gt;[1,2,3,4,5,6,7]&lt;/code&gt; to &lt;code&gt;[4,3,2,1,2,3,4]&lt;/code&gt; so then we took these values to get multiplied by &lt;code&gt;*&lt;/code&gt;. If it takes a while to grasp why I put these values on, I'll try to explain here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# i &amp;lt; 4
&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;
&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="c1"&gt;# else (i &amp;gt;= 4)
&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Okay, but why do we do this? It seems didn't make our code shorter, right?&lt;/p&gt;

&lt;p&gt;That's why we need to do some math here. Enter the absolute function:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3JkDk_f4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1631113620710/O2-9x7sQP.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3JkDk_f4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1631113620710/O2-9x7sQP.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How does this absolute function help us? Well, with some fitting on the equation, we get this graph:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.google.com/search?q=abs%28x+-+4%29+%2B+1"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6tlHrO8t--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1631114170643/C1KPRGkmZ.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(click the image to see interactive version)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This graph does what we want, transforms &lt;code&gt;[1,2,3,4,5,6,7]&lt;/code&gt; to &lt;code&gt;[4,3,2,1,2,3,4]&lt;/code&gt; with a single equation. Math is powerful 💪.&lt;/p&gt;

&lt;p&gt;This is the code now looks like after we implement the equation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'*'&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Luckily python has &lt;code&gt;abs()&lt;/code&gt; &lt;a href="https://docs.python.org/3/library/functions.html#abs"&gt;built-in&lt;/a&gt; without importing any modules. This reduces our code lines from 5 to 2 💪.&lt;/p&gt;

&lt;p&gt;But does this can get further decreased to 1 line? Yes 😱&lt;/p&gt;

&lt;p&gt;But before that, we have to put the &lt;code&gt;print()&lt;/code&gt; function outside the loop. This can be done with a temporary variable that holds the whole string in a loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'*'&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we hold the loop value to a variable named &lt;code&gt;output&lt;/code&gt; and use that to print &lt;code&gt;output&lt;/code&gt; once. Note that we use &lt;code&gt;'\n'.join(output)&lt;/code&gt; which converts the array to string with &lt;code&gt;\n&lt;/code&gt; between values. &lt;code&gt;\n&lt;/code&gt; simply means a new line, for each string, we add during for loop.&lt;/p&gt;

&lt;p&gt;But why this makes our code more verbose? Enter Python's killer feature: List Comprehension.&lt;/p&gt;

&lt;p&gt;List Comprehension simply means doing a loop within a single line. Effectively makes a loop became a python expression. What this means for a layman is they allow us to convert this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;variable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="n"&gt;variable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;variable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;expression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three lines into one! Doesn't that awesome? 😎&lt;/p&gt;

&lt;p&gt;This is our final code after the list comprehension:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s"&gt;'*'&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)]))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's really short, isn't it? Of course, this code is not readable as we are beginning with 😅 but hey, we do this for fun 💪 also these pieces of stuff are also useful for machine code optimization (if you're into that).&lt;/p&gt;

&lt;p&gt;Anyway, if you're familiar with code golfing, you can get the lowest of all codes within 55 characters in Python by removing unneeded whitespace:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s"&gt;'*'&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)]))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Anyone can beat that? 😅 Hope this useful 💪&lt;/p&gt;

</description>
      <category>python</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to Redirect a domain only using DNS records</title>
      <dc:creator>Wildan Mubarok</dc:creator>
      <pubDate>Sun, 22 Aug 2021 12:26:00 +0000</pubDate>
      <link>https://dev.to/willnode/how-to-redirect-a-domain-only-using-dns-records-1l6b</link>
      <guid>https://dev.to/willnode/how-to-redirect-a-domain-only-using-dns-records-1l6b</guid>
      <description>&lt;p&gt;At some point in time to want to move your website to a new domain address but don't want people with existing URL links to your old domain to find your content is no longer found, so then you need to set up a redirect link.&lt;/p&gt;

&lt;p&gt;I thought this was easy, but turns out it isn't. You need a separate server for that. Who would want to purchase additional bucks just to set up a server to redirect links?&lt;/p&gt;

&lt;p&gt;So let's meet &lt;a href="https://forwarddomain.net"&gt;forwarddomain.net&lt;/a&gt;, a simple redirect service.&lt;/p&gt;

&lt;p&gt;All you need to do to use this service is to add CNAME and some TXT records, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;www&lt;/span&gt;.&lt;span class="n"&gt;old&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;     &lt;span class="n"&gt;IN&lt;/span&gt;    &lt;span class="n"&gt;CNAME&lt;/span&gt;   &lt;span class="n"&gt;r&lt;/span&gt;.&lt;span class="n"&gt;forwarddomain&lt;/span&gt;.&lt;span class="n"&gt;net&lt;/span&gt;
&lt;span class="err"&gt;_&lt;/span&gt;.&lt;span class="n"&gt;www&lt;/span&gt;.&lt;span class="n"&gt;old&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;   &lt;span class="n"&gt;IN&lt;/span&gt;    &lt;span class="n"&gt;TXT&lt;/span&gt;     &lt;span class="n"&gt;forward&lt;/span&gt;-&lt;span class="n"&gt;domain&lt;/span&gt;=&lt;span class="n"&gt;https&lt;/span&gt;://&lt;span class="n"&gt;old&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;/*
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will redirect all links from &lt;code&gt;www.old.com&lt;/code&gt; to &lt;code&gt;old.com&lt;/code&gt;. You can also redirect other domains, just change the &lt;code&gt;forward-domain=&lt;/code&gt; part.&lt;/p&gt;

&lt;p&gt;In case you want to redirect a root or apex domain, you can't do that with CNAME, so you can use an A record that directly bind to the IP address of this service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;old&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;     &lt;span class="n"&gt;IN&lt;/span&gt;    &lt;span class="n"&gt;A&lt;/span&gt;       &lt;span class="m"&gt;167&lt;/span&gt;.&lt;span class="m"&gt;172&lt;/span&gt;.&lt;span class="m"&gt;5&lt;/span&gt;.&lt;span class="m"&gt;31&lt;/span&gt;
&lt;span class="err"&gt;_&lt;/span&gt;.&lt;span class="n"&gt;old&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;   &lt;span class="n"&gt;IN&lt;/span&gt;    &lt;span class="n"&gt;TXT&lt;/span&gt;     &lt;span class="n"&gt;forward&lt;/span&gt;-&lt;span class="n"&gt;domain&lt;/span&gt;=&lt;span class="n"&gt;https&lt;/span&gt;://&lt;span class="n"&gt;new&lt;/span&gt;.&lt;span class="n"&gt;net&lt;/span&gt;/*
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it! this will redirect all links from &lt;code&gt;old.com&lt;/code&gt; to &lt;code&gt;new.net&lt;/code&gt;. Note the &lt;code&gt;*&lt;/code&gt; part? it means also forward URL paths and GET query data.&lt;/p&gt;

&lt;p&gt;What about the email? It is used to signing HTTPS certificates from Let's Encrypt. This should be your valid public email. HTTPS redirection would not work without it.&lt;/p&gt;

&lt;p&gt;This is all you need to be able to set up domain redirection of your old domain. No coding required, no registration required, completely free and anonymous. You can also see the &lt;a href="https://github.com/willnode/forward-domain"&gt;GitHub repo&lt;/a&gt; since it's an open-source project anyway.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;EDIT 2021-09-21: This post is updated for &lt;a href="https://github.com/willnode/forward-domain/blob/main/CHANGES.md"&gt;v2.0 changes&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>microservices</category>
      <category>showdev</category>
    </item>
    <item>
      <title>5 Basic Things you need to know about managing a Linux server</title>
      <dc:creator>Wildan Mubarok</dc:creator>
      <pubDate>Wed, 30 Jun 2021 00:58:37 +0000</pubDate>
      <link>https://dev.to/willnode/5-basic-things-you-need-to-know-about-managing-a-linux-server-12fh</link>
      <guid>https://dev.to/willnode/5-basic-things-you-need-to-know-about-managing-a-linux-server-12fh</guid>
      <description>&lt;p&gt;As a web developer, you may come up with the situation of needing to set up a Virtual Machine to host your website online. While it's great that we have a variety of managed cloud services to lift this complexity for us, it's not a bad thing if we want to learn about some basic knowledge of setting up your own server. In fact, I come across this situation, and having this kind of knowledge is essential to me, especially when running a small project all by yourself or run with a tight budget.&lt;/p&gt;

&lt;p&gt;Without further ado, let's start:&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Use a web hosting control panel
&lt;/h2&gt;

&lt;p&gt;This is true, especially if you don't familiar with the Linux tools or come from a Windows background. There's a lot of setup and maintenance hurdles that come when you start to manage your own server. And definitely, you don't want to memorize all the things using only the terminal! So to lift this up, we need to install this piece of software.&lt;/p&gt;

&lt;p&gt;While there are some popular options like cPanel or Plesk, it comes with string (price) attached. So we need to use the free one, and &lt;a href="https://www.virtualmin.com/"&gt;Virtualmin&lt;/a&gt;, to me, is just perfect.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://www.virtualmin.com/documentation/installation/automated"&gt;installation step&lt;/a&gt; is easy too. I won't cover them all here but all it needs to do is run this command (as root):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wget http://software.virtualmin.com/gpl/scripts/install.sh
&lt;span class="nb"&gt;chmod &lt;/span&gt;0700 ./install.sh
sh ./install.sh &lt;span class="nt"&gt;--bundle&lt;/span&gt; LEMP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do you see that? I put &lt;code&gt;--bundle LEMP&lt;/code&gt; because I prefer to install Nginx over Apache. Whatever the choice is up to you but overall Nginx is way faster than Apache because of its simple configuration and event-driven, and you need those (the webserver) anyway to let it handle the heavy lifting of managing your app processes. &lt;/p&gt;

&lt;p&gt;I'll discuss these later but one thing you need to know is installing Virtualmin or any of these &lt;strong&gt;will destroy any existing setup on your server&lt;/strong&gt; so only install it when your VM or server is a fresh install.&lt;/p&gt;

&lt;p&gt;But then, what happens after the installation? Head to &lt;code&gt;https://&amp;lt;Your IP address&amp;gt;:10000&lt;/code&gt; to open Webmin portal (yes, Virtualmin is part of Webmin). &lt;/p&gt;

&lt;p&gt;You may encounter some SSL issues but skip it, it's fine. Login with root account and password that &lt;a href="https://www.virtualmin.com/documentation/installation/automated#toc-setting-a-root-password-KTINPhGW"&gt;you've set up&lt;/a&gt;, then follow the initial setup and create a new domain. Voila, you're done! No need to learn the hassle of creating a non-root user in a terminal and tries to synchronize everything overnight!&lt;/p&gt;

&lt;p&gt;Sounds good? Let's continue.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Know how to run your app properly
&lt;/h2&gt;

&lt;p&gt;Chances are you already know how to start your own local server. You may do the same thing on your VM but it will be a bad, bad idea. For an online server that needs to run 24 hours 7 days a week, you need some sort of proxy that protects your app processes from randomly crashing due to fatal crashes or high flood of traffic, and this proxy is what Nginx (or Apache) really does. What these proxies really do is they're run the actual HTTP(S) port on 80 and 443 and forward any incoming traffic to a local port or socket which your app really listens to. Web proxies also really good at dividing traffic based on domains (like domain A goes to this app then domain B goes to that app) and reporting or logging crashes of your app. Web proxies are just that awesome and you need to understand how to configure them properly, even though Virtualmin will already do the heavy lifting for you.&lt;/p&gt;

&lt;p&gt;After the installation of Nginx that comes from Virtualmin, you might be surprised that, it already comes with PHP support by default, like the usual way web hosting does. You can see how NginX config on a specific domain looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;server {
    server_name example.com;
    listen 1.2.3.4;
    listen 1.2.3.4:443 ssl;
    root /home/username/public_html;
    index index.html index.htm index.php;
    access_log /var/log/virtualmin/example.com_access_log;
    error_log /var/log/virtualmin/example.com_error_log;
    location ~ \.php(/|$) {
        try_files $uri =404;
        fastcgi_pass localhost:8001;
    }   
    ssl_certificate /home/username/ssl.combined;
    ssl_certificate_key /home/username/ssl.key;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see that it has the domain you want to listen to &lt;code&gt;example&lt;/code&gt;, the server IP to listen with &lt;code&gt;1.2.3.4&lt;/code&gt;, where the base directory is &lt;code&gt;/home/username/public_html&lt;/code&gt; and so on. What essential in NginX is that by default it only serves as a static web server. To make most of the features it gives you need to understand additional configs, like the &lt;code&gt;fastcgi_pass&lt;/code&gt; to enable dynamic processing on &lt;code&gt;.php&lt;/code&gt; files.&lt;/p&gt;

&lt;p&gt;PHP is great, but not for all of us. What about running Node.js or Python apps? You might be tempted to use &lt;code&gt;proxy_pass&lt;/code&gt; but it won't handle the app startup and crashes for us. Luckily we have a better option: &lt;a href="https://www.phusionpassenger.com/"&gt;Phusion Passenger&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What is that? That is the app server, which able to manage and automatically run Node.JS, Python, Ruby, well, all kinds of server apps you might need to run in your server, and it has an awesome integration with Nginx. &lt;/p&gt;

&lt;p&gt;After you follow &lt;a href="https://www.phusionpassenger.com/docs/tutorials/installation/node/"&gt;the installation step&lt;/a&gt;, all you need to do is add these options in &lt;a href="http://nginx.org/en/docs/beginners_guide.html"&gt;NginX config&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    root /home/username/public_html/public;
    passenger_enabled on;
    # for easier debugging!
    passenger_friendly_error_pages on;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will magically find any &lt;a href="https://www.phusionpassenger.com/library/config/nginx/reference/#passenger_startup_file"&gt;relevant startup file&lt;/a&gt; (like &lt;code&gt;app.js&lt;/code&gt; or &lt;code&gt;passenger_wsgi.py&lt;/code&gt;) in the parent root directory (&lt;code&gt;public_html&lt;/code&gt;) and boot the relevant process (of course, you need to already do have Node.js or whatever programming language you want to run with and already installing &lt;code&gt;node_modules&lt;/code&gt; or whatever code dependencies your app need beforehand).&lt;/p&gt;

&lt;p&gt;Can you run your app now? Great. Let's continue.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Overcoming DNS (and SSL) problems
&lt;/h2&gt;

&lt;p&gt;Your app runs on an IP public address now. Great! But nobody (even Google) wants to remember your IP address. You need to buy a domain yourself. I won't point out what's to recommend on this one so go buy a domain from whatever web hosting service you're already familiar with. But what I need to tell you is that after you buy a domain, you need to point out that domain to your server's IP address. This is done under "DNS Management" and in there, you can insert your server IP address using A record (and AAAA if care about IPv6), and that's it! &lt;/p&gt;

&lt;p&gt;But wait. There's more...&lt;/p&gt;

&lt;p&gt;DNS caches everything under the TTL (Time to Live), and by default for most services, it's set for about 4 hours (14400). You certainly don't want to wait 4 hours to just be able to see your new shiny website, right?&lt;/p&gt;

&lt;p&gt;While you can just bypass DNS using &lt;a href="https://man7.org/linux/man-pages/man5/hosts.5.html"&gt;hosts file&lt;/a&gt;, it's much better if you can go to &lt;a href="https://dns.google/"&gt;Google DNS resolver&lt;/a&gt; and see if Google itself picks up your new domain. It usually works for the first time without flushing their cache. (if it doesn't work, well something may wrong with your registrar?!).&lt;/p&gt;

&lt;p&gt;After you check it, if Google DNS resolver sees your IP address now but your device still won't pick up it, you can set your device DNS resolver to 8.8.8.8 and 8.8.4.4 (the &lt;a href="https://developers.google.com/speed/public-dns"&gt;Google Public DNS&lt;/a&gt;) and after that, it will certainly work. Yay!&lt;/p&gt;

&lt;p&gt;But wait. There's more (again!)...&lt;/p&gt;

&lt;p&gt;You can access your site using http:// but not https://, right? HTTPS is very important nowadays so you can't ignore it. But then, to do that, you need to sign your SSL certificates. I won't go into detail about why it works like that but what I need to tell you is that there's one and only kind of SSL agency there, it's called &lt;a href="https://letsencrypt.org/"&gt;Let's Encrypt&lt;/a&gt; and it will create a signed SSL certificate for your domain for free. How?&lt;/p&gt;

&lt;p&gt;Assuming you already have a correct configuration in your Nginx, with Virtualmin you can go to &lt;a href="https://www.youtube.com/watch?v=bUe9dJOnUV0"&gt;SSL certificate panel&lt;/a&gt; and send a request to Let's encrypt in a few clicks. Sound simple? Yes, but not just that. You can also make Virtualmin renew your SSL certificate automatically. Awesome, isn't it?&lt;/p&gt;

&lt;p&gt;Now your website should be online and can start gaining users. Congrats!&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Understand memory management (and when to panic)
&lt;/h2&gt;

&lt;p&gt;It's a regular evening and your server has been running for few weeks. Yet you look at the Virtualmin memory gauges of your server and start wondering. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WxMKtEWY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1gy9gjpdsm44l1tgp0qf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WxMKtEWY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1gy9gjpdsm44l1tgp0qf.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Usually, this will come in two situations:&lt;/p&gt;

&lt;h3&gt;
  
  
  Situation A: Your server is wasting resources
&lt;/h3&gt;

&lt;p&gt;You notice that your server only uses around 40% of memory so you think if you could cut the monthly bill in half by reducing its computing memory. Before it happens, I will tell you: don't do that! unless you're running into a budget problem.&lt;/p&gt;

&lt;p&gt;Even though it seems your system is wasting the excess memory, it's actually not. Linux will always &lt;a href="https://www.linuxatemyram.com/"&gt;use most of your RAM&lt;/a&gt; because of RAM cache. And you might wonder, what's the deal with it?&lt;/p&gt;

&lt;p&gt;Well, most operations on Linux rely heavily on files. The kernel is smart, when a process is done reading or writing a file, it's actually kept temporarily as RAM cache so when another process reads it the next time, it won't wait for the storage disk to actually perform the read, dramatically improving the overall system performance.&lt;/p&gt;

&lt;p&gt;I won't tell more details in this, but that's the whole point. Cutting your free memory will severely decrease the overall performance. Don't reduce it unless you have a problem with budgeting.&lt;/p&gt;

&lt;h3&gt;
  
  
  Situation B: Your server is heating
&lt;/h3&gt;

&lt;p&gt;Some users tell you slower loading times and some error pages show up significantly. How would you confirm what goes wrong? Firstly, you need to check the load. If the load metric is going like tens, it means your server can't keep up the traffic. Then you need to check your memory consumption by going to &lt;a href="https://man7.org/linux/man-pages/man1/free.1.html"&gt;free -m&lt;/a&gt;. The result is probably like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;              total        used        free      shared  buff/cache   available
Mem:           1817        1327          67          72         421         268
Swap:             0           0           0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you have low memory available, it means your server struggling to find more memory. You can increase the computation memory right now but it would be a bad idea if you actually turn off your VM during high traffic, so what you can do is &lt;a href="https://www.digitalocean.com/community/tutorials/how-to-add-swap-space-on-ubuntu-16-04"&gt;create a swap file&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A swap file is basically an additional memory attached to a storage disk. You might think it's a good idea to put a large swap file and suddenly your memory problem would go, but no. Because too much swapping could render the system unstable too.&lt;/p&gt;

&lt;p&gt;A better way to think about a swapfile is like a band-aid. During temporary traffic surges, Linux can put non-essential memory processes to swapfile so the actual memory can better spend on essential programs and frequently used RAM caches. For this to work, I recommend a swapfile about 1 or 2 GB size and &lt;a href="https://linuxhint.com/understanding_vm_swappiness/"&gt;swappiness&lt;/a&gt; around 30. &lt;/p&gt;

&lt;p&gt;But if you have already done these but still has low memory availability, yeah it's time to add more actual memory.&lt;/p&gt;

&lt;p&gt;I talked frequently about memory. While it's the most likely problem during high load, sometimes there's another factor too, like a rogue process running in the background or maybe there's just not enough core counts in your VM. A look at &lt;a href="https://man7.org/linux/man-pages/man1/top.1.html"&gt;top&lt;/a&gt; can help you a lot to diagnose this.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Protect your server with basic security and backup knowledge
&lt;/h2&gt;

&lt;p&gt;This is the final piece of advice that I need to tell you, as security and backups are so easy to overlook yet most people don't realize how important it is until it's too late.&lt;/p&gt;

&lt;p&gt;Good basic security of any VM serving the internet is to only allow specific inbound ports like SSH, HTTP(S), and any related port you might use. Most cloud providers already have a firewall config so it's good to use them if available. Or if it isn't you can use &lt;a href="https://firewalld.org/"&gt;firewalld&lt;/a&gt; or &lt;a href="https://linux.die.net/man/8/iptables"&gt;iptables&lt;/a&gt; to safeguard your traffic at kernel level. If you're like me who uses Webmin, you might want to change the port to something else as leaving the default 10000 probably would make it vulnerable to botnets that swarming the internet.&lt;/p&gt;

&lt;p&gt;If you have some memory and computation to spare, it might be a good idea to install software that prevents brute force attacks like &lt;a href="https://www.fail2ban.org/"&gt;Fail2Ban&lt;/a&gt;, or maybe just don't enable password-based login in SSH and disable database remote control when you don't need it.&lt;/p&gt;

&lt;p&gt;And lastly, do a frequent backup, as you probably don't aware of how things can be messed up certainly in the future. The good news is most cloud providers have a way to make a "snapshot" of your VM and allow you to schedule it weekly. It probably cost you an additional pennies but it totally worth it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;That is a lot of topics I discover. You might think, where do I get all those knowledge? Well, I have some background story that you might want to read, go &lt;a href="https://dev.to/willnode/i-generally-don-t-satisfied-with-all-web-hosting-out-there-2b63"&gt;check it out&lt;/a&gt; :)&lt;/p&gt;

</description>
      <category>linux</category>
      <category>server</category>
      <category>maintenance</category>
    </item>
    <item>
      <title>I generally don't satisfied with all web hosting out there</title>
      <dc:creator>Wildan Mubarok</dc:creator>
      <pubDate>Sat, 10 Apr 2021 05:12:10 +0000</pubDate>
      <link>https://dev.to/willnode/i-generally-don-t-satisfied-with-all-web-hosting-out-there-2b63</link>
      <guid>https://dev.to/willnode/i-generally-don-t-satisfied-with-all-web-hosting-out-there-2b63</guid>
      <description>&lt;p&gt;It's late spring 2020 and I still a student in my local university, yet pandemic comes to changes my life as I get bored in my home. So back then, I'm gone freelancing.&lt;/p&gt;

&lt;p&gt;As a starting discussion, I have decent experience in web development by self-learning and self-made projects (I can't rely on what I learn from my university as its pace is too slow). You can see those in &lt;a href="https://github.com/willnode"&gt;my GitHub profile&lt;/a&gt; but for now, let's continue the discussion.&lt;/p&gt;

&lt;p&gt;As a web developer and freelancer, it's quite common that I need a good web hosting provider for my future clients. From now on you might want to point me to some popular options like BlueHost or Hostinger. However, I won't go into that territory as I'm from a third-world country and one dollar is one freakin' huge. So I went looking for local web hosting which accepts my local money.&lt;/p&gt;

&lt;p&gt;After some digging, I concluded... Web development can't be cheap. I will tell you that the best option there cost about $2 a month (yes I did currency conversion for you) and the worst it, it's only on the first purchase (kind of a promo), the next (normal) bill cost about $7 a month, or $84 a year.&lt;/p&gt;

&lt;p&gt;That's freaking huge! I mean, I don't know if you, the first-world country readers here think $84 a year it's not a big deal, but considering $80 is a price I set to work on a WordPress (cheapest) website, how can the operational cost costs so much more than creating the website itself?&lt;/p&gt;

&lt;p&gt;(Okay, some of you might say, $80 is too cheap for web developers. Indeed, but as I said, I'm in the third-world country where I can survive with only $2 a day for meals and renting a room for $30 a month, I'm sure you can figure out everything else :) )&lt;/p&gt;

&lt;p&gt;But I have no choice, it's the best option out there, so I generally keep quiet about this as it's not my responsibility to pay the renewal anyway, and I'm fine with $2 a month for first pay, my clients would agree with me too (or maybe not, for the renewal).&lt;/p&gt;

&lt;p&gt;From here probably you would say there's nothing else to consider. But for me, it's not, it doesn't have the features I need. Well, maybe I just fine with WordPress, but what about, say, Laravel? which requires composer install. I have to open FTP and selectively transfer some files (god-what-knows if I miss some files) as there's no other way than, say, Git, which requires SSH access. &lt;/p&gt;

&lt;p&gt;Also, I asked support, they say they don't support other than PHP in shared hosting. They said if I want to run some other server apps, like Python or Node.js, I have to purchase VPS (virtual private server) which is very expensive last time I checked. Arrgghh! why just SSH access is so luxurious to get one? It doesn't make sense for a hobby project.&lt;/p&gt;

&lt;p&gt;I started to look around for platform companies like Heroku, Docker, or Vercel. At first glance, they sound promising and generous, but in execution, it's confusing at best. Wanna deploy something? I need to master the configuration files first. Wanna edit something? No, they won't give me FTP or SSH to edit files, I have to destroy and create a new deployment because that's how immutability works at the container level. And what about databases? No, they don't give me that either. So I stuck with shared hosting still.&lt;/p&gt;

&lt;p&gt;Because of all this, around late summer I decided to take a leap of faith.&lt;/p&gt;

&lt;h2&gt;
  
  
  "Fine! I'll do it myself!"
&lt;/h2&gt;

&lt;p&gt;I decided to run a hosting business.&lt;/p&gt;

&lt;p&gt;It's a kinda risky move, a bold move indeed. Since I still a student and know nothing about hosting or cloud businesses, I was thought I will go on-premise, buying all the hardware needed to run the business. But then, there is one major problem: I don't live in rural areas. I can't just rent some apartment and burning thousands of dollars for a risky startup, I don't have that much money anyway. So where do I start? No idea. Eventually, I posted my concerns on social media. I was thinking about giving up because of the sheer amount of money required to run a hosting company (and maybe the reasons why they can't be cheap).&lt;/p&gt;

&lt;p&gt;Luckily, one of my colleagues replies to my post with "why don't you use cloud services?". It struck my head with a flash of enlightenment. I went looking and researching between the three cloud computing giants: AWS, GCP, and Azure. I decided to go with Azure because they are listed in GitHub Education Program (remember, I still a student) and Azure are the cheapest between the three.&lt;/p&gt;

&lt;p&gt;To my surprise, cloud services today are so cheap, compared when doing those on on-premise. The best thing about it, it scales by budget. This is interesting to me, as suddenly creating a hosting business became way easier. All I do for the next three months is developing the new server and the software to manage hosts (from now I call this software, "portal"). From here, things get interesting.&lt;/p&gt;

&lt;h2&gt;
  
  
  So Cheap it can be Free
&lt;/h2&gt;

&lt;p&gt;The first thing in my mind, can it provide a free option? There's nothing that can beat a free option of course, and a free hosting option is rare anyway. And to my surprise, it's possible. But the road to get there is kind of rough. &lt;/p&gt;

&lt;p&gt;The first thing that I have to consider is the web panel. Most hosting providers came with cPanel, and I was about to install it until it came to my surprise that cPanel usage came with a paywall of about $0.2 per user per month, which is unacceptable if I want to provide a free hosting option. So look for alternatives, then found Virtualmin which comparatively has the same features.&lt;/p&gt;

&lt;p&gt;Virtualmin is awesome, it has a builtin file &amp;amp; database manager, storage and bandwidth usage, support Apache or Nginx web server, MySQL (MariaDB) or PostgreSQL webserver, issuing Let's Encrypt SSL, and so many more, yet the UI is simpler and has REST API which is an absolute necessity for the portal to function.&lt;/p&gt;

&lt;p&gt;Can it be better? I thought Apache is good enough until I come across about &lt;a href="https://www.nginx.com/resources/wiki/start/topics/examples/likeapache-htaccess/"&gt;this article from nginx&lt;/a&gt;, and then I start to worry about performance, like what happens if a hundred users come signed in? That's when I learn about &lt;a href="https://ma.ttias.be/a-better-way-to-run-php-fpm/"&gt;PHP-FPM on-demand mode&lt;/a&gt;, &lt;a href="https://www.nginx.com/blog/http2-module-nginx/"&gt;the goodness in HTTP/2&lt;/a&gt;, &lt;a href="https://www.digitalocean.com/community/tutorials/how-to-implement-browser-caching-with-nginx-s-header-module-on-centos-7"&gt;the importance of ETag Header&lt;/a&gt;, and so much more optimization else I need so the server can cramp more people under limited resources.&lt;/p&gt;

&lt;p&gt;This all is flowers and daisies until the next three months I aware of something. When I almost run out of student credit, I looked at the historical billing, and I see the data outbound rates, it cripples me up. As been said in &lt;a href="https://thghosting.com/blog/the-hidden-costs-of-data-transfer-from-public-cloud/"&gt;some articles&lt;/a&gt; it's one of the things that often overlooked when signing up for cloud services, turns out it's not that cheap. &lt;/p&gt;

&lt;h2&gt;
  
  
  Digital Ocean to the rescue
&lt;/h2&gt;

&lt;p&gt;It's late fall 2020 and &lt;a href="https://hacktoberfest.digitalocean.com/"&gt;Hacktoberfest&lt;/a&gt; came along. I looked at the website and something caught my attention. &lt;/p&gt;

&lt;p&gt;"What is Digital Ocean?" &lt;/p&gt;

&lt;p&gt;Obviously, it's one who sponsors the Hacktoberfest. I knew it for years, I have the 2017 and 2018 T-shirts. But I haven't know what exactly the company is. Turns out it's selling cloud services and it's way predictable and cheaper. I became quickly interested to move away from Azure. I also kind of lucky that they have a Singapore server too and Virtualmin backup and restore make the server migration easy. &lt;/p&gt;

&lt;p&gt;As of today, Digital Ocean &lt;a href="https://docs.digitalocean.com/products/billing/bandwidth/"&gt;bill data transfer&lt;/a&gt; at $0.01 per GB if you exceed the transfer pool. With this large amount of data transfer available, I'm able to increase plans by about 10 times what initially available. &lt;/p&gt;

&lt;h2&gt;
  
  
  Freedom on the cloud
&lt;/h2&gt;

&lt;p&gt;This was the story of how &lt;a href="https://domcloud.io"&gt;DOM Cloud&lt;/a&gt; became. As of now, you can sign up a free hosting at 256 MB and 1 GB monthly bandwidth. A larger option with a custom domain is also available at $5 a year. &lt;/p&gt;

&lt;p&gt;From now on you might be thinking this all just part of my marketing plan. Actually, I just want to share something that should be common to most people when starting a job as a web freelancer: the expensive prices of operational cost and lack of features most developers need. Websites that do not take as much as resources shouldn't be as expensive as they should be anyway. &lt;/p&gt;

&lt;p&gt;And this is a problem in my country too, as to accelerate internet growth we have to deliver the best prices for our clients. I got all positive reactions when DOM Cloud goes available. My clients never doubt our web pricing anymore and I'm happy with my day job as a web freelancer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Things I learned from this
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Building startup doesn't always start with burning lots of money&lt;/li&gt;
&lt;li&gt;The best product came from solving your own daily problem&lt;/li&gt;
&lt;li&gt;Recent advancements in open source technologies made this all possible&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can comment for things that get you curious from this story, but for this product itself you should check the &lt;a href="https://github.com/domcloud/domcloud-io"&gt;GitHub repository&lt;/a&gt; or &lt;a href="https://github.com/domcloud/domcloud-io/discussions"&gt;discussion page&lt;/a&gt; as I open sourced everything anyway.&lt;/p&gt;

</description>
      <category>devjournal</category>
    </item>
  </channel>
</rss>
