<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Dr. Kibria]]></title><description><![CDATA[Hi Friends 👋 Kibria here. I am a Full-stack Developer, Guitarist and a Doctor of Medicine 😳]]></description><link>https://gkibria.com/</link><image><url>https://gkibria.com/favicon.png</url><title>Dr. Kibria</title><link>https://gkibria.com/</link></image><generator>Ghost 5.87</generator><lastBuildDate>Sat, 02 May 2026 00:12:29 GMT</lastBuildDate><atom:link href="https://gkibria.com/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[14 mysterious JavaScript features worth knowing]]></title><description><![CDATA[<p>JavaScript is a powerful and flexible programming language, but it also has some unique features and behavior that can be considered &quot;weird&quot; or &quot;non-intuitive&quot; to some developers. Here are a few examples:</p><h2 id="automatic-type-coercion">Automatic type coercion: </h2><p>JavaScript is a loosely typed language, which means that the interpreter</p>]]></description><link>https://gkibria.com/article/14-mysterious-javascript-features-worth-knowing/</link><guid isPermaLink="false">63d14bfc1f979c0001cf6947</guid><category><![CDATA[Javascript]]></category><dc:creator><![CDATA[Mohammad Golam Kibria]]></dc:creator><pubDate>Wed, 25 Jan 2023 16:04:14 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1627398242454-45a1465c2479?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDF8fGphdmFzY3JpcHR8ZW58MHx8fHwxNjc0NjYyMTgx&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1627398242454-45a1465c2479?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDF8fGphdmFzY3JpcHR8ZW58MHx8fHwxNjc0NjYyMTgx&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="14 mysterious JavaScript features worth knowing"><p>JavaScript is a powerful and flexible programming language, but it also has some unique features and behavior that can be considered &quot;weird&quot; or &quot;non-intuitive&quot; to some developers. Here are a few examples:</p><h2 id="automatic-type-coercion">Automatic type coercion: </h2><p>JavaScript is a loosely typed language, which means that the interpreter will automatically convert values from one type to another when necessary. This can lead to unexpected results, for example:</p><pre><code class="language-js">console.log(1 + &quot;2&quot;);  // &quot;12&quot; (string concatenation)
console.log([] + []); // &quot;&quot; (empty string)
console.log([1,2,3] == &quot;1,2,3&quot;); // true (type coercion)</code></pre><h2 id="equality-comparison">Equality comparison: </h2><p>JavaScript has two types of equality comparison: &quot;==&quot; and &quot;===&quot;. The &quot;==&quot; operator performs type coercion if necessary, while the &quot;===&quot; operator compares values without coercion. This can lead to unexpected results, for example:</p><pre><code class="language-js">console.log(1 == true);  // true (type coercion)
console.log(1 === true); // false (no coercion)
console.log(null == undefined); // true
console.log(null === undefined); // false</code></pre><h2 id="hoisting">Hoisting: </h2><p>In JavaScript, variable and function declarations are &quot;hoisted&quot; to the top of their scope, which means that they are accessible before they are declared. This can lead to unexpected results, for example:</p><pre><code class="language-js">console.log(x);   // undefined (x is hoisted)
var x = 1;

console.log(y);   // ReferenceError: y is not defined
let y = 1;
</code></pre><h2 id="global-variables">Global variables: </h2><p>In JavaScript, variables that are not declared inside a function are considered global variables and are accessible from anywhere in the code. This can lead to naming conflicts and unexpected results, for example:</p><pre><code class="language-js">var x = 1;
function test() {
  console.log(x);   // 1 (x is global)
}
test();
</code></pre><h2 id="the-this-keyword">The &apos;this&apos; keyword: </h2><p>In JavaScript, the value of <code>this</code> keyword is determined by how a function is called, not where it is defined. This can lead to unexpected results, for example:</p><pre><code class="language-js">const obj = {
  name: &quot;John&quot;,
  printName: function() {
    console.log(this.name);
  }
};

const print = obj.printName;
print();  // undefined (this is not bound to obj)
</code></pre><h2 id="function-scope">Function scope: </h2><p>In JavaScript, function scope is used instead of block scope. This can lead to unexpected results, for example:</p><pre><code class="language-js">for (var i = 0; i &lt; 3; i++) {
  setTimeout(function() {
    console.log(i);
  }, 100);
}
// 3 3 3 (i is in the same scope)

for (let i = 0; i &lt; 3; i++) {
  setTimeout(function() {
    console.log(i);
  }, 100);
}
// 0 1 2 (i is in different scope)
</code></pre><h2 id="prototype-based-inheritance">Prototype-based inheritance: </h2><p>JavaScript is a prototype-based language, which means that objects inherit properties and methods from other objects through prototypes. This can be different from traditional class-based inheritance and can lead to unexpected results, for example:</p><pre><code class="language-js">const animal = {
  eats: true,
  walk() {
    console.log(&quot;Animal can walk&quot;);
  }
};
const rabbit = Object.create(animal);
rabbit.jumps = true;
console.log(rabbit.eats);  // true (inherited from animal)
console.log(rabbit.jumps); // true (defined on rabbit)
</code></pre><h2 id="automatic-semicolon-insertion">Automatic semicolon insertion: </h2><p>JavaScript&apos;s automatic semicolon insertion (ASI) feature can lead to unexpected results if not used correctly. For example:</p><pre><code class="language-js">const x = 5
console.log(x) // 5
</code></pre><p>In this example, JavaScript inserts a semicolon after the <code>const x = 5</code> statement, which is treated as a separate statement from the <code>console.log(x)</code>. As a result, <code>x</code> is assigned the value <code>5</code> instead of the intended <code>console.log(x)</code> statement.</p><h2 id="function-expressions-vs-function-declarations">Function expressions vs function declarations: </h2><p>The difference in how they are handled by JavaScript&apos;s hoisting feature can lead to unexpected results if not used correctly. For example:</p><pre><code class="language-js">foo(); // ReferenceError

const foo = function() {
  console.log(&apos;bar&apos;);
};

</code></pre><p>In this example, the function is assigned to a variable <code>foo</code> but due to hoisting the variable is hoisted but the assignment is not and thus the reference error.</p><h2 id="the-nan-value">The NaN value: </h2><p>JavaScript has a special <code>NaN</code> value, which stands for &quot;not a number.&quot; When a mathematical operation cannot produce a valid number, it returns <code>NaN</code>. This can lead to unexpected results, for example:</p><pre><code class="language-js">console.log(0 / 0); // NaN
console.log(isNaN(NaN)); // true
console.log(NaN == NaN); // false
</code></pre><h2 id="implicit-type-conversion">Implicit type conversion: </h2><p>JavaScript can perform implicit type conversion in certain situations, such as when comparing values or using certain operators. For example:</p><pre><code class="language-js">console.log(&quot;5&quot; == 5); // true
console.log(&quot;5&quot; === 5); // false
console.log(true + 1); // 2
console.log([] + {}); // &quot;[object Object]&quot;
</code></pre><p>In these examples, JavaScript performs an implicit type conversion, which can lead to unexpected results if not taken into account.</p><h2 id="property-access-on-null-and-undefined">Property access on null and undefined: </h2><p>In JavaScript, trying to access a property on a <code>null</code> or <code>undefined</code> value will not throw an error, but instead will return <code>undefined</code>. For example:</p><pre><code class="language-js">console.log(null.x); // undefined
console.log(undefined.x); // undefined
console.log({}.x); // undefined
</code></pre><p>In these examples, trying to access a property on a <code>null</code> or <code>undefined</code> value will not throw an error, but it can lead to unexpected results if not handled properly.</p><h2 id="the-operator">The == operator: </h2><p>JavaScript&apos;s <code>==</code> operator compares values for equality, but it can perform type coercion if the operands are of different types. This can lead to unexpected results, for example:</p><pre><code class="language-js">console.log(&apos;&apos; == 0); // true
console.log(null == undefined); // true
console.log([] == false); // true
</code></pre><p>In these examples, JavaScript&apos;s <code>==</code> operator performs type coercion and returns <code>true</code> even though the values are not equal in the traditional sense.</p><h2 id="function-scope-1">Function scope: </h2><p>JavaScript uses function scope, which means that variables declared within a function are only accessible within that function. However, variables declared with the <code>var</code> keyword are also accessible within the entire function scope, which can lead to unexpected results. For example:</p><pre><code class="language-js">function test() {
  var x = 1;
  if (true) {
    var x = 2;
    console.log(x); // 2
  }
  console.log(x); // 2
}
test();
</code></pre><p>In this example, the variable <code>x</code> is declared twice within the same function scope, and the second declaration overwrites the first. This can lead to unexpected results if not handled properly.</p><h2 id="conclusion">Conclusion:</h2><p>These are examples of unique features and behavior of JavaScript that can be considered &quot;weird&quot; or &quot;non-intuitive&quot; to some developers. Understanding these features can help you write more efficient and effective code, and avoid potential bugs in your JavaScript programs.</p>]]></content:encoded></item><item><title><![CDATA[Javascript Type coercion with examples]]></title><description><![CDATA[<p>In JavaScript, type coercion refers to the way in which the interpreter automatically converts values from one data type to another, as needed, during the execution of a program.</p><p>Here are a few examples of type coercion in JavaScript:</p><p>&#x1F449; When an operator is applied to operands of different types,</p>]]></description><link>https://gkibria.com/article/javascript-type-coercion-with-examples/</link><guid isPermaLink="false">63d154d71f979c0001cf6a04</guid><category><![CDATA[Javascript]]></category><dc:creator><![CDATA[Mohammad Golam Kibria]]></dc:creator><pubDate>Tue, 17 Jan 2023 16:18:00 GMT</pubDate><content:encoded><![CDATA[<p>In JavaScript, type coercion refers to the way in which the interpreter automatically converts values from one data type to another, as needed, during the execution of a program.</p><p>Here are a few examples of type coercion in JavaScript:</p><p>&#x1F449; When an operator is applied to operands of different types, the operands are often coerced to a common type before the operation is performed. For example:</p><pre><code class="language-js">console.log(1 + &apos;2&apos;);  // Output: &apos;12&apos;
</code></pre><p>In this example, the number 1 is coerced to a string before it is concatenated with the string &apos;2&apos;.</p><p>&#x1F449; When a non-boolean value is used in a boolean context, it is coerced to a boolean. For example:</p><pre><code class="language-js">console.log(!!&apos;hello&apos;);  // Output: true
console.log(!!&apos;&apos;);       // Output: false
</code></pre><p>In these examples, the string &apos;hello&apos; is coerced to the boolean value true, and the empty string is coerced to the boolean value false.</p><p>&#x1F449; When a function is called with too few or too many arguments, the missing arguments are filled in with the value undefined, and excess arguments are ignored. This is called &quot;argument coercion&quot;. For example:</p><pre><code class="language-js">function greet(name) {
  console.log(`Hello, ${name}!`);
}

greet(&apos;Alice&apos;);  // Output: &apos;Hello, Alice!&apos;
greet();         // Output: &apos;Hello, undefined!&apos;
greet(&apos;Bob&apos;, &apos;Charlie&apos;);  // Output: &apos;Hello, Bob!&apos;
</code></pre><p>&#x1F449; When an object is used in a context where a primitive value is expected, the object is coerced to a primitive value using the internal <code>ToPrimitive</code> operation. For example:</p><pre><code class="language-js">console.log(1 + {});  // Output: &apos;1[object Object]&apos;
</code></pre><p>In this example, the object {} is coerced to the string &apos;[object Object]&apos;, which is then concatenated with the number 1 to produce the string &apos;1[object Object]&apos;.</p><p>&#x1F449; When the <code>+</code> operator is used to concatenate a string and a number, the number is coerced to a string before the concatenation is performed. For example:</p><pre><code class="language-js">console.log(3 + 4 + &apos;5&apos;);  // Output: &apos;75&apos;
</code></pre><p>In this example, the numbers 3 and 4 are first summed to produce the number 7, which is then concatenated with the string &apos;5&apos; to produce the string &apos;75&apos;.</p><p>&#x1F449; When the <code>==</code> operator is used to compare a value to <code>null</code> or <code>undefined</code>, it performs a type coercion before performing the comparison. For example:</p><pre><code class="language-js">console.log(null == undefined);  // Output: true
</code></pre><p>In this example, the <code>==</code> operator first coerces both <code>null</code> and <code>undefined</code> to the same type (which is <code>undefined</code>), and then performs the comparison. Since both values are now of the same type and value, the comparison returns true.</p><p>I hope these examples help to further illustrate the concept of type coercion in JavaScript.</p>]]></content:encoded></item><item><title><![CDATA[JavaScript explanation: this, apply and bind]]></title><description><![CDATA[<p>Hi there! In this post I would like to briefly explain what is the meaning of <code>this</code> , <code>apply</code> and <code>bind</code>. </p><h2 id="about-this-keyword">About this keyword</h2><p>In JavaScript, <code>this</code> refers to the object that is executing the current function. The value of <code>this</code> can be determined by how a function is called.</p><p>Here</p>]]></description><link>https://gkibria.com/article/javascript-explanation-this-apply-and-bind/</link><guid isPermaLink="false">63d15c251f979c0001cf6a65</guid><category><![CDATA[Javascript]]></category><dc:creator><![CDATA[Mohammad Golam Kibria]]></dc:creator><pubDate>Wed, 11 Jan 2023 16:51:00 GMT</pubDate><content:encoded><![CDATA[<p>Hi there! In this post I would like to briefly explain what is the meaning of <code>this</code> , <code>apply</code> and <code>bind</code>. </p><h2 id="about-this-keyword">About this keyword</h2><p>In JavaScript, <code>this</code> refers to the object that is executing the current function. The value of <code>this</code> can be determined by how a function is called.</p><p>Here are a few ways that the value of <code>this</code> can be determined:</p><ul><li>In the global scope (outside of any function), <code>this</code> refers to the global object. In a web browser, the global object is <code>window</code>.</li><li>Inside a function, the value of <code>this</code> depends on how the function is called. If the function is called as a method of an object (e.g., <code>obj.method()</code>), <code>this</code> will refer to the object (<code>obj</code>). If the function is called as a standalone function (e.g., <code>function()</code>), <code>this</code> will refer to the global object.</li><li>Inside an arrow function, the value of <code>this</code> is determined by the surrounding context. Arrow functions do not have their own <code>this</code> value, so they inherit the <code>this</code> value of the surrounding context.</li></ul><p>Here are a few examples to illustrate how <code>this</code> can be determined:</p><pre><code class="language-js">// In the global scope
console.log(this);  // Output: window (in a web browser)

const obj = {
  x: 10,
  y: 20,
  sum: function() {
    console.log(this);  // Output: obj
    console.log(this.x + this.y);  // Output: 30
  }
};
obj.sum();

const standAlone = function() {
  console.log(this);  // Output: window (in a web browser)
};
standAlone();
</code></pre><h2 id="apply-and-bind">apply and bind</h2><p><code>apply</code> and <code>bind</code> are methods that can be used to specify the value of <code>this</code> when calling a function.</p><p>Here is an example of how <code>apply</code> can be used:</p><pre><code class="language-js">const obj = {
  x: 10,
  y: 20
};

function add() {
  return this.x + this.y;
}

console.log(add.apply(obj));  // Output: 30
</code></pre><p>In the example above, the <code>apply</code> method is called on the <code>add</code> function and is passed the <code>obj</code> object as an argument. This sets the value of <code>this</code> inside the <code>add</code> function to <code>obj</code>, so when <code>this.x</code> and <code>this.y</code> are accessed, they refer to <code>obj.x</code> and <code>obj.y</code>, respectively. The <code>apply</code> method is called on the <code>add</code> function and the result of <code>add</code> is logged to the console.</p><p>Here is an example of how <code>bind</code> can be used:</p><pre><code class="language-js">const obj = {
  x: 10,
  y: 20
};

function add() {
  return this.x + this.y;
}

const boundAdd = add.bind(obj);
console.log(boundAdd());  // Output: 30
</code></pre><p>In the example above, the <code>bind</code> method is called on the <code>add</code> function and is passed the <code>obj</code> object as an argument. This creates a new function, called <code>boundAdd</code>, that has its <code>this</code> value set to <code>obj</code>. When <code>boundAdd</code> is called, it will execute the code in the <code>add</code> function with <code>this</code> set to <code>obj</code>.</p><h2 id="apply-vs-bind">apply vs bind</h2><p>The main difference between <code>apply</code> and <code>bind</code> is that <code>apply</code> calls a function with a specified <code>this</code> value and arguments, whereas <code>bind</code> returns a new function with a specified <code>this</code> value and arguments.</p><p>Here is an example that demonstrates the difference between <code>apply</code> and <code>bind</code>:</p><pre><code class="language-js">const obj = {
  x: 10,
  y: 20
};

function add(a, b) {
  return this.x + this.y + a + b;
}

console.log(add.apply(obj, [1, 2]));  // Output: 33

const boundAdd = add.bind(obj, 1, 2);
console.log(boundAdd());  // Output: 33
</code></pre><p>In the example above, the <code>apply</code> method is called on the <code>add</code> function and is passed the <code>obj</code> object as the <code>this</code> value and the array <code>[1, 2]</code> as the arguments. This calls the <code>add</code> function with <code>this</code> set to <code>obj</code> and the arguments <code>1</code> and <code>2</code>.</p><p>The <code>bind</code> method is called on the <code>add</code> function and is passed the <code>obj</code> object as the <code>this</code> value and the arguments <code>1</code> and <code>2</code>. This creates a new function called <code>boundAdd</code> that has its <code>this</code> value set to <code>obj</code> and its arguments set to <code>1</code> and <code>2</code>. When <code>boundAdd</code> is called, it will execute the code in the <code>add</code> function with <code>this</code> set to <code>obj</code> and the arguments <code>1</code> and <code>2</code>.</p><p>So, in summary, the main difference between <code>apply</code> and <code>bind</code> is that <code>apply</code> calls a function with a specified <code>this</code> value and arguments, whereas <code>bind</code> returns a new function with a specified <code>this</code> value and arguments.</p>]]></content:encoded></item><item><title><![CDATA[Authentication vs Authorization]]></title><description><![CDATA[<p>If you are struggling with the concept of authentication and authorization, well here is kinda good news. These two concepts are not as hard as you are thinking but really important to build any kind of software application. After reading this post, you will have a solid understanding of these</p>]]></description><link>https://gkibria.com/article/authentication-vs-authorisations/</link><guid isPermaLink="false">63b428241f979c0001cf686b</guid><category><![CDATA[Backend]]></category><category><![CDATA[Frontend]]></category><dc:creator><![CDATA[Mohammad Golam Kibria]]></dc:creator><pubDate>Tue, 03 Jan 2023 13:57:29 GMT</pubDate><media:content url="https://gkibria.com/content/images/2023/01/blog-authentication-vs-authorization.png" medium="image"/><content:encoded><![CDATA[<img src="https://gkibria.com/content/images/2023/01/blog-authentication-vs-authorization.png" alt="Authentication vs Authorization"><p>If you are struggling with the concept of authentication and authorization, well here is kinda good news. These two concepts are not as hard as you are thinking but really important to build any kind of software application. After reading this post, you will have a solid understanding of these two &quot;seems like confusing concepts&quot;.</p><h2 id="what-are-they">What are they?</h2><p><strong><em>Authentication</em></strong> is the process of verifying the identity of a user, device, or system. It involves verifying that the entity claiming to be who they say they are actually is who they claim to be.</p><p><strong><em>Authorization</em></strong> is the process of granting or denying access to resources or actions based on the identity of the user, device, or system. It involves deciding whether an authenticated entity has the necessary permissions to perform a specific action or access a particular resource.</p><h3 id="here-are-some-examples">Here are some examples.</h3><ol><li><strong>Online banking: </strong>When you log into your online banking account, you are required to enter your username and password. This is the authentication step, as it verifies your identity. Once you are authenticated, you are then able to perform certain actions, such as transferring money or viewing your account balance. This is the authorization step, as it determines what you are allowed to do based on your authenticated identity.</li><li><strong>Accessing a secure building:</strong> When you enter a secure building, you may be required to present a badge or swipe a card to gain entry. This is the authentication step, as it verifies that you are an authorized employee or visitor. Once you are authenticated, you may only be allowed to access certain areas of the building based on your role or clearance level. This is the authorization step, as it grants or denies access to specific areas based on your authenticated identity.</li><li><strong>Using a smartphone app:</strong> When you download and open a smartphone app, you may be required to log in with your username and password. This is the authentication step, as it verifies your identity. Once you are authenticated, the app may grant you access to certain features or functions based on your permissions. For example, a productivity app may allow you to create and edit documents, but not delete them, based on your authorization level.</li></ol><p>Now that you understand the basics, let&apos;s advance further.</p><h2 id="what-are-the-available-technologies">What are the available technologies?</h2><p>You might be wondering which technologies are typically used to achieve this in a web application. Well, there are several technologies that can be used. </p><h3 id="for-authentication">For authentication:</h3><ol><li><strong>Single Sign-On (SSO) systems:</strong> SSO systems allow users to log in to multiple web applications using a single set of credentials, such as a username and password. This can make it easier for users to access multiple applications without having to remember multiple sets of login information. SSO systems are often used in enterprise environments, where users may need to access a large number of internal applications.</li><li><strong>OAuth:</strong> OAuth is an open standard for authorization that allows users to grant third-party applications access to their resources without sharing their login credentials. OAuth is commonly used for social media login integrations, where users can log in to a web application using their Facebook or Google accounts.</li><li><strong>JSON Web Tokens (JWTs):</strong> JWTs are a popular method for authenticating and authorizing users in web applications. They are digitally signed tokens that contain information about the user and their permissions. JWTs can be easily passed between servers and clients, making them useful for API authentication and authorization.</li><li><strong>Cookies:</strong> Cookies are small pieces of data that are stored on the user&apos;s device and sent back to the server with each request. They can be used to store information about the user&apos;s session, such as their authenticated identity and permissions.</li><li><strong>HTTP Basic and Digest Authentication:</strong> HTTP Basic and Digest Authentication are methods for authenticating users using the HTTP protocol. They involve sending the user&apos;s login credentials with each request, either in the header or as part of the URL.</li><li><strong>Biometric authentication:</strong> Biometric authentication involves using unique physical characteristics, such as a fingerprint or facial recognition, to verify the identity of a user. This type of authentication is becoming more common on smartphones and other devices.</li><li><strong>Multi-Factor Authentication (MFA):</strong> MFA involves using more than one method to verify the identity of a user. This can include something the user knows (such as a password), something the user has (such as a phone or security token), or something the user is (such as a fingerprint). MFA provides an additional layer of security by requiring multiple pieces of evidence to verify the user&apos;s identity.</li></ol><h3 id="and-for-authorizations">And for authorizations:</h3><ol><li><strong>Role-Based Access Control (RBAC):</strong> RBAC is a method of granting or denying access to resources based on the user&apos;s role or job function. Users are assigned to specific roles, and each role is given a set of permissions that determine what actions the user is allowed to perform.</li><li><strong>Access Control Lists (ACLs):</strong> ACLs are a way of specifying which users or groups are allowed to access specific resources. Each resource is associated with an ACL that lists the users or groups that are allowed to access it, as well as the actions they are allowed to perform.</li><li><strong>OAuth:</strong> OAuth is an open standard for authorization that allows users to grant third-party applications access to their resources without sharing their login credentials. OAuth is commonly used for social media login integrations, where users can log in to a web application using their Facebook or Google accounts.</li><li><strong>JSON Web Tokens (JWTs):</strong> JWTs are a popular method for authenticating and authorizing users in web applications. They are digitally signed tokens that contain information about the user and their permissions. JWTs can be easily passed between servers and clients, making them useful for API authentication and authorization.</li><li><strong>Cookies:</strong> Cookies are small pieces of data that are stored on the user&apos;s device and sent back to the server with each request. They can be used to store information about the user&apos;s session, such as their authenticated identity and permissions.</li><li>H<strong>TTP Basic and Digest Authentication:</strong> HTTP Basic and Digest Authentication are methods for authenticating users using the HTTP protocol. They involve sending the user&apos;s login credentials with each request, either in the header or as part of the URL.</li></ol><h2 id="so-what-is-the-usual-flow-of-authentication-and-authorization">So, what is the usual flow of authentication and authorization?</h2><p>The authentication and authorization flow of a web application typically involves the following steps:</p><ol><li>The user attempts to access a protected resource or perform a restricted action on the web application.</li><li>The web application prompts the user to enter their login credentials, such as a username and password.</li><li>The user enters their credentials and submits them to the web application.</li><li>The web application verifies the user&apos;s credentials against a stored set of valid credentials. This is the authentication step.</li><li>If the user&apos;s credentials are valid, the web application grants the user access to the protected resource or allows them to perform the restricted action. This is the authorization step.</li><li>If the user&apos;s credentials are not valid, the web application denies access and may prompt the user to try again or provide an error message.</li></ol><p>Depending on the specific technology being used for authentication and authorization, the details of this process may vary. For example, if the web application is using OAuth for authentication, the user may be redirected to a login page hosted by a third-party provider (such as Google or Facebook) to enter their credentials. If the web application is using JWTs for authorization, the user may be issued a token upon successful authentication that contains information about their permissions and is passed with each subsequent request to the web application.</p><h2 id="what-is-the-typical-http-response">What is the typical HTTP response?</h2><p>Here is a description of typical HTTP responses for both authentication and authorization in success and error states:</p><h3 id="authentication-success">Authentication success:</h3><ul><li>If the user&apos;s login credentials are successfully verified, the web application may return an HTTP 200 OK response.</li><li>In some cases, the web application may also return an HTTP 302 Found response, redirecting the user to a protected resource or the home page of the application.</li></ul><h3 id="authentication-error">Authentication error:</h3><ul><li>If the user&apos;s login credentials are invalid or cannot be verified, the web application may return an HTTP 401 Unauthorized response.</li><li>The web application may also include a WWW-Authenticate header in the response, indicating the authentication method being used (such as Basic or Digest) and providing a challenge for the user to retry the authentication process.</li></ul><h3 id="authorization-success">Authorization success:</h3><ul><li>If the user is successfully authorized to access a protected resource or perform a restricted action, the web application may return an HTTP 200 OK response.</li><li>Depending on the specific resource or action being accessed, the web application may also return other HTTP status codes, such as HTTP 201 Created for resource creation or HTTP 204 No Content for actions that do not return a response body.</li></ul><h3 id="authorization-error">Authorization error:</h3><ul><li>If the user is not authorized to access a protected resource or perform a restricted action, the web application may return an HTTP 403 Forbidden response.</li><li>The web application may also include a WWW-Authenticate header in the response, indicating the authorization method being used and providing a challenge for the user to retry the authorization process.</li></ul><p>In conclusion, if the system asks &quot;Who are you?&quot; to validate the right person, this is authentication. When it checks &quot;Are you allowed to do that?&quot; by checking the user&apos;s permission to access the resources, you guessed it right, this is an authorization. If you like this post, please share and subscribe to my blog. </p><p>Happy New Year 2023!</p>]]></content:encoded></item><item><title><![CDATA[Directus installation guide on oracle cloud using docker]]></title><description><![CDATA[<p>Hi good people! In my other post, I reviewed Directus which is a headless data platform and can be used as a backend API with a built-in data studio (admin panel). I highly recommend you read <a href="https://gkibria.com/article/directus-the-leading-headless-data-platform/">that post</a> if you are new to Directus.</p><p>In this post, I will guide</p>]]></description><link>https://gkibria.com/article/directus-installation-guide-on-oracle-cloud-using-docker/</link><guid isPermaLink="false">637520aead0b4d00010f3224</guid><category><![CDATA[Directus.io]]></category><category><![CDATA[Backend]]></category><category><![CDATA[docker]]></category><category><![CDATA[aaPanel]]></category><dc:creator><![CDATA[Mohammad Golam Kibria]]></dc:creator><pubDate>Wed, 16 Nov 2022 22:59:07 GMT</pubDate><media:content url="https://gkibria.com/content/images/2022/11/directus-installation-on-oracle-cloud.png" medium="image"/><content:encoded><![CDATA[<img src="https://gkibria.com/content/images/2022/11/directus-installation-on-oracle-cloud.png" alt="Directus installation guide on oracle cloud using docker"><p>Hi good people! In my other post, I reviewed Directus which is a headless data platform and can be used as a backend API with a built-in data studio (admin panel). I highly recommend you read <a href="https://gkibria.com/article/directus-the-leading-headless-data-platform/">that post</a> if you are new to Directus.</p><p>In this post, I will guide you on how to install Directus using docker on Oracle Cloud. We will be using aaPanel which is a great free and stable server control panel. If you haven&apos;t heard of it, I have a review and a full installation guide available for you.</p><h3 id="pre-requisites">Pre-requisites</h3><ul><li>Oracle VM with aaPanel installed. <a href="https://gkibria.com/article/installing-aapanel-on-oracle-cloud-virtual-machine/">Click here</a> for the aaPanel installation guide.</li><li>Some docker knowledge</li><li>Domain name added to Cloudflare, and Origin server certificate</li><li>Google account for backup</li></ul><hr><h2 id="step-1-install-the-docker-in-aapanel">Step 1: Install the docker in aaPanel</h2><p>You can skip this if you already have docker installed. Otherwise, follow the steps below.</p><ul><li>log in to the panel</li><li>go to the App stores of the panel</li><li>search for docker</li><li>install Docker manager</li></ul><h2 id="step-2-dns-setup">Step 2: DNS setup</h2><p>Since DNS will take some time to propagate, we will start with the domain. I recommend using Cloudflare as they have free features with free origin server certificates.</p><ul><li>Log in to the <strong>Cloudflare dashboard</strong></li><li>Add your domain to Cloudflare if you have not done yet</li><li>Add an <strong>A</strong> record to the server&apos;s <strong>public IP</strong> address. If you are planning to use the root domain, use @ in the name. I will be using a subdomain.</li><li>Be sure to check the <strong>proxy</strong> status is <strong>On</strong>.</li><li>Go to the <strong>SSL/TLS</strong> section of your domain, and click <strong>origin server</strong>. Now <strong>create a cretificate</strong> for your domain. After generating, save the <strong>Private key</strong> and <strong>Certificate</strong> in a file. We will need these to install SSL and reverse proxy later.</li></ul><h2 id="step-3-set-up-mysql-database">Step 3: Set up MySQL database</h2><p>Come back to the aaPanel. In this step, we will create a database for directus. Follow the steps.</p><ul><li>Navigate to the database and click Add Database</li><li>Write the <strong>DB Name</strong>: directus, <strong>username</strong>: directus, <strong>permission</strong>: specified IP and write down your server public IP.</li><li>Click Submit.</li></ul><p>This will create a database. Don&apos;t forget to change the DB name, username, and password according to your choice.</p><h2 id="step-4-docker-compose-template">Step 4: Docker compose template</h2><p>In this step, we will write a docker-compose file with all the required configuration options of Directus and persistent storage with docker volume. </p><p>We will create a YAML file in a directory called &apos;directus&apos; under the /www directory. Later we will configure the required volume in this directory and finally back up this folder. So all our volume files and YAML file will be backed up.</p><p>Follow steps:</p><ul><li>In aaPanel, navigate to <strong>Files</strong> and go to <strong>/www</strong> directory</li><li>create a directory named &apos;<strong>directus</strong>&apos;</li><li>create a file <strong>docker-compose.yaml</strong> under directus folder</li><li>double click to edit the file and <strong>paste the following code</strong></li></ul><pre><code class="language-yaml">version: &apos;3&apos;
services:

  directus:
    container_name: directus
    image: directus/directus:9.20.4
    restart: always
    ports:
      - 8055:8055
    volumes:
      # By default, uploads are stored in /directus/uploads
      # Always make sure your volumes matches the storage root when using
      # local driver
      - ./uploads:/directus/uploads
      # Make sure to also mount the volume when using SQLite
      # - ./database:/directus/database
      # If you want to load extensions from the host
      #- ./extensions:/directus/extensions
    environment:
      KEY: &apos;255d861b-5ea1-5996-9aa3-7f6rg47h-922530ec40b1&apos;
      SECRET: &apos;6116487b-cda1-52c2-fu75hk-b5b5-c8022c45e263&apos;

      DB_CLIENT: &apos;mysql&apos;
      DB_HOST: &apos;server_public_ip&apos;
      DB_PORT: &apos;3306&apos;
      DB_DATABASE: &apos;directus&apos;
      DB_USER: &apos;directus&apos;
      DB_PASSWORD: &apos;mysql_password&apos;

      ADMIN_EMAIL: &apos;admin@example.com&apos;
      ADMIN_PASSWORD: &apos;d1r3ctu5&apos;

      # Make sure to set this in production
      # (see https://docs.directus.io/self-hosted/config-options#general)
      PUBLIC_URL: &apos;https://directus.example.com&apos;
</code></pre><p>Please change the DB configuration, key, secret, and admin credentials according to your need. You can also add additional environmental variables here to configure Directus. Full options <a href="https://docs.directus.io/self-hosted/config-options.html?ref=gkibria.com">here</a>.</p><h2 id="step-5-run-the-container">Step 5: Run the container</h2><p>To run the container in aaPanel, you must first import the compose file. </p><ul><li>Navigate to Docker &gt; <strong>compose template</strong>. </li><li>Now click <strong>add</strong> and select the <strong>local template</strong> tab. </li><li>Enter <strong>/www/directus</strong> in the search box and click <strong>search</strong>. You must see the newly created yaml file. Select it from the list and <strong>submit</strong> it.</li></ul><p>Then we need to pull the image. On the same page, click the <strong>pull image</strong> link of the directus template. A directus (v9.20.4) image will be pulled based on the image we specified in yaml file. </p><p>Now it&apos;s time to run a container from the pulled image. To do so-</p><ul><li>Navigate to Docker &gt; <strong>Container</strong> in the aaPanel</li><li>Click <strong>Add Container</strong> and chose the <strong>compose</strong> tab.</li><li><strong>Select</strong> directus from the dropdown and enter a<strong> name</strong>.</li><li>After submitting the dialog, a new container will be created and listed.</li><li><strong>Wait</strong> for a minute or two (give some time to boot up directus) and <strong>see the log</strong> of the container. In the log, you must see &apos;<em>Server started at http://0.0.0.0:8055</em>&apos; which indicates your directus is running successfully.</li></ul><h2 id="step-6-open-the-port-on-the-security-group">Step 6: Open the port on the security group</h2><p>On the docker-compose file, we exposed the 8055 port on the host. So we need to open this port. Follow this <a href="https://gkibria.com/article/installing-aapanel-on-oracle-cloud-virtual-machine/#step-3-open-ports-in-the-firewall">instruction</a>. Make sure MySQL port 3306 is there.</p><p>Next, come back to aaPanel to release ports from inside the server. Go to the security page, and open the 8055 ports in the Firewall section. For example, type 8055 in the port, directus in the description, and click open. Do a similar thing for other ports if not already there.</p><p>At this stage, you should see a running directus on URL: http://server_public_ip:8055 </p><p>You can now log in with the credentials you specified in yaml file and see if everything is working or not. For example, try to upload a file. If the upload does not succeed, you should change the <strong>upload</strong> directory permission inside <strong>/www/directus</strong> directory. Try the following code:</p><pre><code class="language-bash">sudo chown -R 1000:1000 ./uploads</code></pre><h2 id="step-7-reverse-proxy-with-nginx">Step 7: Reverse proxy with Nginx</h2><p>In this step, we will set up a reverse Nginx proxy. It will proxy all the requests from our domain to http://localhost:8055. To configure SSL, we need a Cloudflare origin server certificate from step 2.</p><ul><li>Go to the website page on aaPanael, and click <strong>add site</strong> under PHP project.</li><li>Enter the <strong>domain</strong>, FTP - no, Database - No, PHP version - <strong>static</strong>, and click submit. Refresh the page, you can see a new site is created.</li><li>Click the site name. The site config dialog will open.</li><li>Go to SSL &gt; <strong>Other certificate</strong>, paste the <strong>Private key</strong> and <strong>Certificate</strong> and Save.</li><li>Turn <strong>On</strong> the Force HTTPS option.</li><li>Go to the Reverse proxy section and <strong>add a proxy</strong>.</li><li>Enter the proxy name: <strong>directus</strong>, target URL: <strong>http://localhost:8055</strong>, and submit.</li></ul><p>Test your domain in the browser and you should see your new directus website. Now you have successfully configured a reverse proxy for the directus docker container. The next step is optional but very important.</p><h2 id="step-8-configure-backup">Step 8: Configure backup</h2><p>In this section, we will configure a backup for our newly created directus with cron. In aaPanel, there are several plugins for that - Google Drive, S3, and remote FTP. Feel free to use whatever you like. But I would go for Google Drive.</p><p>First, you have to install the plugin in aaPanel. Go to App Store, search for google drive and install the plugin. After installation, click the settings. Complete the Google Drive verification process according to the instruction.</p><p>Now we will create 2 cron tasks for the backup - one for the database and the other for the directory (/www/directus) in our server.</p><h3 id="database-backup">Database Backup</h3><p>Go to the Cron page of aaPanel and add a task according to the instruction:</p><ul><li>Type of Task: <strong>Backup Database</strong></li><li>Execution cycle: choose how you want to backup</li><li>Backup database: select the <strong>directus</strong> or all</li><li>Backup to: <strong>Google Drive</strong></li><li>save the task</li></ul><h3 id="directory-backup">Directory Backup</h3><p>Go to the Cron page of aaPanel and add a task according to the instruction:</p><ul><li>Type of Task: <strong>Backup Directory</strong></li><li>Execution cycle: choose how you want to backup</li><li>Directory to backup: select <strong>/www/directus/</strong></li><li>Backup to: <strong>Google Drive</strong></li><li>save the task</li></ul><p>The tasks will now be available in the task list. To test a task, click <strong>execute</strong> link and wait for some time. You will see your backup is now uploaded to Google Drive.</p><hr><p>Congratulations! You now successfully installed a directus instance on oracle cloud and configured the SSL, reverse proxy, and backup strategy to Google Drive. Now go to your directus admin panel by visiting yourdomain.com</p>]]></content:encoded></item><item><title><![CDATA[Directus - The leading Headless Data Platform]]></title><description><![CDATA[<p>Directus called itself &quot;the leading Headless Data Platform&quot;, which is layers on top of any new or existing SQL database and introspects the schema, providing both GraphQL+REST APIs and a beautiful and intuitive GUI app ideal for technical and non-technical users.</p><p>You probably get the idea already.</p>]]></description><link>https://gkibria.com/article/directus-the-leading-headless-data-platform/</link><guid isPermaLink="false">636d879fad0b4d00010f2f94</guid><category><![CDATA[Directus.io]]></category><category><![CDATA[Database]]></category><category><![CDATA[Backend]]></category><dc:creator><![CDATA[Mohammad Golam Kibria]]></dc:creator><pubDate>Fri, 11 Nov 2022 11:20:22 GMT</pubDate><media:content url="https://gkibria.com/content/images/2022/11/directus-engine-architecture-stacked.svg" medium="image"/><content:encoded><![CDATA[<img src="https://gkibria.com/content/images/2022/11/directus-engine-architecture-stacked.svg" alt="Directus - The leading Headless Data Platform"><p>Directus called itself &quot;the leading Headless Data Platform&quot;, which is layers on top of any new or existing SQL database and introspects the schema, providing both GraphQL+REST APIs and a beautiful and intuitive GUI app ideal for technical and non-technical users.</p><p>You probably get the idea already. It is the world&apos;s leading modern, open-source data platform software.</p><p>In this post, I will give you my opinion about Directus from a developer&apos;s perspective. I have used it in one of my hobby projects. I liked it and planning to do more with it.</p><h3 id="why-you-might-need-this">Why you might need this?</h3><p>Any modern web project requires storing, managing, connecting, searching visualizing data. Directus provide all of that. It is a <strong><em>developer toolkit</em></strong> that enables you to develop virtually any data-driven project. </p><p>Writing the backend of any project requires a lot of time and resources. Using Directus, you will get <em><strong>instant API</strong></em> for all your data.</p><p><em><strong>Authentication</strong></em> and authorization are hard to implement. Directus gives you built-in authentication and <em><strong>Role Based Access Control</strong></em> for your data. You can create different roles and configure permissions for all CRUD operations. You can also manage users and assign them to any role you wish. So, if you are thinking about API about login or password resets, it is there.</p><p>In, the Data Model interface, you can <em><strong>model your database tables</strong></em> visually just like you normally do in any SQL database GUI. But in Directus, you can have much more options for: schema (relationship, constrain), field, interface (e.g autocomplete, map), display, validations, etc.</p><p>Like Zapier, you can <strong><em>automate anything</em></strong> by using its flow system. You can configure actions for any Data events (CRUD), webhook, schedule with CRON and transform and transfer data to another flow. It is possible to use javascript and bind dynamic values inside flow actions and also send emails.</p><p>A <em><strong>file manager</strong></em> is built-in where you can store files, edit images, create virtual folders, and configure storage using a local file system or S3-compatible service. Its file API gives you on-the-fly image resizing capability which also supports custom image transformation presets.</p><p>Now, imagine how much time you need to rebuild all of those features. You want to build the backend with an admin panel very quickly right? You should try Directus. It has also <strong><em>JS SDK</em></strong>, which helps you to interact with its API from any frontend framework.</p><p>But wait, rather than using only CRUD operations, you should implement your own business logic at the backend right? You can <em><strong>extend Directus</strong></em> and write custom endpoints, hooks, layouts, etc. It uses Node.JS in the backend and Vue.JS in the frontend for Data Studio.</p><p>It has all the great features, documentation is not bad, but lacks tutorials. They have a strong active community.</p><h3 id="composition">Composition</h3><p>Every Directus project comprises <strong><em>3 layers</em></strong></p><figure class="kg-card kg-image-card"><img src="https://directus.io/assets/img/layers.svg" class="kg-image" alt="Directus - The leading Headless Data Platform" loading="lazy"></figure><ul><li><strong>Data layer.</strong> Any new or existing SQL database. No vendor locking</li><li><strong>Data Engine &amp; API</strong> (REST &amp; GraphQL) for developers. It inspects database schema and provides you instant API, full CRUD (Create, Read, Update and Delete) operations, authentication, &#xA0;Role Based Access Control (RBAC), workflow automation, asset transformation, and much more.</li><li><strong>Data Studio</strong>. A beautiful no-code app for business users to browse, manage and visualize data. Technical users can model all the data and complex relationships using the GUI (Graphical User Interface).</li></ul><h3 id="common-use-cases-for-using-directus">Common use cases for using Directus</h3><ul><li>Headless CMS</li><li>Backend with Admin Panel</li><li>Building Internal Apps and Business Intelligence</li><li>SaaS Applications</li><li>Robotics and IoT devices</li><li>Games</li></ul><h3 id="free-cloud-hosting-instance">Free cloud hosting instance</h3><p>They have completely free cloud options where you can get an instance very quickly to get started or build a proof of concept. They have also paid options.</p><h3 id="self-hosting">Self-hosting</h3><p>Their source code is open on GitHub and you can install it on your own server like any node.js app. Also, their docker image is available on the docker hub.</p><p>Official Website: <a href="https://directus.io/?ref=gkibria.com">https://directus.io/</a></p><h3 id="take-a-look-at-their-video-demonstration"><strong>Take a look at their video demonstration</strong></h3><figure class="kg-card kg-embed-card"><iframe width="200" height="113" src="https://www.youtube.com/embed/viURaw3oiBA?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen title="Getting Started with Directus"></iframe></figure>]]></content:encoded></item><item><title><![CDATA[aaPanel performance test on DigitalOcean, Vultr, and Hetzner]]></title><description><![CDATA[I would like to share my recent experiment with aaPanel performance on DigitalOcean, Vultr, and Hetzner.]]></description><link>https://gkibria.com/article/aapanel-performance-test-on-digitalocean-vultr-and-hetzner/</link><guid isPermaLink="false">636933a7ad0b4d00010f2ccd</guid><category><![CDATA[devOps]]></category><category><![CDATA[Research]]></category><category><![CDATA[aaPanel]]></category><dc:creator><![CDATA[Mohammad Golam Kibria]]></dc:creator><pubDate>Mon, 07 Nov 2022 22:06:52 GMT</pubDate><media:content url="https://gkibria.com/content/images/2022/11/aaPanel-performance-testing.png" medium="image"/><content:encoded><![CDATA[<img src="https://gkibria.com/content/images/2022/11/aaPanel-performance-testing.png" alt="aaPanel performance test on DigitalOcean, Vultr, and Hetzner"><p>I have been using aaPanel for over a year on Oracle cloud. I have also used DigitalOcean droplet for over 8 years and have experience with Vultr and Hetzner. Last few months, I have been publishing different posts about aaPanel installing, reviewing, ghost installation, &#xA0;etc. I was thinking, Why not test aaPanel in different cloud providers? So, in this post, I would love to share my recent experiment with aaPanel performance on DigitalOcean, Vultr, and Hetzner.</p><div class="kg-card kg-callout-card kg-callout-card-grey"><div class="kg-callout-emoji">&#x1F4A1;</div><div class="kg-callout-text">All opinions in this post are from my observational study and are not influenced by any providers.</div></div><h2 id="objective">Objective</h2><blockquote class="kg-blockquote-alt">To find out which provider&apos;s entry-level VPS (virtual private server) is good for optimum aaPanel performance.</blockquote><h2 id="methodology">Methodology</h2><p>3 brand new entry-level VPS was created and aaPanel was installed on DigitalOcean, Vultr, and Hetzner one by one. Ubuntu 22.04 LTS was used as an Operating system across all of the VPS. aaPanel was installed using the command prompt. aaPanel installation script gives us the total installation time required. After installation, some software was installed (see the list below). The time required for all installations was recorded using a stopwatch. After installing all the software, each VPS was observed for 30 minutes. Performance data were obtained from the provider&apos;s usage graphs and aaPanel&apos;s built-in server monitoring graphs. Then it was manually calculated. VPS provider inclusion criteria were personal choice and ease of use.</p><h2 id="results">Results:</h2><p>To install aaPanel, DigitalOcean VPS took 2 minutes and others took 1 minute. The time to install the software was 64, 44, and 41 minutes for DigitalOcean, Vultr, and Hetzner respectively. During software installation, all of the VPS used 100% CPU while during idle time DigitalOcean used 7% of CPU. On the other hand, Vultr, and Hetzner used 14% of the CPU. </p><h3 id="time-required-during-installation">Time required during installation</h3><!--kg-card-begin: markdown--><table>
<thead>
<tr>
<th>Provider</th>
<th>aaPanel Install time</th>
<th>Software Install time</th>
</tr>
</thead>
<tbody>
<tr>
<td>DigitalOcean</td>
<td>2 mins</td>
<td>64 mins</td>
</tr>
<tr>
<td>Vultr</td>
<td>1 min</td>
<td>44 mins</td>
</tr>
<tr>
<td>Hetzner</td>
<td>1 min</td>
<td>41 mins</td>
</tr>
</tbody>
</table>
<!--kg-card-end: markdown--><h3 id="cpu-usage-comparison">CPU usage comparison</h3><!--kg-card-begin: markdown--><table>
<thead>
<tr>
<th>Provider</th>
<th>Max CPU load during installation</th>
<th>Avg CPU load during Idle</th>
</tr>
</thead>
<tbody>
<tr>
<td>DigitalOcean</td>
<td>100%</td>
<td>7%</td>
</tr>
<tr>
<td>Vultr</td>
<td>100%</td>
<td>14%</td>
</tr>
<tr>
<td>Hetzner</td>
<td>100%</td>
<td>14%</td>
</tr>
</tbody>
</table>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://gkibria.com/content/images/2022/11/aapanel-performance-vps.png" class="kg-image" alt="aaPanel performance test on DigitalOcean, Vultr, and Hetzner" loading="lazy" width="951" height="291" srcset="https://gkibria.com/content/images/size/w600/2022/11/aapanel-performance-vps.png 600w, https://gkibria.com/content/images/2022/11/aapanel-performance-vps.png 951w" sizes="(min-width: 720px) 720px"><figcaption>Time and resource usage</figcaption></figure><h3 id="entry-level-vps-resources-comparison">Entry-level VPS: resources comparison</h3><!--kg-card-begin: markdown--><table>
<thead>
<tr>
<th>provider</th>
<th>CPU</th>
<th>RAM</th>
<th>SSD</th>
<th>Bandwidth</th>
<th>Location</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<tr>
<td>DigitalOcean</td>
<td>1 CPU</td>
<td>1 GB</td>
<td>25 GB</td>
<td>1 TB</td>
<td>Germany</td>
<td>$6</td>
</tr>
<tr>
<td>Vultr</td>
<td>1 vCPU</td>
<td>1 GB</td>
<td>25 GB</td>
<td>1 TB</td>
<td>Germany</td>
<td>$5</td>
</tr>
<tr>
<td>Hetzner</td>
<td>1 vCPU</td>
<td>2 GB</td>
<td>20 GB</td>
<td>20 TB</td>
<td>Germany</td>
<td>$4.51</td>
</tr>
</tbody>
</table>
<!--kg-card-end: markdown--><p>Among the 3 providers, Vultr is lacking metrics in server monitoring.</p><h2 id="discussion">Discussion</h2><p>As an entry-level VPS, Hetzner seems to be a better choice in terms of price vs resource calculation. Hetzner and Vultr both seem to be more performant than DigitalOcean where Hetzner is slightly ahead of the race.</p><p>When installing software, aaPanel compile and build (other than CentOS 7) from the source within the server for the best performance and it will take time. In my case, I have used Ubuntu 22.04 LTS intentionally which will give a compilation guarantee. So, the time to take install software is a good indicator of measuring performance, in my opinion.</p><p>All the provider&apos;s control panels and user experience are somewhat the same but Hetzner has a very clearcut interface.</p><p>Including more VPS providers, using more deterministic factors, and performing statistical tests would definitely improve the findings.</p><h2 id="my-opinion">My Opinion</h2><p>For hobby projects and personal blogs (e.g ghost) hosting, any of the prover&apos;s VPS will be more than enough where aaPanel will be performing optimally. For production and high volume usage, use at least 4 GB RAM and 2 vCPUs.</p><h3 id="installed-software-list">Installed Software List</h3><ul><li>Nginx 1.21</li><li>MySQL 8.0</li><li>PHP 8.0</li><li>phpMyAdmin 5.0</li><li>Node Manager (aaPanel plugin)</li><li>Node.Js v18.2.1</li><li>Docker Manager (aaPanel plugin)</li></ul><hr><p><strong><em>Affiliate links</em></strong></p><p>If you want to try any of the providers for free, please use the following links. You will &#x2013; </p><ul><li>Get <a href="https://m.do.co/c/93635a74cca1?ref=gkibria.com">$200 free credits</a> on DigitalOcean.</li><li>Get <a href="https://www.vultr.com/?ref=9281549-8H">$100 free credits</a> on Vultr.</li><li>Get <a href="https://hetzner.cloud/?ref=fL49Pn0WX1O6">$20 free creadits</a> on Hetzner.</li></ul><p>Thanks &#x1F44B;</p>]]></content:encoded></item><item><title><![CDATA[I am migrating my site to self-hosted Ghost!]]></title><description><![CDATA[<p>Hi there!</p><p>I am currently migrating my site to self-hosted Ghost from WordPress.</p><p>I will write detail about why I made this decision.</p><p>Meanwhile, try exploring my site and give me your feedback.</p><p>Happy Halloween!</p>]]></description><link>https://gkibria.com/article/i-am-migrating-to-self-hosted-ghost/</link><guid isPermaLink="false">635f17c2c9f68c000185e6ed</guid><dc:creator><![CDATA[Mohammad Golam Kibria]]></dc:creator><pubDate>Mon, 31 Oct 2022 00:35:49 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1603516863860-7d5c93a83fe8?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDF8fGdob3N0fGVufDB8fHx8MTY2NzE3NjUwNQ&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1603516863860-7d5c93a83fe8?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDF8fGdob3N0fGVufDB8fHx8MTY2NzE3NjUwNQ&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="I am migrating my site to self-hosted Ghost!"><p>Hi there!</p><p>I am currently migrating my site to self-hosted Ghost from WordPress.</p><p>I will write detail about why I made this decision.</p><p>Meanwhile, try exploring my site and give me your feedback.</p><p>Happy Halloween!</p>]]></content:encoded></item><item><title><![CDATA[Install ghost on oracle cloud]]></title><description><![CDATA[<p>Ghost is a powerful, open-source blogging and content publishing platform. In this post, I will guide you to install ghost on oracle cloud and configure the domain, SSL, and backup strategy on Google Drive.</p><p>According to the official documentation, you can install ghost on different cloud providers like Digitalocean and</p>]]></description><link>https://gkibria.com/article/installing-ghost-on-oracle-cloud/</link><guid isPermaLink="false">63665308ad0b4d00010f27d8</guid><category><![CDATA[devOps]]></category><category><![CDATA[ghost]]></category><category><![CDATA[docker]]></category><category><![CDATA[aaPanel]]></category><dc:creator><![CDATA[Mohammad Golam Kibria]]></dc:creator><pubDate>Mon, 10 Oct 2022 18:23:00 GMT</pubDate><media:content url="https://gkibria.com/content/images/2022/11/blog-article-ghost.png" medium="image"/><content:encoded><![CDATA[<img src="https://gkibria.com/content/images/2022/11/blog-article-ghost.png" alt="Install ghost on oracle cloud"><p>Ghost is a powerful, open-source blogging and content publishing platform. In this post, I will guide you to install ghost on oracle cloud and configure the domain, SSL, and backup strategy on Google Drive.</p><p>According to the official documentation, you can install ghost on different cloud providers like Digitalocean and Linode very easily with one click. But you have to pay monthly for that and there is some hassle regarding backups and restores. I have chosen Oracle Cloud because they have a very attractive free tier.</p><p>Now, there are 2 ways of installing ghost on a Linux server. By using ghost CLI and using docker. In this post, I will go for the docker image option. </p><p>I will also use aaPanel hosting panel for this. This is also free and comes with great features. I have <a href="https://gkibria.com/article/aapanel-review-developers-perspective/">reviewed this panel</a> before and published <a href="https://gkibria.com/article/installing-aapanel-on-oracle-cloud-virtual-machine/">a comprehensive guide</a> on how to install it on oracle cloud.</p><h3 id="pre-requisites">Pre-requisites</h3><ul><li>Oracle VM with aaPanel installed. <a href="https://gkibria.com/article/installing-aapanel-on-oracle-cloud-virtual-machine/">Click here</a> for the aaPanel installation guide.</li><li>Some docker knowledge</li><li>Domain name for the blog added to Cloudflare, and Origin server certificate</li><li>Mailgun account for sending transitional emails</li><li>Google account for backup</li></ul><hr><h2 id="step-1-install-the-docker">Step 1: Install the docker</h2><p>If you followed the aaPanel installation guide, you now have a fresh copy of aaPanel with Nginx, MySQL, PHP, and phpMyAdmin installed. Now it&apos;s time to install docker. Follow the steps below.</p><ul><li>log in to the panel</li><li>go to the App stores of the panel</li><li>search for docker</li><li>install Docker manager.</li></ul><h2 id="step-2-domain-dns-record-setup">Step 2: Domain DNS record setup</h2><p>Since domain DNS will take some time to propagate, we will start with the domain. I recommend using Cloudflare as they have free features with free origin server certificates.</p><ul><li>Log in to the <strong>Cloudflare dashboard</strong></li><li>Add your domain to Cloudflare if you have not done yet</li><li>Add an <strong>A</strong> record to the server&apos;s <strong>public IP</strong> address. If you are planning to use the root domain, use @ in the name. I will be using a subdomain.</li><li>Be sure to check the <strong>proxy</strong> status is <strong>On</strong>.</li><li>Go to the <strong>SSL/TLS</strong> section of your domain, and click <strong>origin server</strong>. Now <strong>create a cretificate</strong> for your domain. After generating, save the <strong>Private key</strong> and <strong>Certificate</strong> in a file. We will need these to install SSL and reverse proxy later.</li></ul><h2 id="step-3-set-up-mysql-database">Step 3: Set up MySQL database</h2><p>Come back to the aaPanel. In this step, we will create a database for ghost. Please write down the database info, we need it later. Follow the steps.</p><ul><li>Navigate to the database and click Add Database</li><li>Write the <strong>DB Name</strong>: ghost_data, <strong>username</strong>: ghost_data, and write down all the database info.</li><li>Click Submit</li></ul><p>This will create a database. Don&apos;t forget to change the DB name, username, and password according to your choice.</p><h2 id="step-4-pull-the-ghost-docker-image">Step 4: Pull the ghost docker image</h2><p>In this step, we will pull the ghost latest image from the docker hub. To do so:</p><ul><li>In the aaPanel, go to the Docker page and navigate to the Image tab</li><li>Click the <strong>Pull Image</strong> button</li><li>Enter the image name <strong>ghost:latest</strong> and click submit</li></ul><p>This will pull the latest ghost image and save it to the server.</p><h2 id="step-5-compose-the-template">Step 5: Compose the template</h2><p>In this step, we will write a docker-compose template with all the configuration options of ghost and persistent storage with docker volume.</p><ul><li>On aaPanel, go to the Compose template tab on the docker page and click Add Button</li><li>Write the template name: <strong>ghost</strong> and remark: <strong>ghost template</strong> and paste the following code into the content.</li></ul><pre><code class="language-yaml">version: &apos;3.3&apos;

services:

  ghost:
    image: ghost:latest
    restart: always
    ports:
      - 2368:2368
    environment:
      # see https://ghost.org/docs/config/#configuration-options
      database__client: mysql
      database__connection__host: server_public_ip
      database__connection__user: database_user
      database__connection__password: database_pass
      database__connection__database: database_name
      
      #url change your domain
      url: https://yourdomain.com
      
      #mail
      mail__transport: SMTP
      mail__options__host: smtp_host
      mail__options__secure: false
      mail__options__port: 587
      mail__options__service: SES
      mail__options__auth__user: smtp_user
      mail__options__auth__pass: smtp_pass

      #NODE_ENV: development
    volumes:
      - /www/ghost_blog:/var/lib/ghost/content</code></pre><p>Do not forget to change the server_public_ip, database_user, database_pass, and database_name with the info you saved while creating the database. Change your domain and mail-sending info from Mailgun or other providers.</p><h2 id="step-6-run-the-container-from-the-template">Step 6: Run the container from the template</h2><p>In this step, we will create and run a container from the template. Follow the steps-</p><ul><li>In aaPanel, go to the compose tab and click <strong>Add compose project</strong></li><li>In the dialog, select ghost as a template, enter ghost for name and click submit. You can see a project named ghost started with 1 container with it.</li><li>A minute later, go to the container tab. &#xA0;you might see container status is stopped. Let&apos;s examine the container log. Click the <strong>log</strong> link, on the right side of the container. You might see a database connection error. This is because database permission is set to local (when we created it) or there may be some port issue. Let&apos;s delete this project for now and fix all these issues in the next step. For this, click the <strong>delete</strong> link next to the log link.</li></ul><h2 id="step-7-open-the-port-on-the-security-group-on-oracle">Step 7: Open the port on the security group on oracle</h2><p>On line 9, of the docker-compose file, we exposed the 2368 port on the host. So we need to open this port. Follow this <a href="https://gkibria.com/article/installing-aapanel-on-oracle-cloud-virtual-machine/#step-3-open-ports-in-the-firewall">instruction</a>. Make sure MySQL port 3306 is there.</p><p>Next, come back to aaPanel to release ports from inside the server. Go to the security page, and open the 3306 and 2368 ports in the Firewall section. For example, type 3306 in the port, MySQL in the description, and click open. Do a similar thing for ghost port.</p><p>Next, go to the database page and modify the permission from the <strong>local server</strong> to the <strong>Specified IP</strong> and enter the server&apos;s public IP. Save the changes.</p><p>Next, perform step 6 again. In the log, you now see no error, and ghost is running fine.</p><h2 id="step-8-reverse-proxy-with-nginx">Step 8: Reverse proxy with Nginx</h2><p>In this step, we will set up a reverse Nginx proxy. It will proxy all the requests from our blog domain to http://localhost:2368. To configure SSL, we need a Cloudflare origin server certificate from step 2.</p><ul><li>Go to the website page on aaPanael, and click <strong>add site</strong> under PHP project.</li><li>Enter the <strong>domain</strong>, FTP - no, Database - No, PHP version - <strong>static</strong>, and click submit. Refresh the page, you can see a new site is created.</li><li>Click the site name. The site config dialog will open.</li><li>Go to SSL &gt; <strong>Other certificate</strong>, paste the <strong>Private key</strong> and <strong>Certificate</strong> and Save.</li><li>Turn <strong>On</strong> the Force HTTPS option.</li><li>Go to the Reverse proxy section and <strong>add a proxy</strong>.</li><li>Enter the proxy name: <strong>ghost</strong>, target URL: <strong>http://localhost:2368</strong>, and submit.</li></ul><p>Test your domain in the browser and you should see your new ghost blog website. Now you have successfully configured a reverse proxy for the ghost docker container. The next step is optional but very important.</p><h2 id="step-9-configure-backup">Step 9: Configure backup</h2><p>In this section, we will configure a backup for our newly created ghost blog with cron. In aaPanel, there are several plugins for that - Google Drive, S3, and remote FTP. Feel free to use whatever you like. But I would go for Google Drive. </p><p>First, you have to install the plugin in aaPanel. Go to App Store, search for google drive and install the plugin. After installation, click the settings. Complete the Google Drive verification process according to the instruction.</p><p>Now we will create 2 cron tasks for the backup - one for the database and the other for the ghost directory (/www/ghost_blog) in our server.</p><h3 id="database-backup">Database Backup</h3><p>Go to the Cron page of aaPanel and add a task according to the instruction:</p><ul><li>Type of Task: <strong>Backup Database</strong></li><li>Execution cycle: choose how you want to backup</li><li>Backup database: select the <strong>ghost_data</strong> or all</li><li>Backup to: <strong>Google Drive</strong></li><li>save the task</li></ul><h3 id="directory-backup">Directory Backup</h3><p>Go to the Cron page of aaPanel and add a task according to the instruction:</p><ul><li>Type of Task: <strong>Backup Directory</strong></li><li>Execution cycle: choose how you want to backup</li><li>Directory to backup: select <strong>/www/ghost_blog/</strong></li><li>Backup to: <strong>Google Drive</strong></li><li>save the task</li></ul><p>The tasks will now be available in the task list. To test a task, click <strong>execute</strong> link and wait for some time. You will see your backup is now uploaded to Google Drive.</p><h2 id="step-10-update-ghost">Step 10: Update Ghost</h2><p>Updating a ghost is really easy. follow the steps.</p><ul><li>Remove the existing container in aaPanel (docker &gt; container &gt; delete).</li><li>Remove the existing ghost image (docker &gt; image &gt; delete).</li><li>Create a new container again using the template.</li></ul><p>This should download the latest image from the docker hub and create a new container using the template.</p><p>Note: If you want to upgrade to a specific version, adjust your ghost version in the template from ghost:latest to ghost:5.25.5 for example. Then follow the above steps.</p><p>You can see the available version in <a href="https://hub.docker.com/_/ghost?ref=gkibria.com">the docker hub</a>.</p><hr><p>Congratulations! You now successfully installed a ghost blog on oracle cloud and configured the SSL, reverse proxy, and backup strategy to Google Drive. Now go to your ghost admin panel by visiting yourdomain.com/ghost/</p><h3 id="video-guide">Video Guide</h3><figure class="kg-card kg-embed-card"><iframe width="200" height="150" src="https://www.youtube.com/embed/NoFeuO5iND8?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen title="install ghost on oracle cloud with aaPanel"></iframe></figure><p>cheers &#x1F44B;</p>]]></content:encoded></item><item><title><![CDATA[SBA Quiz]]></title><description><![CDATA[<p>A hobby project to exercise the react knowledge with context API.</p><p>App has the following features so far...</p><ul><li>User registration, login, password reset</li><li>Browsing the public quiz</li><li>Browsing and filtering quizzes in quiz admin</li><li>Quiz CRUD (todo), Quiz play (todo), etc.</li></ul><hr><h3 id="technology-used">Technology Used</h3><ul><li>Frontend: React.Js, Bulma, CSS, HTML</li><li>Backend:</li></ul>]]></description><link>https://gkibria.com/portfolio/sba-quiz/</link><guid isPermaLink="false">63627647ad0b4d00010f2213</guid><category><![CDATA[Portfolio]]></category><category><![CDATA[React.js]]></category><category><![CDATA[Directus.io]]></category><category><![CDATA[Database]]></category><dc:creator><![CDATA[Mohammad Golam Kibria]]></dc:creator><pubDate>Tue, 12 Jul 2022 13:06:00 GMT</pubDate><media:content url="https://gkibria.com/content/images/2022/11/sba-quiz.png" medium="image"/><content:encoded><![CDATA[<img src="https://gkibria.com/content/images/2022/11/sba-quiz.png" alt="SBA Quiz"><p>A hobby project to exercise the react knowledge with context API.</p><p>App has the following features so far...</p><ul><li>User registration, login, password reset</li><li>Browsing the public quiz</li><li>Browsing and filtering quizzes in quiz admin</li><li>Quiz CRUD (todo), Quiz play (todo), etc.</li></ul><hr><h3 id="technology-used">Technology Used</h3><ul><li>Frontend: React.Js, Bulma, CSS, HTML</li><li>Backend: Directus</li><li>Database: MySQL</li></ul><h3 id="what-i-did">What I did</h3><p>For the frontend, I created react UI using Bulma CSS framework, custom Notification context API, written various custom react hooks for Axios client, user authentication, quiz admin, etc.</p><p>For the backend, I used Directus where I modeled all the databases tables. Directus has a js client but I have used the REST interface. Also configured authorization permission there. To learn more about Directus, <a href="https://directus.io/?ref=gkibria.com">click here</a>.</p><p>Project URL: <a href="https://sba-quiz-frontend-react.pages.dev/?ref=gkibria.com">https://sba-quiz-frontend-react.pages.dev/</a></p><p>Source code: <a href="https://github.com/gkibria/sba_quiz_frontend_react?ref=gkibria.com">https://github.com/gkibria/sba_quiz_frontend_react</a></p>]]></content:encoded></item><item><title><![CDATA[Installing aaPanel on oracle cloud virtual machine]]></title><description><![CDATA[<p>aaPanel is a free and open-source hosting control panel that can be installed on popular Linux distributions like Ubuntu, CentOS, Debian, etc. In this post, I would like to tell you step by step to installation instructions.</p><p>You can use any cloud provider for this but I am using the</p>]]></description><link>https://gkibria.com/article/installing-aapanel-on-oracle-cloud-virtual-machine/</link><guid isPermaLink="false">6364f837ad0b4d00010f24d9</guid><category><![CDATA[devOps]]></category><category><![CDATA[aaPanel]]></category><dc:creator><![CDATA[Mohammad Golam Kibria]]></dc:creator><pubDate>Wed, 29 Jun 2022 17:48:00 GMT</pubDate><media:content url="https://gkibria.com/content/images/2022/11/oracle-cloud-aapanel-installation.png" medium="image"/><content:encoded><![CDATA[<img src="https://gkibria.com/content/images/2022/11/oracle-cloud-aapanel-installation.png" alt="Installing aaPanel on oracle cloud virtual machine"><p>aaPanel is a free and open-source hosting control panel that can be installed on popular Linux distributions like Ubuntu, CentOS, Debian, etc. In this post, I would like to tell you step by step to installation instructions.</p><p>You can use any cloud provider for this but I am using the oracle cloud free tier. They have very attractive free cloud resources that you probably don&apos;t know. In summary, you can get </p><ul><li>2 AMD-based VMs with 1 GB ram each</li><li>Arm-based Ampere A1 cores and 24 GB of memory usable as 1 VM or up to 4 VMs with 3,000 OCPU hours and 18,000 GB hours per month</li><li>2 Block Volumes Storage, 200 GB total</li><li>And many more. Check out their <a href="https://www.oracle.com/cloud/free/?ref=gkibria.com">offerings</a>.</li></ul><h3 id="pre-requisites">Pre-requisites</h3><ul><li>An oracle cloud free tier account</li><li>knowledge of some basic Linux commands</li></ul><h2 id="step-1-creating-the-vm">Step 1: Creating the VM</h2><p>In this step, we will create a new AMD-based VM, with <strong>CentOS 7</strong> image. You can use other images (Ubuntu, Oracle Linux, CentOS 8, etc.) also. But there is a benefit to using CentOS 7. Later, when you install server software (Nginx, MySQL, etc.), aaPanel will give you 2 options - <strong>Fast</strong> and <strong>Compile</strong>. Fast will use pre-compiled binaries that are very fast to install but compile options are very stable because it will download sources, and compile them according to your server environment. </p><div class="kg-card kg-callout-card kg-callout-card-grey"><div class="kg-callout-emoji">&#x1F4A1;</div><div class="kg-callout-text">If you use CentOS 7, installation of the subsequent software on aaPanel will be significantly fast. Otherwise, compilation will be done which will be time-consuming and resource intensive.</div></div><p>Let&apos;s create the VM.</p><ul><li>Log In to your oracle cloud console</li><li>Go to your <a href="https://cloud.oracle.com/compute/instances?ref=gkibria.com">compute instance</a> page and click <strong>create instance</strong> button.</li><li>Chose a name of the instance, e.g. aapanel-centos-7</li><li>Edit the Image and Shape &gt; click <strong>Change image</strong> &gt; Select <strong>CentOS</strong>, OS version to <strong>7</strong> &gt; click <strong>Select image</strong></li><li>Under <strong>Add SSH keys</strong>, you can <strong>generate key pairs</strong> (default option) if you haven&apos;t already done so. Download the private and public keys and keep them in a separate folder. This will be needed later to log in to the server. If you already have those keys, select <strong>upload public key</strong> and chose .pub file.</li><li>Finally, click <strong>create</strong> button. This will start the process and a few minutes later, your instance will be ready to install aaPanel.</li></ul><h2 id="step-2-installing-aapanel">Step 2: Installing aaPanel</h2><p>In this step, we will log in to our newly created VM, update the server software, and install aaPanel. For this, we need some info - server_public_ip, username, and the private key that you used during the creation of the VM. You will find this information on the instance page under the <strong>instance access</strong> heading.</p><ul><li>Open your terminal or command prompt and navigate to the folder where you kept the SSH keys</li><li>Log in to the VM using the following command. Replace <strong>username</strong>, <strong>server_public_ip</strong>, and <strong>your_private.key</strong> with your own info.</li></ul><pre><code class="language-bash">ssh username@server_public_ip -i your_private.key</code></pre><ul><li>Switch to the root user</li></ul><pre><code class="language-bash">sudo su -</code></pre><ul><li>Update the server </li></ul><pre><code class="language-bash">yum update</code></pre><ul><li>Install the aaPanel by entering the following code</li></ul><pre><code class="language-bash">yum install -y wget &amp;&amp; wget -O install.sh http://www.aapanel.com/script/install_6.0_en.sh &amp;&amp; bash install.sh aapanel</code></pre><h3 id="installation-prompts">installation prompts</h3><p>The installation will prompt you for some info and confirmations. Here are my response</p><ul><li>installation directory /www - <strong>y</strong></li><li>panel SSL - <strong>N</strong> (will configure it later)</li></ul><p>If everything goes well, the installation process will end in around 8 minutes. After installation is finished, you will find some login credentials and ports information. <strong>Save this info</strong>, you need it for accessing the panel.</p><h2 id="step-3-open-ports-in-the-firewall">Step 3: Open ports in the firewall</h2><p>You will find some port information from the previous step. You need to open these ports in the cloud provider&apos;s firewall. In our case, <em>default security list</em>. To find this page, search the keyword <strong>security list</strong> in the search box on the console. Alternatively, you can go there from the instance detail page &gt; virtual cloud network &gt; security lists under resources.</p><p>In the security list page, you must <strong>Add Ingress Rules</strong> for all the ports according to the following table</p><!--kg-card-begin: markdown--><table>
<thead>
<tr>
<th>source type</th>
<th>source CIDR</th>
<th>IP protocol</th>
<th>Destination port range</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>CIDR</td>
<td>0.0.0.0/0</td>
<td>TCP</td>
<td>port</td>
<td>aapanel</td>
</tr>
</tbody>
</table>
<!--kg-card-end: markdown--><h2 id="step-4-installing-software-modules">Step 4: Installing software modules</h2><p>Now log in to the newly installed aapanel using the credentials. Immediately after login, you will be prompted to install the necessary stack (LNMP/LAMP). Choose your stack. For example, I will go for Nginx, MySQL 8, PHP 8, and phpMyAdmin 5. And never forget to check for the <strong>FAST</strong> option to install from binary.</p><h2 id="step-5-installing-ssl-and-panel-domain">Step 5: Installing SSL and panel domain</h2><p>In this step, you need a domain name, to install SSL in your panel. You can use a subdomain also. I prefer to add a subdomain rather than a domain as a panel URL. </p><ul><li>Add an <strong>A record</strong> to your domain DNS pointing to the server&apos;s <strong>Public IP</strong>. If you are using Cloudflare, be sure to uncheck the proxy.</li><li>In the aaPanel, go to <strong>Settings</strong>. Enter the selected domain in the domain text field under the security tab. When you click save, the panel will set the domain and you can no longer access it with the IP address. So, you may see a blank page. Replace the IP with your domain in the browser&apos;s address bar and log in again.</li><li>Now let&apos;s install SSL. Go to the settings, and click the Panel SSL switch under the security section. A dialog window will appear. Select the let&apos;s encrypt option, enter your email, check the terms, and submit. After a few moments, your panel will reload with the HTTPS protocol.</li></ul><p>In certain cases, you may get some errors. If you can&apos;t log in to the panel, try removing the SSL options. Log in to the server via SSH, and enter the following command.</p><pre><code class="language-bash">rm -f /www/server/panel/data/ssl.pl &amp;&amp; /etc/init.d/bt restart</code></pre><p>Other panel ssh commands can be found <a href="https://www.aapanel.com/new/download.html?ref=gkibria.com">here</a>.</p><h3 id="congratulations">Congratulations!</h3><p>If you have come so far, I now have a clean copy of aaPanel installed with the necessary software and SSL.</p><h3 id="video-demo">Video demo</h3><figure class="kg-card kg-embed-card"><iframe width="200" height="150" src="https://www.youtube.com/embed/ri22jwFxFW4?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen title="Installing aaPanel on oracle cloud virtual machine"></iframe></figure><p>For full features and review, <a href="https://gkibria.com/article/aapanel-review-developers-perspective/">click here</a> for my other post.</p>]]></content:encoded></item><item><title><![CDATA[aaPanel review: Developer's perspective]]></title><description><![CDATA[<p>Hi good people! aaPanel is a free and open-source server control panel that I am using for about 2 years and I am very much satisfied with it. In this post, I am going to tell you why I like this, what are the features, why it beats the other</p>]]></description><link>https://gkibria.com/article/aapanel-review-developers-perspective/</link><guid isPermaLink="false">6363b8f2ad0b4d00010f22a5</guid><category><![CDATA[devOps]]></category><category><![CDATA[aaPanel]]></category><dc:creator><![CDATA[Mohammad Golam Kibria]]></dc:creator><pubDate>Sat, 25 Jun 2022 14:39:00 GMT</pubDate><media:content url="https://gkibria.com/content/images/2022/11/aaPanel.png" medium="image"/><content:encoded><![CDATA[<img src="https://gkibria.com/content/images/2022/11/aaPanel.png" alt="aaPanel review: Developer&apos;s perspective"><p>Hi good people! aaPanel is a free and open-source server control panel that I am using for about 2 years and I am very much satisfied with it. In this post, I am going to tell you why I like this, what are the features, why it beats the other free options, and when it might not be a good option.</p><p>Developer must host their project on a server for production or staging called deployment. There are many hosted deployment solutions out there that are very easy to get started but cost you more money down the line. If your project is successful, and you have steady revenue, hosted deployment solution is the best, because you don&apos;t have to worry about the server management tasks. On the contrary, if your projects are a hobby or in development mode, a self-hosted server is a good option in my opinion. Because down the line, you will learn some DevOps things and save lots of money. aaPanel has some great features that will blow your mind.</p><h3 id="features-of-aapanel">Features of aaPanel:</h3><ul><li><strong>Modular structure:</strong> Unlike other free control panels (cyberpanel, hestia etc.), aaPanel is modular and can be extended features via its plugins. For example, if you need docker, you can install it.</li><li><strong>Multiple Databases:</strong> MySQL, MariaDB, PostgreSQL, MongoDB, and Redis can be installed on the same instance. For MySQL or MariaDB, phpMyAdmin can also be installed. Database instance&apos;s access permission (local/remote) can also be changed per database wise.</li><li><strong>Choice of web servers:</strong> Apache, Nginx, or OpenLiteSpeed can be installed.</li><li><strong>Website / Webapp Hosting:</strong> From static to PHP, Laravel and Node.JS apps can be hosted very easily. </li><li><strong>SSL cert:</strong> Let&apos;s encrypt or any other SSL can be installed for every website and node app.</li><li><strong>Nginx configuration and reverse proxy:</strong> Every website&apos;s Nginx config as well as global Nginx config and reverse proxy can be configured very easily. </li><li><strong>Node Manager:</strong> Multiple Node.JS versions can be installed and can be configured per website wise. Also, the command line version can be set.</li><li><strong>Docker:</strong> Docker file and docker composer are supported. You can set a separate docker registry. Docker images, containers, volumes, compose files everything can be used in GUI.</li><li><strong>Server File Manager:</strong> aaPanel&apos;s file manager is the best ever. You can upload, download, zip/unzip, modify permission, restore files, and last but not least, you can edit files with a beautiful interface. Unlike many other panels (cyberpanel), this feature is free.</li><li><strong>Backup and restore:</strong> Every website, database, and even any server folder can be backed up both in the local filesystem or remote location. It supports, google drive, google cloud storage, s3 or s3 compatible options, and FTP.</li><li><strong>Server monitoring:</strong> Server load average, CPU, memory, disk I/O, and network I/O can be monitored with a predefined or custom time frame.</li><li><strong>Security:</strong> Firewall GUI can be used to open and close ports. SSH port can also be changed and the entire SSH access can be disabled. Any security or updates of the panel can be easily applied with one click.</li></ul><h3 id="my-favorite-features">My Favorite Features</h3><p>Among all the features, I like modular structure, multiple database and web server, NodeJS version manager and app hosting, server file manager, Nginx reverse proxy config, and backup and restore.</p><h3 id="the-things-i-do-not-like">The things I do not like</h3><ul><li><strong>No Git:</strong> Git is a must feature and I don&apos;t know why they are not implementing it. You can install it by command prompt. But a GUI and integration of git to the website deployment (CD/CI) options would be great. I heard that using their webhook plugin, CD/CI can be configured but never tried.</li><li>Free <strong>Docker manager</strong> has very limited functionality. All the docker features that I have mentioned above are going to be paid options soon.</li><li>No <strong>one-click-install</strong> to different cloud providers.</li></ul><h3 id="why-it-might-beat-the-competitors">Why it might beat the competitors?</h3><p>aaPanel might beat its competitors because of its clean interface, ease to use, stability, and modular structure. They have paid modules that will give sustainability to maintain future releases.</p><h3 id="when-you-dont-need-to-use-it">When you don&apos;t need to use it?</h3><p>aaPanel is not good for any kind of hosting business where you need to configure packages for your users and your users need a separate control panel. No Resellers options etc. I think aaPanel is not designed for that.</p><h3 id="conclusion">Conclusion</h3><p>I am happy and satisfied with aaPanel. I can do whatever I like on my server very easily. If you are a developer you must try it. I bet, &#xA0;you are gonna love it.</p><div class="kg-card kg-callout-card kg-callout-card-yellow"><div class="kg-callout-emoji">&#x1F4A1;</div><div class="kg-callout-text">I am not affiliated with aaPanel. All those words are my own learned lesson.</div></div><p>aaPanel Link: <a href="https://www.aapanel.com/new/index.html?ref=gkibria.com">https://www.aapanel.com/new/index.html</a></p><div class="kg-card kg-callout-card kg-callout-card-grey"><div class="kg-callout-emoji">&#x1F4A1;</div><div class="kg-callout-text">I will make a few posts about aaPanel. If you like, please subscribe.</div></div>]]></content:encoded></item><item><title><![CDATA[Cheems X dApp - version 1]]></title><description><![CDATA[<p>A web 3 dashboard to show users&apos; assets and other information.</p><p>The following features were implemented:</p><ul><li>User login by Metamask</li><li>show the current balance of cheemsX</li><li>Total reflection</li><li>Total burnt</li><li>Total LP</li><li>Total Market Cap</li></ul><hr><h3 id="technology-used">Technology Used</h3><ul><li>Frontend: React, NextJS</li><li>Backend: Avalanche Blockchain, Moralis.io</li><li>Database: Moralis.io</li></ul><h3 id="what-i-did">What</h3>]]></description><link>https://gkibria.com/portfolio/cheemsx-dapp-v-1/</link><guid isPermaLink="false">63615006ad0b4d00010f21a0</guid><category><![CDATA[Portfolio]]></category><category><![CDATA[React.js]]></category><category><![CDATA[Next.js]]></category><category><![CDATA[Blockchain]]></category><dc:creator><![CDATA[Mohammad Golam Kibria]]></dc:creator><pubDate>Sat, 04 Jun 2022 22:00:00 GMT</pubDate><media:content url="https://gkibria.com/content/images/2022/11/cheemx-dApp.png" medium="image"/><content:encoded><![CDATA[<img src="https://gkibria.com/content/images/2022/11/cheemx-dApp.png" alt="Cheems X dApp - version 1"><p>A web 3 dashboard to show users&apos; assets and other information.</p><p>The following features were implemented:</p><ul><li>User login by Metamask</li><li>show the current balance of cheemsX</li><li>Total reflection</li><li>Total burnt</li><li>Total LP</li><li>Total Market Cap</li></ul><hr><h3 id="technology-used">Technology Used</h3><ul><li>Frontend: React, NextJS</li><li>Backend: Avalanche Blockchain, Moralis.io</li><li>Database: Moralis.io</li></ul><h3 id="what-i-did">What I did</h3><p>Convert the supplied design into NextJS, designed the Backend DB, wrote backend code using Javascript and implemented all the features.</p><p>Project URL: <a href="https://web.archive.org/web/20220527125727/https://app.cheemsx.org/">https://web.archive.org/web/20220527125727/https://app.cheemsx.org/</a></p>]]></content:encoded></item><item><title><![CDATA[Best public DNS servers]]></title><description><![CDATA[<p>DNS servers resolve a hostname to an IP address. There are many free publicly available DNS Servers out there. If you have a problem with your local ISP&apos;s DNS server, you can use the following DNS server.</p><h3 id="google-dns">Google DNS</h3><ul><li>Primary: 8.8.8.8</li><li>Secondary: 8.8.4.</li></ul>]]></description><link>https://gkibria.com/article/best-public-dns-servers/</link><guid isPermaLink="false">635c42471c85d700015b4d7e</guid><category><![CDATA[devOps]]></category><dc:creator><![CDATA[Mohammad Golam Kibria]]></dc:creator><pubDate>Sun, 01 May 2022 21:09:00 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1544197150-b99a580bb7a8?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDl8fHNlcnZlcnxlbnwwfHx8fDE2NjcxNzQ0OTQ&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1544197150-b99a580bb7a8?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDl8fHNlcnZlcnxlbnwwfHx8fDE2NjcxNzQ0OTQ&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="Best public DNS servers"><p>DNS servers resolve a hostname to an IP address. There are many free publicly available DNS Servers out there. If you have a problem with your local ISP&apos;s DNS server, you can use the following DNS server.</p><h3 id="google-dns">Google DNS</h3><ul><li>Primary: 8.8.8.8</li><li>Secondary: 8.8.4.4</li></ul><h3 id="opendns">OpenDNS</h3><ul><li>Primary: 208.67.222.222</li><li>Secondary: 208.67.220.220</li></ul><h3 id="cloudflare">Cloudflare</h3><ul><li>Primary: 1.1.1.1</li><li>Secondary: 1.0.0.1</li></ul><h3 id="comodo-secure-dns">Comodo Secure DNS</h3><ul><li>Primary: 8.26.56.26</li><li>Secondary: 8.20.247.20</li></ul><h3 id="quad9">Quad9</h3><ul><li>Primary: 9.9.9.9</li><li>Secondary: 149.112.112.112</li></ul><p>Tell me which one suits you better. </p><p>Cheers &#x1F44B;</p>]]></content:encoded></item><item><title><![CDATA[Strapi: Exposing custom user data in 'users/me' endpoint]]></title><description><![CDATA[<p>If you don&#x2019;t know about <a href="https://strapi.io/?ref=gkibria.com">Strapi</a>, It is a powerful and popular NodeJS headless CMS that was built with the aim to &#x201C;Design APIs fast, manage content easily&#x201D;.</p><p>On its &#x2018;users/me&#x2019; endpoint, it returns sanitized user info without any related data. If you</p>]]></description><link>https://gkibria.com/article/strapi-exposing-custom-user-data-in-users-me-endpoint/</link><guid isPermaLink="false">6357ba3e36d5be0001d97150</guid><category><![CDATA[Node.js]]></category><category><![CDATA[Strapi]]></category><dc:creator><![CDATA[Mohammad Golam Kibria]]></dc:creator><pubDate>Sat, 28 Aug 2021 19:55:25 GMT</pubDate><content:encoded><![CDATA[<p>If you don&#x2019;t know about <a href="https://strapi.io/?ref=gkibria.com">Strapi</a>, It is a powerful and popular NodeJS headless CMS that was built with the aim to &#x201C;Design APIs fast, manage content easily&#x201D;.</p><p>On its &#x2018;users/me&#x2019; endpoint, it returns sanitized user info without any related data. If you need additional related data to be exposed, you have to override the &#x2018;me&#x2019; function manually. For this, you have to create a file in a specific folder and create a new function with the same name.</p><p>File location: <strong>extensions/users-permissions/controllers/User.js</strong></p><pre><code class="language-javascript">const { sanitizeEntity } = require(&apos;strapi-utils&apos;);

const sanitizeUser = user =&gt;
  sanitizeEntity(user, {
    model: strapi.query(&apos;user&apos;, &apos;users-permissions&apos;).model,
  });

module.exports = {
  async me(ctx) {
    const user = ctx.state.user;

    if (!user) {
      return ctx.badRequest(null, [{ messages: [{ id: &apos;No authorization header was found&apos; }] }]);
    }

    const userQuery = await strapi.query(&apos;user&apos;, &apos;users-permissions&apos;);
    const userWithMedia = await userQuery.findOne({ id: ctx.state.user.id });

    const data = sanitizeUser(userWithMedia, { model: userQuery.model });
    ctx.send(data);
  },
};</code></pre><p>This will return all related fields. Feel free to modify it according to your needs. Happy Strapi-ing.. &#x1F642;</p>]]></content:encoded></item></channel></rss>