<?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"><channel><title><![CDATA[Fiko Borizqy (Bestafiko)]]></title><description><![CDATA[I wrote these tutorials for myself in future when I forget for the next steps.]]></description><link>https://fiko.me</link><generator>RSS for Node</generator><lastBuildDate>Tue, 14 Apr 2026 20:49:28 GMT</lastBuildDate><atom:link href="https://fiko.me/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Setting Up Local HTTPS with mkcert on macOS]]></title><description><![CDATA[When developing web applications locally, HTTPS is often overlooked. Yet, modern browsers and APIs increasingly require secure connections—even in development. That’s where mkcert comes in: a simple t]]></description><link>https://fiko.me/setting-up-local-https-with-mkcert-on-macos</link><guid isPermaLink="true">https://fiko.me/setting-up-local-https-with-mkcert-on-macos</guid><category><![CDATA[SSL]]></category><category><![CDATA[https]]></category><category><![CDATA[macOS]]></category><dc:creator><![CDATA[Fiko Borizqy]]></dc:creator><pubDate>Wed, 25 Feb 2026 00:51:19 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/61a439839ac0d611876b1234/9e9fee13-4717-4217-b3a3-8fe479254b8b.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When developing web applications locally, HTTPS is often overlooked. Yet, modern browsers and APIs increasingly require secure connections—even in development. That’s where <strong>mkcert</strong> comes in: a simple tool to generate locally trusted SSL certificates without hassle.</p>
<p>In this post, I’ll walk you through installing mkcert on macOS, generating certificates for <code>localhost</code>, and explain why organizing them in the mkcert directory matters.</p>
<hr />
<h2>🚀 Installing mkcert on macOS</h2>
<p>mkcert is lightweight and easy to set up. Here’s how:</p>
<ol>
<li><p><strong>Install Homebrew</strong> (if you don’t already have it):</p>
<pre><code class="language-bash">/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
</code></pre>
</li>
<li><p><strong>Install mkcert and nss (needed for Firefox trust store):</strong></p>
<pre><code class="language-bash">brew install mkcert
brew install nss
</code></pre>
</li>
<li><p><strong>Create and install a local CA (Certificate Authority):</strong></p>
<pre><code class="language-bash">mkcert -install
</code></pre>
<p>This step generates a root CA and adds it to your system and browser trust stores. You’ll see files like <code>rootCA.pem</code> and <code>rootCA-key.pem</code> stored in:</p>
<pre><code class="language-plaintext">~/Library/Application Support/mkcert/
</code></pre>
</li>
</ol>
<hr />
<h2>🛠 Generating a Localhost Certificate</h2>
<p>Once mkcert is installed, creating a certificate for <code>localhost</code> is straightforward:</p>
<pre><code class="language-bash">mkcert localhost
</code></pre>
<p>Output:</p>
<pre><code class="language-plaintext">Created a new certificate valid for the following names 📜
 - "localhost"

The certificate is at "./localhost.pem" and the key at "./localhost-key.pem" ✅
It will expire on 25 May 2028 🗓
</code></pre>
<p>You now have two files:</p>
<ul>
<li><p><code>localhost.pem</code> → the certificate</p>
</li>
<li><p><code>localhost-key.pem</code> → the private key</p>
</li>
</ul>
<hr />
<h2>📂 Organizing Certificates</h2>
<p>To keep things tidy and ensure recognition by browsers, move your generated files into mkcert’s support directory:</p>
<pre><code class="language-bash">mv localhost.pem ~/Library/Application\ Support/mkcert/
mv localhost-key.pem ~/Library/Application\ Support/mkcert/
</code></pre>
<p>Now your certificates live alongside the root CA:</p>
<pre><code class="language-plaintext">~/Library/Application Support/mkcert/
├── rootCA.pem
├── rootCA-key.pem
├── localhost.pem
└── localhost-key.pem
</code></pre>
<h3>🔎 Why move them here?</h3>
<p>Browsers trust certificates signed by mkcert’s root CA <strong>only if they’re managed within mkcert’s directory structure</strong>. By placing your <code>localhost.pem</code> and <code>localhost-key.pem</code> inside <code>~/Library/Application Support/mkcert/</code>, you ensure that mkcert’s trust chain is consistent and browsers recognize the certificates as valid. This avoids the dreaded “Not Secure” warnings and makes your local HTTPS environment behave like production.</p>
<hr />
<h2>🌐 Using Certificates in Development</h2>
<p>Point your local server (e.g., Nginx, Apache, Laravel Valet, or Node.js HTTPS server) to these files:</p>
<ul>
<li><p>Certificate: <code>~/Library/Application Support/mkcert/localhost.pem</code></p>
</li>
<li><p>Key: <code>~/Library/Application Support/mkcert/localhost-key.pem</code></p>
</li>
</ul>
<p>Once configured, you can access your app securely via <code>https://localhost</code>.</p>
<hr />
<h2>✅ Conclusion</h2>
<p>mkcert makes HTTPS development painless. With just a few commands, you can generate trusted certificates, organize them neatly in the mkcert directory, and run your local projects over HTTPS—mirroring production environments more closely.</p>
<p>This setup ensures:</p>
<ul>
<li><p>No browser warnings 🚫</p>
</li>
<li><p>Secure API testing 🔐</p>
</li>
<li><p>A smoother developer experience ⚡</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Magento 2 - How to Test Success Page Without Repeatedly Placing Orders]]></title><description><![CDATA[Testing the checkout success page in Magento 2 can be frustrating. By default, once an order is placed, Magento clears the quote session, meaning you can’t simply refresh or revisit the success page without going through the entire checkout process a...]]></description><link>https://fiko.me/magento-2-how-to-test-success-page-without-repeatedly-placing-orders</link><guid isPermaLink="true">https://fiko.me/magento-2-how-to-test-success-page-without-repeatedly-placing-orders</guid><category><![CDATA[Magento]]></category><category><![CDATA[magento 2]]></category><category><![CDATA[PHP]]></category><dc:creator><![CDATA[Fiko Borizqy]]></dc:creator><pubDate>Mon, 05 Jan 2026 01:10:56 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/zbILyELGOtk/upload/fcaf600eddded0a9e030d7ab658fa740.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Testing the <strong>checkout success page</strong> in Magento 2 can be frustrating. By default, once an order is placed, Magento clears the quote session, meaning you can’t simply refresh or revisit the success page without going through the entire checkout process again.</p>
<p>For developers and testers, this slows down iteration when styling or debugging the success page. Fortunately, there’s a simple tweak you can apply to make testing much easier.</p>
<h2 id="heading-why-magento-clears-the-quote">Why Magento Clears the Quote?</h2>
<p>Magento’s checkout flow is designed to ensure that once an order is completed:</p>
<ul>
<li><p>The <strong>quote session</strong> is cleared (<code>$session-&gt;clearQuote()</code>).</p>
</li>
<li><p>Customers don’t accidentally re-submit the same order.</p>
</li>
<li><p>The cart resets for a fresh shopping experience.</p>
</li>
</ul>
<p>This is great for production, but not so convenient when you’re working on the success page design or functionality.</p>
<h2 id="heading-the-quick-solution">The Quick Solution</h2>
<p>To bypass this, you can temporarily comment out the line that clears the quote in the <strong>Success controller</strong>.</p>
<h3 id="heading-file-location">File Location</h3>
<p>bash</p>
<pre><code class="lang-plaintext">vendor/magento/module-checkout/Controller/Onepage/Success.php
</code></pre>
<h3 id="heading-code-adjustment">Code Adjustment</h3>
<p>Find the following line inside the <code>execute()</code> method:</p>
<p>php</p>
<pre><code class="lang-plaintext">$session-&gt;clearQuote();
</code></pre>
<p>Comment it out:</p>
<p>php</p>
<pre><code class="lang-plaintext">// $session-&gt;clearQuote();
</code></pre>
<h2 id="heading-what-this-does">What This Does</h2>
<p>By commenting out this line:</p>
<ul>
<li><p>The quote session remains intact after checkout.</p>
</li>
<li><p>You can revisit the success page multiple times without placing new orders.</p>
</li>
<li><p>It allows faster iteration when testing layout, custom blocks, or tracking scripts.</p>
</li>
</ul>
<h2 id="heading-how-to-access-the-success-page">How to Access the Success Page</h2>
<p>Once the quote isn’t cleared, you can directly access the success page by visiting:</p>
<p>Code</p>
<pre><code class="lang-plaintext">https://yourdomain.com/checkout/onepage/success/
</code></pre>
<p>This will display the last order’s success details without requiring a fresh checkout.</p>
<h2 id="heading-important-notes">Important Notes</h2>
<ul>
<li><p><strong>Do not keep this change in production.</strong> Clearing the quote is essential for preventing duplicate orders and ensuring a clean cart experience.</p>
</li>
<li><p>Treat this as a <strong>temporary development tweak</strong> only.</p>
</li>
<li><p>Once you’re done testing, restore the original line:</p>
<p>  php</p>
<pre><code class="lang-plaintext">  $session-&gt;clearQuote();
</code></pre>
</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>This small adjustment can save you significant time when working on Magento 2’s checkout success page. Instead of repeatedly placing test orders, you can comment out <code>$session-&gt;clearQuote()</code> and freely reload the success page until your design or functionality is perfected.</p>
<p>Would you like me to also add a <strong>step-by-step guide with screenshots</strong> (e.g., file path navigation, code snippet before/after) so your blog post feels more visual and beginner-friendly, or keep it concise and developer-focused?</p>
]]></content:encoded></item><item><title><![CDATA[How to Downgrade Magento from Commerce to Open Source Using Opengento's Tool]]></title><description><![CDATA[Magento Commerce (EE) offers powerful features, but for many teams, Open Source (CE) is leaner, lighter, and more sustainable. If you're migrating from EE to CE, the Opengento downgrade tool provides a clean, scriptable way to remove proprietary modu...]]></description><link>https://fiko.me/how-to-downgrade-magento-from-commerce-to-open-source-using-opengentos-tool</link><guid isPermaLink="true">https://fiko.me/how-to-downgrade-magento-from-commerce-to-open-source-using-opengentos-tool</guid><category><![CDATA[Magento]]></category><category><![CDATA[Linux]]></category><category><![CDATA[MySQL]]></category><dc:creator><![CDATA[Fiko Borizqy]]></dc:creator><pubDate>Tue, 23 Sep 2025 06:00:18 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/GNyjCePVRs8/upload/9074a4bb7acff944e7ef015c208384d3.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Magento Commerce (EE) offers powerful features, but for many teams, Open Source (CE) is leaner, lighter, and more sustainable. If you're migrating from EE to CE, the <a target="_blank" href="https://github.com/opengento/magento2-downgrade-ee-ce">Opengento downgrade tool</a> provides a clean, scriptable way to remove proprietary modules and reset your codebase.</p>
<p>Here’s how to use it safely and effectively.</p>
<hr />
<h3 id="heading-prerequisites">🧰 Prerequisites</h3>
<ul>
<li><p>Magento 2 Commerce installed (any version ≥ 2.3)</p>
</li>
<li><p>Composer installed and configured</p>
</li>
<li><p>Git version control (strongly recommended)</p>
</li>
<li><p>Full backup of your codebase and database</p>
</li>
</ul>
<hr />
<h3 id="heading-step-by-step-downgrade">🚀 Step-by-Step Downgrade</h3>
<h4 id="heading-1-clone-the-downgrade-tool">1. <strong>Clone the downgrade tool</strong></h4>
<p>bash</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> https://github.com/opengento/magento2-downgrade-ee-ce.git
<span class="hljs-built_in">cd</span> magento2-downgrade-ee-ce
</code></pre>
<h4 id="heading-2-copy-the-sample-script">2. <strong>Copy the sample script</strong></h4>
<p>bash</p>
<pre><code class="lang-bash">cp downgrade.sample downgrade.sh
chmod +x downgrade.sh
</code></pre>
<h4 id="heading-3-update-downgradeshhttpdowngradesh">3. <strong>Update</strong> <a target="_blank" href="http://downgrade.sh"><code>downgrade.sh</code></a></h4>
<p>Edit the script to include SQL cleanup after the downgrade logic. Example addition at the end:</p>
<p>bash</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Apply SQL cleanup patches</span>
mysql magento_db &lt; ./scripts/attributes.sql
mysql magento_db &lt; ./scripts/ee.sql
mysql magento_db &lt; ./scripts/cms.sql
mysql magento_db &lt; ./scripts/catalogrule.sql
mysql magento_db &lt; ./scripts/salesrule.sql
mysql magento_db &lt; ./scripts/category.sql
mysql magento_db &lt; ./scripts/product.sql
mysql magento_db &lt; ./scripts/cataloginventory.sql
mysql magento_db &lt; ./scripts/customer.sql
mysql magento_db &lt; ./scripts/quote.sql
mysql magento_db &lt; ./scripts/sales.sql
mysql magento_db &lt; ./scripts/wishlist.sql
</code></pre>
<p>Replace <code>magento_db</code> with your actual database name.</p>
<h4 id="heading-4-run-the-script">4. <strong>Run the script</strong></h4>
<p>bash</p>
<pre><code class="lang-bash">./downgrade.sh
</code></pre>
<p>This will:</p>
<ul>
<li><p>Remove EE modules</p>
</li>
<li><p>Rewrite <code>composer.json</code></p>
</li>
<li><p>Apply SQL cleanup patches</p>
</li>
</ul>
<h3 id="heading-final-steps">✅ Final Steps</h3>
<p>bash</p>
<pre><code class="lang-bash">composer install
bin/magento setup:upgrade
bin/magento setup:di:compile
bin/magento cache:flush
</code></pre>
]]></content:encoded></item><item><title><![CDATA[Fixing Apache’s “Permission Denied: Search Permissions Missing” Error on Linux]]></title><description><![CDATA[If you’ve ever checked your Apache error logs and seen something like this:
Code
[core:error] (13)Permission denied: access to /robots.txt denied (filesystem path '/home/username/sites') because search permissions are missing on a component of the pa...]]></description><link>https://fiko.me/fixing-apaches-permission-denied-search-permissions-missing-error-on-linux</link><guid isPermaLink="true">https://fiko.me/fixing-apaches-permission-denied-search-permissions-missing-error-on-linux</guid><category><![CDATA[Linux]]></category><category><![CDATA[apache]]></category><dc:creator><![CDATA[Fiko Borizqy]]></dc:creator><pubDate>Fri, 05 Sep 2025 07:12:35 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/tg7xChYyE08/upload/a4b8fc908e7218b8e30c13db693e76a9.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you’ve ever checked your Apache error logs and seen something like this:</p>
<p>Code</p>
<pre><code class="lang-bash">[core:error] (13)Permission denied: access to /robots.txt denied (filesystem path <span class="hljs-string">'/home/username/sites'</span>) because search permissions are missing on a component of the path
</code></pre>
<p>…you’ve run into a classic Linux filesystem permissions problem. The good news? It’s easy to fix once you understand what’s going on.</p>
<h2 id="heading-what-the-error-means"><strong>What the Error Means</strong></h2>
<p>In Linux, directories need <strong>execute (</strong><code>x</code><strong>) permission</strong> for a user or process to “search” or traverse them. Even if a file like <code>/robots.txt</code> has the right read permissions, Apache can’t serve it unless it can walk through every directory in the path.</p>
<p>If any parent directory in <code>/home/username/sites/...</code> is missing execute permission for Apache’s user (<code>apache</code>, <code>www-data</code>, or similar), you’ll get this error.</p>
<h2 id="heading-how-to-diagnose"><strong>How to Diagnose</strong></h2>
<ol>
<li><p><strong>Check Apache’s user</strong></p>
<p> bash</p>
<pre><code class="lang-bash"> ps aux | grep httpd   <span class="hljs-comment"># Apache</span>
 ps aux | grep nginx   <span class="hljs-comment"># Nginx with php-fpm</span>
</code></pre>
</li>
<li><p><strong>Check permissions on each directory in the path</strong></p>
<p> bash</p>
<pre><code class="lang-bash"> namei -l /home/username/sites
</code></pre>
<p> This shows the permissions for each component of the path.</p>
</li>
</ol>
<h2 id="heading-how-to-fix"><strong>How to Fix</strong></h2>
<h3 id="heading-option-1-open-execute-permission-for-others">Option 1 — Open execute permission for “others”</h3>
<p>Quick and simple:</p>
<p>bash</p>
<pre><code class="lang-bash">chmod o+x /home
chmod o+x /home/username
chmod o+x /home/username/sites
</code></pre>
<h3 id="heading-option-2-use-group-permissions-more-secure">Option 2 — Use group permissions (more secure)</h3>
<ol>
<li><p>Add Apache’s user to your group:</p>
<p> bash</p>
<pre><code class="lang-bash"> sudo usermod -a -G yourgroup apache
</code></pre>
</li>
<li><p>Change group ownership and set execute for group:</p>
<p> bash</p>
<pre><code class="lang-bash"> sudo chgrp -R yourgroup /home/username/sites
 chmod g+x /home /home/username /home/username/sites
</code></pre>
</li>
</ol>
<h2 id="heading-why-this-happens-often"><strong>Why This Happens Often</strong></h2>
<p>Many developers keep their web projects under <code>/home/&lt;user&gt;/</code> for convenience. By default, home directories are locked down so other users (including the web server process) can’t traverse them. Apache needs at least execute permission to reach the <code>public</code> folder in your Laravel, WordPress, or static site.</p>
<h2 id="heading-best-practice"><strong>Best Practice</strong></h2>
<ul>
<li><p>Keep your web root in <code>/var/www/</code> or another directory Apache already has access to.</p>
</li>
<li><p>If you must serve from your home directory, adjust permissions carefully — don’t just <code>chmod 777</code>.</p>
</li>
<li><p>Use <code>namei -l</code> to quickly spot where permissions break.</p>
</li>
</ul>
<p><strong>In short:</strong> This error isn’t about the file itself, it’s about Apache’s ability to walk the path to it. Give the web server execute permission on each parent directory, and your 403 Forbidden will vanish.</p>
]]></content:encoded></item><item><title><![CDATA[How to Increase an Oracle Cloud Boot Volume]]></title><description><![CDATA[Oracle Cloud Infrastructure allows you to expand the size of a boot volume without rebuilding your instance. This can be done online in many cases, meaning you can keep your system running while the change is applied. Below is a practical guide to re...]]></description><link>https://fiko.me/how-to-increase-an-oracle-cloud-boot-volume</link><guid isPermaLink="true">https://fiko.me/how-to-increase-an-oracle-cloud-boot-volume</guid><category><![CDATA[Oracle]]></category><category><![CDATA[Linux]]></category><dc:creator><![CDATA[Fiko Borizqy]]></dc:creator><pubDate>Wed, 03 Sep 2025 11:33:48 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/ShHkXuZdpTw/upload/d6e835afc01ca668add4ada0aa07ebdc.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Oracle Cloud Infrastructure allows you to expand the size of a boot volume without rebuilding your instance. This can be done online in many cases, meaning you can keep your system running while the change is applied. Below is a practical guide to resizing your boot volume safely.</p>
<h2 id="heading-1-understand-the-limits">1. Understand the Limits</h2>
<ul>
<li><p>You can <strong>only increase</strong> the size of a boot volume. Reducing it is not supported.</p>
</li>
<li><p>The maximum size for a boot volume is <strong>16 TB</strong>.</p>
</li>
<li><p>If cross‑region replication is enabled, you must disable it before resizing.</p>
</li>
<li><p>Always take a <strong>backup</strong> before making changes.</p>
</li>
</ul>
<h2 id="heading-2-prepare-for-the-resize">2. Prepare for the Resize</h2>
<ol>
<li><p><strong>Check your current boot volume size</strong> In the OCI Console, go to <strong>Compute → Boot Volumes</strong> and select your instance’s boot volume.</p>
</li>
<li><p><strong>Review performance settings</strong> If you are on a paid performance tier and want to stay in the Always Free limits, ensure the performance level is set to <strong>Lower Cost</strong>.</p>
</li>
</ol>
<h2 id="heading-3-resize-the-boot-volume-in-the-oci-console">3. Resize the Boot Volume in the OCI Console</h2>
<ol>
<li><p>Sign in to the Oracle Cloud Console.</p>
</li>
<li><p>Open the navigation menu and go to <strong>Compute → Boot Volumes</strong>.</p>
</li>
<li><p>Locate the boot volume you want to resize and click its name.</p>
</li>
<li><p>Click <strong>Edit Size or Performance</strong>.</p>
</li>
<li><p>Enter the new size in GB. This must be larger than the current size.</p>
</li>
<li><p>Save the changes.</p>
</li>
</ol>
<h2 id="heading-4-resize-the-partition-and-filesystem-in-linux">4. Resize the Partition and Filesystem in Linux</h2>
<p>After the OCI change is applied, your operating system will see the extra space, but you must extend the partition and filesystem to use it.</p>
<ol>
<li><p><strong>Check the device name</strong></p>
<p> bash</p>
<pre><code class="lang-bash"> lsblk
</code></pre>
<p> Identify your boot disk (often <code>/dev/sda</code> or <code>/dev/nvme0n1</code>).</p>
</li>
<li><p><strong>Grow the partition</strong> (if using GPT and <code>cloud-init</code> has not done it automatically)</p>
<p> bash</p>
<pre><code class="lang-bash"> sudo growpart /dev/sda 1
</code></pre>
<p> Replace <code>/dev/sda 1</code> with your actual device and partition number.</p>
</li>
<li><p><strong>Resize the filesystem</strong> For ext4:</p>
<p> bash</p>
<pre><code class="lang-bash"> sudo resize2fs /dev/sda1
</code></pre>
<p> For XFS:</p>
<p> bash</p>
<pre><code class="lang-bash"> sudo xfs_growfs /
</code></pre>
</li>
<li><p><strong>Verify the new size</strong></p>
<p> bash</p>
<pre><code class="lang-bash"> df -h
</code></pre>
</li>
</ol>
<h2 id="heading-5-best-practices">5. Best Practices</h2>
<ul>
<li><p>Keep your boot volume performance tier within free limits if cost control is important.</p>
</li>
<li><p>Schedule the resize during a maintenance window if you are unsure about online resizing.</p>
</li>
<li><p>Maintain regular backups so you can roll back if needed.</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[How to Setup Ruby to run gem install Without Sudo]]></title><description><![CDATA[let’s get you a clean Ruby environment so you can install Capistrano without sudo and without fighting system directories. The easiest, safest way is to use a Ruby version manager like rbenv (lightweight) or rvm (full‑featured). I’ll walk you through...]]></description><link>https://fiko.me/how-to-setup-ruby-to-run-gem-install-without-sudo</link><guid isPermaLink="true">https://fiko.me/how-to-setup-ruby-to-run-gem-install-without-sudo</guid><category><![CDATA[Linux]]></category><category><![CDATA[Ruby]]></category><dc:creator><![CDATA[Fiko Borizqy]]></dc:creator><pubDate>Wed, 03 Sep 2025 07:43:58 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/UW5I6jZfOOM/upload/cec93a8bd987d06b73dc8379611ee28c.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>let’s get you a clean Ruby environment so you can install Capistrano <strong>without sudo</strong> and without fighting system directories. The easiest, safest way is to use a <strong>Ruby version manager</strong> like <code>rbenv</code> (lightweight) or <code>rvm</code> (full‑featured). I’ll walk you through <code>rbenv</code> since it’s simple and works well on Linux/Ubuntu/Debian.</p>
<h2 id="heading-step-1-install-rbenv-and-ruby-build">🛠 Step 1 - Install rbenv and ruby-build</h2>
<p>bash</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Install dependencies</span>
sudo apt update
sudo apt install -y build-essential libssl-dev libreadline-dev zlib1g-dev git

<span class="hljs-comment"># Clone rbenv into ~/.rbenv</span>
git <span class="hljs-built_in">clone</span> https://github.com/rbenv/rbenv.git ~/.rbenv

<span class="hljs-comment"># Add rbenv to PATH and init in your shell</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">'export PATH="$HOME/.rbenv/bin:$PATH"'</span> &gt;&gt; ~/.bashrc
<span class="hljs-built_in">echo</span> <span class="hljs-string">'eval "$(rbenv init - bash)"'</span> &gt;&gt; ~/.bashrc
<span class="hljs-built_in">source</span> ~/.bashrc

<span class="hljs-comment"># Install ruby-build plugin</span>
git <span class="hljs-built_in">clone</span> https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
</code></pre>
<h2 id="heading-step-2-install-ruby-userlocal">🛠 Step 2 - Install Ruby (user‑local)</h2>
<p>bash</p>
<pre><code class="lang-bash"><span class="hljs-comment"># List available Ruby versions</span>
rbenv install -l

<span class="hljs-comment"># Install a stable version (e.g., 3.4.5)</span>
rbenv install 3.4.5

<span class="hljs-comment"># Set it as default</span>
rbenv global 3.4.5.
</code></pre>
<h2 id="heading-step-3-install-capistrano-without-sudo">🛠 Step 3 - Install Capistrano without sudo</h2>
<p>bash</p>
<pre><code class="lang-bash">gem install capistrano
</code></pre>
<h2 id="heading-step-4-verify">🧪 Step 4 - Verify</h2>
<p>bash</p>
<pre><code class="lang-bash">ruby -v
gem -v
<span class="hljs-built_in">cap</span> --version
</code></pre>
<p>You should now see:</p>
<ul>
<li><p>Ruby version from rbenv (not system Ruby)</p>
</li>
<li><p>Capistrano installed and runnable without sudo</p>
</li>
</ul>
<p>💡 <strong>Why this works</strong> <code>rbenv</code> installs Ruby entirely in your home directory (<code>~/.rbenv</code>), so you own the files and can install/update gems freely. No system paths, no permission errors.</p>
]]></content:encoded></item><item><title><![CDATA[Mounting a New Disk on Linux]]></title><description><![CDATA[(in my case: a 140 GB disk*)*
When working on cloud servers - whether in Oracle Cloud, AWS, or your own bare-metal rigs - it’s common to attach additional block volumes for more storage. In this guide, we’ll walk through mounting a fresh 140 GB disk ...]]></description><link>https://fiko.me/mounting-a-new-disk-on-linux</link><guid isPermaLink="true">https://fiko.me/mounting-a-new-disk-on-linux</guid><category><![CDATA[Linux]]></category><category><![CDATA[disk]]></category><dc:creator><![CDATA[Fiko Borizqy]]></dc:creator><pubDate>Thu, 28 Aug 2025 07:25:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/MJkGUYwMYr4/upload/e56b0532d822716ab5a82ab75c20ba57.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>(in my case:</em> <strong><em>a 140 GB disk*</em></strong>)*</p>
<p>When working on cloud servers - whether in Oracle Cloud, AWS, or your own bare-metal rigs - it’s common to attach additional block volumes for more storage. In this guide, we’ll walk through mounting a fresh <strong>140 GB</strong> disk at a custom directory so it’s ready for your data and persists across reboots.</p>
<h2 id="heading-1-identify-the-new-disk">1. Identify the New Disk</h2>
<p>First, list your block devices:</p>
<p>bash</p>
<pre><code class="lang-bash">lsblk
</code></pre>
<p>In my case the new disk appeared as <code>/dev/sdb</code> and is <strong>140 GB</strong> in size:</p>
<p>Code</p>
<pre><code class="lang-bash">NAME    MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
sda       8:0    0 46.6G  0 disk 
├─sda1    8:1    0 45.6G  0 part /
├─sda15   8:15   0   99M  0 part /boot/efi
└─sda16 259:0    0  923M  0 part /boot
sdb       8:16   0  140G  0 disk
</code></pre>
<h2 id="heading-2-partition-the-disk">2. Partition the Disk</h2>
<p>If it’s completely unformatted, create a partition table and one primary partition:</p>
<p>bash</p>
<pre><code class="lang-bash">sudo fdisk /dev/sdb
</code></pre>
<p>Inside <code>fdisk</code>:</p>
<ul>
<li><p>Press <code>n</code> → <code>p</code> → accept defaults</p>
</li>
<li><p>Press <code>w</code> to save changes</p>
</li>
</ul>
<h2 id="heading-3-format-the-partition">3. Format the Partition</h2>
<p>bash</p>
<pre><code class="lang-bash">sudo mkfs.ext4 /dev/sdb1
</code></pre>
<p>💡 Replace <code>sdb1</code> with your actual partition name.</p>
<h2 id="heading-4-create-a-mount-point">4. Create a Mount Point</h2>
<p>Even though you can mount into <code>/etc/data</code>, best practice is to use <code>/mnt/data</code> or <code>/data</code> for clarity:</p>
<p>bash</p>
<pre><code class="lang-bash">sudo mkdir -p /mnt/data
</code></pre>
<h2 id="heading-5-mount-the-partition">5. Mount the Partition</h2>
<p>bash</p>
<pre><code class="lang-bash">sudo mount /dev/sdb1 /mnt/data
</code></pre>
<h2 id="heading-6-make-the-mount-persistent">6. Make the Mount Persistent</h2>
<p>Find the UUID:</p>
<p>bash</p>
<pre><code class="lang-bash">sudo blkid /dev/sdb1
</code></pre>
<p>Edit <code>/etc/fstab</code>:</p>
<p>plaintext</p>
<pre><code class="lang-bash">UUID=abcd-1234-...   /mnt/data   ext4   defaults   0   2
</code></pre>
<p>Test it:</p>
<p>bash</p>
<pre><code class="lang-bash">sudo mount -a
</code></pre>
<h2 id="heading-final-thoughts">📌 Final Thoughts</h2>
<ul>
<li><p>Mount points under <code>/mnt</code> or <code>/data</code> keep the system layout predictable and reduce risk of breaking config-related directories.</p>
</li>
<li><p>Always double-check <code>fstab</code> entries before rebooting - a wrong mount configuration can block the boot process.</p>
</li>
<li><p>In this real-world example, we mounted a <strong>140 GB</strong> disk, but the same process applies to any size.</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Magento 2 : Fixing Elasticsearch's "TOO_MANY_REQUESTS/12" Error: Flood-Stage Disk Usage]]></title><description><![CDATA[During a recent Magento 2.4.4 development sprint, I ran into a puzzling indexing error that might look familiar to fellow devs working with Elasticsearch:
Catalog Search index process error during indexation process:
index [magento244p13_product_1_v1...]]></description><link>https://fiko.me/magento-2-fixing-elasticsearchs-toomanyrequests12-error-flood-stage-disk-usage</link><guid isPermaLink="true">https://fiko.me/magento-2-fixing-elasticsearchs-toomanyrequests12-error-flood-stage-disk-usage</guid><category><![CDATA[Magento]]></category><category><![CDATA[magento 2]]></category><category><![CDATA[elasticsearch]]></category><dc:creator><![CDATA[Fiko Borizqy]]></dc:creator><pubDate>Thu, 19 Jun 2025 07:45:19 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1750319077094/6011894d-26c3-4759-8616-b72d569ce709.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>During a recent Magento 2.4.4 development sprint, I ran into a puzzling indexing error that might look familiar to fellow devs working with Elasticsearch:</p>
<pre><code class="lang-bash">Catalog Search index process error during indexation process:
index [magento244p13_product_1_v1] blocked by: [TOO_MANY_REQUESTS/12/disk usage exceeded flood-stage watermark, index has read-only-allow-delete block]
</code></pre>
<p>In plain terms: Elasticsearch panicked because disk usage passed the flood-stage watermark (typically 95%), so it slammed the brakes and marked the index as read-only. Magento couldn’t update the index because of it.</p>
<p>Here’s how I solved it, step-by-step.</p>
<h3 id="heading-step-1-check-disk-usage">Step 1: Check Disk Usage</h3>
<p>First, I ran:</p>
<p>bash</p>
<pre><code class="lang-bash">df -h
</code></pre>
<p>Sure enough, my disk space was on the brink. A quick cleanup of old logs and unused packages brought it under control.</p>
<h3 id="heading-step-2-clear-the-read-only-block">Step 2: Clear the Read-Only Block</h3>
<p>After freeing space, I lifted the restriction on all indexes with:</p>
<p>bash</p>
<pre><code class="lang-bash">curl -XPUT -H <span class="hljs-string">"Content-Type: application/json"</span> \
  http://localhost:9200/_all/_settings \
  -d <span class="hljs-string">'{"index.blocks.read_only_allow_delete": null}'</span>
</code></pre>
<p>In stubborn cases, this broader setting can help:</p>
<p>bash</p>
<pre><code class="lang-bash">curl -XPUT -H <span class="hljs-string">"Content-Type: application/json"</span> \
  http://localhost:9200/_cluster/settings \
  -d <span class="hljs-string">'{
    "transient": {
      "cluster.routing.allocation.disk.threshold_enabled": false
    }
  }'</span>
</code></pre>
<h3 id="heading-step-3-reindex-magento">Step 3: Reindex Magento</h3>
<p>With the block removed, I ran:</p>
<p>bash</p>
<pre><code class="lang-bash">bin/magento indexer:reindex
</code></pre>
<p>And this time—no errors. Clean as a whistle.</p>
<p><strong>Takeaway</strong>: Keep a close eye on your Elasticsearch node’s disk usage—especially in local or staging environments with limited storage. Flood-stage blocks are protective but disruptive. This simple reset can save hours of head-scratching.</p>
]]></content:encoded></item><item><title><![CDATA[Ubuntu - Ultimate Guide to OpenVPN: Server and Client Configuration]]></title><description><![CDATA[Setting up an OpenVPN server and client on Ubuntu can be a straightforward process when following the right steps. This guide will walk you through the process of setting up an OpenVPN server using a script from angristan and then configuring a clien...]]></description><link>https://fiko.me/ubuntu-ultimate-guide-to-openvpn-server-and-client-configuration</link><guid isPermaLink="true">https://fiko.me/ubuntu-ultimate-guide-to-openvpn-server-and-client-configuration</guid><category><![CDATA[Linux]]></category><category><![CDATA[Ubuntu]]></category><category><![CDATA[vpn]]></category><category><![CDATA[OpenVPN]]></category><dc:creator><![CDATA[Fiko Borizqy]]></dc:creator><pubDate>Thu, 27 Feb 2025 08:28:23 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/CXlqHmQy3MY/upload/ed18715ca42300dc7a62f495d1ca5e5c.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Setting up an OpenVPN server and client on Ubuntu can be a straightforward process when following the right steps. This guide will walk you through the process of setting up an OpenVPN server using a script from angristan and then configuring a client to connect to the server.</p>
<h3 id="heading-step-1-setting-up-the-openvpn-server"><strong>Step 1: Setting Up the OpenVPN Server</strong></h3>
<ol>
<li><p><strong>Install Required Packages</strong>: Ensure that your server has all the necessary packages installed.</p>
<pre><code class="lang-bash"> sudo apt update
 sudo apt install wget curl
</code></pre>
</li>
<li><p><strong>Download and Run the OpenVPN Installation Script</strong>: The script from angristan simplifies the setup process.</p>
<pre><code class="lang-bash"> wget https://github.com/angristan/openvpn-install/archive/master.zip
 unzip master.zip
 <span class="hljs-built_in">cd</span> openvpn-install-master
 chmod +x openvpn-install.sh
 sudo ./openvpn-install.sh
</code></pre>
</li>
<li><p><strong>Follow the Prompts</strong>: The script will prompt you for various configuration options. Follow the instructions to set up the server according to your preferences.</p>
</li>
<li><p><strong>Download the Generated OVPN Profile</strong>: Once the setup is complete, download the generated <code>.ovpn</code> profile to your local machine.</p>
</li>
</ol>
<h3 id="heading-step-2-installing-openvpn-client-on-ubuntu"><strong>Step 2: Installing OpenVPN Client on Ubuntu</strong></h3>
<ol>
<li><p><strong>Install OpenVPN 3 Client</strong>: OpenVPN 3 is the latest version and is recommended for new setups.</p>
<pre><code class="lang-bash"> sudo apt update
 sudo apt install openvpn3
</code></pre>
</li>
<li><p><strong>Import the OVPN Profile</strong>: Import the generated profile into OpenVPN 3 client.</p>
<pre><code class="lang-bash"> openvpn3 config-import --config opi5pro.ovpn
</code></pre>
</li>
<li><p><strong>List Imported Profiles</strong>: You can see the imported profiles using the following command.</p>
<pre><code class="lang-bash"> openvpn3 configs-list
</code></pre>
</li>
</ol>
<h3 id="heading-step-3-connecting-to-the-openvpn-server"><strong>Step 3: Connecting to the OpenVPN Server</strong></h3>
<ol>
<li><p><strong>Start the VPN Session</strong>: Use the imported profile to start a VPN session.</p>
<pre><code class="lang-bash"> openvpn3 session-start --config opi5pro.ovpn
</code></pre>
</li>
<li><p><strong>List Current VPN Sessions</strong>: You can see the list of current VPN sessions with the following command.</p>
<pre><code class="lang-bash"> openvpn3 sessions-list
</code></pre>
</li>
<li><p><strong>Disconnect from the VPN Session</strong>: If you need to disconnect from the VPN session, use the following command, replacing the session path with your specific session path.</p>
<pre><code class="lang-bash"> openvpn3 session-manage --disconnect --session-path /net/openvpn/v3/sessions/4d9521a3s0156s4abfsac14s0864e1bcf14c
</code></pre>
</li>
</ol>
<h3 id="heading-conclusion"><strong>Conclusion</strong></h3>
<p>By following these steps, you can successfully set up an OpenVPN server and client on Ubuntu. This setup ensures that your connection is secure and encrypted, allowing you to safely access your network from anywhere. Whether you're setting this up for personal use or for a larger network, OpenVPN provides a robust solution for your VPN needs.</p>
<p>Feel free to reach out if you encounter any issues or need further assistance. Happy networking! 😊</p>
]]></content:encoded></item><item><title><![CDATA[Linux - Generate Self SSL (Localhost HTTPS/SSL)]]></title><description><![CDATA[In this article, I'll walk you through the steps to generate a self-signed SSL certificate for localhost on a Linux system. We'll use mkcert, a simple tool for making locally trusted development certificates. Also just to highlight it, I’m using arm ...]]></description><link>https://fiko.me/linux-generate-self-ssl-localhost-httpsssl</link><guid isPermaLink="true">https://fiko.me/linux-generate-self-ssl-localhost-httpsssl</guid><category><![CDATA[SSL]]></category><category><![CDATA[Linux]]></category><category><![CDATA[https]]></category><dc:creator><![CDATA[Fiko Borizqy]]></dc:creator><pubDate>Tue, 25 Feb 2025 09:43:05 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/KrPulSdUetk/upload/57bd73704fd19c447cd03e749af24880.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this article, I'll walk you through the steps to generate a self-signed SSL certificate for <a target="_blank" href="http://localhost">localhost</a> on a Linux system. We'll use <code>mkcert</code>, a simple tool for making locally trusted development certificates. Also just to highlight it, I’m using arm base processor, so I use arm64 version.</p>
<h4 id="heading-step-1-download-and-install-mkcert">Step 1: Download and Install mkcert</h4>
<p>First, we need to download the <code>mkcert</code> binary and make it executable:</p>
<p>sh</p>
<pre><code class="lang-bash">curl -JLO <span class="hljs-string">"https://dl.filippo.io/mkcert/latest?for=linux/arm64"</span>
chmod +x mkcert-v*-linux-amd64
sudo cp mkcert-v*-linux-amd64 /usr/<span class="hljs-built_in">local</span>/bin/mkcert
</code></pre>
<h4 id="heading-step-2-generate-the-ssl-certificate">Step 2: Generate the SSL Certificate</h4>
<p>Next, we'll use <code>mkcert</code> to generate the SSL certificate and key for <a target="_blank" href="http://localhost">localhost</a>:</p>
<p>sh</p>
<pre><code class="lang-bash">mkcert -key-file testing-key.pem -cert-file testing-cert.pem testing-dev.fiko.me
</code></pre>
<p>This command will create <a target="_blank" href="http://localhost"><code>localhost</code></a><code>-key.pem</code> and <a target="_blank" href="http://localhost"><code>localhost</code></a><code>-cert.pem</code> files.</p>
<h4 id="heading-step-3-configure-nginx">Step 3: Configure Nginx</h4>
<p>Now, let's configure Nginx to use the generated SSL certificate. Add the following configuration to your Nginx server block:</p>
<p>nginx</p>
<pre><code class="lang-bash">server {
    listen 445 ssl;
    server_name testing-dev.fiko.me;
    <span class="hljs-built_in">set</span> <span class="hljs-variable">$MAGE_ROOT</span> /home/fiko/sites/testing;
    <span class="hljs-built_in">set</span> <span class="hljs-variable">$MAGE_MODE</span> developer; <span class="hljs-comment"># or production, depending on your environment</span>

    ssl_certificate /home/fiko/downloads/testing-cert.pem;
    ssl_certificate_key /home/fiko/downloads/testing-key.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;

    include /home/fiko/sites/testing/nginx.conf.sample;

    error_page  404  /errors/404.php;
    error_page  500 502 503 504  /errors/503.php;

    access_log /var/<span class="hljs-built_in">log</span>/nginx/testing_ssl.access.log;
    error_log /var/<span class="hljs-built_in">log</span>/nginx/testing_ssl.error.log;
}
</code></pre>
<p>Make sure the paths to the SSL certificate and key files are correct.</p>
<h4 id="heading-step-4-restart-nginx">Step 4: Restart Nginx</h4>
<p>Finally, restart Nginx to apply the new configuration:</p>
<p>sh</p>
<pre><code class="lang-bash">sudo systemctl restart nginx
</code></pre>
<p>Your Nginx server should now be serving the site over HTTPS using the self-signed certificate.</p>
<h3 id="heading-references">References</h3>
<ul>
<li><a target="_blank" href="https://github.com/FiloSottile/mkcert">mkcert GitHub Repository</a></li>
</ul>
<p>By following these steps, you can generate a self-signed SSL certificate for <a target="_blank" href="http://localhost">localhost</a> and configure Nginx to use it. This setup is great for development environments where you need HTTPS but don't want to obtain a certificate from a Certificate Authority.</p>
<p>Happy coding! 😊</p>
]]></content:encoded></item><item><title><![CDATA[Nextcloud - Cannot login: Too Many Requests]]></title><description><![CDATA[This issue is the one I got when try to login, the simplest solution that works for me is to delete the specific IP on oc_bruteforce_attempts database table. Or maybe just truncate the table, that will make us able to login again without facing that ...]]></description><link>https://fiko.me/nextcloud-cannot-login-too-many-requests</link><guid isPermaLink="true">https://fiko.me/nextcloud-cannot-login-too-many-requests</guid><category><![CDATA[Nextcloud]]></category><category><![CDATA[Linux]]></category><category><![CDATA[Docker]]></category><dc:creator><![CDATA[Fiko Borizqy]]></dc:creator><pubDate>Wed, 28 Aug 2024 06:11:56 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/Ux2j3EAD-_g/upload/30dca3d4cd4ab36492447a50b5f2194c.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This issue is the one I got when try to login, the simplest solution that works for me is to delete the specific IP on <code>oc_bruteforce_attempts</code> database table. Or maybe just truncate the table, that will make us able to login again without facing that issue anymore.</p>
<hr />
<p>Preferences:</p>
<ul>
<li><a target="_blank" href="https://help.nextcloud.com/t/cannot-login-too-many-requests/100905">https://help.nextcloud.com/t/cannot-login-too-many-requests/100905</a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Linux - File has unexpected size (944824 != 944876). Mirror sync in progress]]></title><description><![CDATA[When I'm running sudo apt update on my orangepi5 device, I got these errors:
Hit:1 https://download.docker.com/linux/ubuntu jammy InRelease
Hit:2 https://repo.ivpn.net/stable/ubuntu ./generic InRelease                                                 ...]]></description><link>https://fiko.me/linux-file-has-unexpected-size-944824-944876-mirror-sync-in-progress</link><guid isPermaLink="true">https://fiko.me/linux-file-has-unexpected-size-944824-944876-mirror-sync-in-progress</guid><category><![CDATA[Linux]]></category><category><![CDATA[Ubuntu]]></category><category><![CDATA[debian]]></category><category><![CDATA[terminal]]></category><dc:creator><![CDATA[Fiko Borizqy]]></dc:creator><pubDate>Tue, 27 Aug 2024 13:41:08 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/4Mw7nkQDByk/upload/998b79b48e494103aac087659f5dd6ab.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When I'm running <code>sudo apt update</code> on my orangepi5 device, I got these errors:</p>
<pre><code class="lang-bash">Hit:1 https://download.docker.com/linux/ubuntu jammy InRelease
Hit:2 https://repo.ivpn.net/stable/ubuntu ./generic InRelease                                                                                        
Hit:3 https://pkg.cloudflare.com/cloudflared jammy InRelease                                                                                         
Ign:4 https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/7.0 InRelease                                                                            
Hit:6 http://repo.huaweicloud.com/ubuntu-ports jammy InRelease                                                                                       
Hit:8 http://repo.huaweicloud.com/ubuntu-ports jammy-security InRelease                                                                              
Get:9 http://repo.huaweicloud.com/ubuntu-ports jammy-updates InRelease [128 kB]                                 
Hit:10 http://repo.huaweicloud.com/ubuntu-ports jammy-backports InRelease                                                  
Hit:11 https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/7.0 Release                  
Hit:12 https://ppa.launchpadcontent.net/deadsnakes/ppa/ubuntu jammy InRelease             
Hit:13 https://ppa.launchpadcontent.net/ondrej/php/ubuntu jammy InRelease
Hit:14 http://ppa.launchpad.net/rabbitmq/rabbitmq-erlang/ubuntu jammy InRelease
Hit:5 https://packagecloud.io/rabbitmq/rabbitmq-server/ubuntu jammy InRelease
Hit:15 https://ppa.launchpadcontent.net/redislabs/redis/ubuntu jammy InRelease
Ign:16 http://repo.huaweicloud.com/ubuntu-ports jammy-updates/main armhf Packages
Get:17 http://repo.huaweicloud.com/ubuntu-ports jammy-updates/main arm64 Packages [1,737 kB]
Get:18 http://repo.huaweicloud.com/ubuntu-ports jammy-updates/universe armhf Packages [845 kB]
Ign:18 http://repo.huaweicloud.com/ubuntu-ports jammy-updates/universe armhf Packages
Get:16 http://repo.huaweicloud.com/ubuntu-ports jammy-updates/main armhf Packages [945 kB]
Err:16 http://repo.huaweicloud.com/ubuntu-ports jammy-updates/main armhf Packages
  File has unexpected size (944824 != 944876). Mirror sync <span class="hljs-keyword">in</span> progress? [IP: 103.172.25.237 80]
  Hashes of expected file:
   - Filesize:944876 [weak]
   - SHA256:05dbf070158dd9953ee5c260a2e2f9950e420eb6fd4eefe30723e1a248a799cd
   - SHA1:d2716f274b0fa5766f88a42f8dede17b08eb8d54 [weak]
   - MD5Sum:6f5bae8e83a1007cc2bd91620c9f4dca [weak]
  Release file created at: Mon, 26 Aug 2024 00:14:45 +0000
Hit:7 https://packagecloud.io/varnishcache/varnish60lts/ubuntu jammy InRelease
Get:18 http://repo.huaweicloud.com/ubuntu-ports jammy-updates/universe armhf Packages [845 kB]
Err:18 http://repo.huaweicloud.com/ubuntu-ports jammy-updates/universe armhf Packages

Reading package lists... Done 
E: Failed to fetch http://repo.huaweicloud.com/ubuntu-ports/dists/jammy-updates/main/binary-armhf/Packages.xz  File has unexpected size (944824 != 944876). Mirror sync <span class="hljs-keyword">in</span> progress? [IP: 103.172.25.237 80]
   Hashes of expected file:
    - Filesize:944876 [weak]
    - SHA256:05dbf070158dd9953ee5c260a2e2f9950e420eb6fd4eefe30723e1a248a799cd
    - SHA1:d2716f274b0fa5766f88a42f8dede17b08eb8d54 [weak]
    - MD5Sum:6f5bae8e83a1007cc2bd91620c9f4dca [weak]
   Release file created at: Mon, 26 Aug 2024 00:14:45 +0000
E: Failed to fetch http://repo.huaweicloud.com/ubuntu-ports/dists/jammy-updates/universe/binary-armhf/Packages.xz  
E: Some index files failed to download. They have been ignored, or old ones used instead.
</code></pre>
<p>Then how I tackle it? simply I need to run:</p>
<pre><code class="lang-bash">sudo apt-get clean
</code></pre>
<p>Once executed, it's like nothing happened, yet go run <code>sudo apt update</code> again, and it's working and that error message is gone as well.</p>
<hr />
<p>References:</p>
<ul>
<li><a target="_blank" href="https://askubuntu.com/questions/1147254/apt-update-fails-at-chrome-stable-main-file-has-unexpected-size-1103-1104">https://askubuntu.com/questions/1147254/apt-update-fails-at-chrome-stable-main-file-has-unexpected-size-1103-1104</a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Javascript - Event on Pressing Keyboard]]></title><description><![CDATA[Simple way to detect keyboard pressed is by injecting event listerner, in this case we will detect escape key.
// Add the event listener when needed.
document.addEventListener('keydown', OnKeyboardPressed);

const escPressed = () => { 
  // Remove ev...]]></description><link>https://fiko.me/javascript-event-on-pressing-keyboard</link><guid isPermaLink="true">https://fiko.me/javascript-event-on-pressing-keyboard</guid><category><![CDATA[JavaScript]]></category><dc:creator><![CDATA[Fiko Borizqy]]></dc:creator><pubDate>Fri, 21 Jun 2024 02:42:07 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/i25aqE_YUZs/upload/43b9a0bffb24dbb7fc080561e47d77e3.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Simple way to detect keyboard pressed is by injecting event listerner, in this case we will detect <code>escape</code> key.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Add the event listener when needed.</span>
<span class="hljs-built_in">document</span>.addEventListener(<span class="hljs-string">'keydown'</span>, OnKeyboardPressed);

<span class="hljs-keyword">const</span> escPressed = <span class="hljs-function">() =&gt;</span> { 
  <span class="hljs-comment">// Remove event after pressed or you can remove on any other events</span>
  <span class="hljs-built_in">document</span>.removeEventListener(<span class="hljs-string">'keydown'</span>, OnKeyboardPressed);
};

<span class="hljs-comment">// method to listen to the event</span>
<span class="hljs-keyword">const</span> OnKeyboardPressed = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> e.key === <span class="hljs-string">'Escape'</span> &amp;&amp; escPressed();
</code></pre>
<hr />
<p>References:</p>
<ul>
<li><a target="_blank" href="https://www.toptal.com/developers/keycode">https://www.toptal.com/developers/keycode</a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Magento 2 - How to Custom Order Number]]></title><description><![CDATA[Magento does not provide this feature by default, but recently before posting this article, I've been created custom module to customise the order number (Increment Id)
Please to check this github repo for further documentation: https://github.com/fi...]]></description><link>https://fiko.me/magento-2-how-to-custom-order-number</link><guid isPermaLink="true">https://fiko.me/magento-2-how-to-custom-order-number</guid><category><![CDATA[Magento]]></category><category><![CDATA[magento 2]]></category><category><![CDATA[magento 2 extensions]]></category><category><![CDATA[PHP]]></category><dc:creator><![CDATA[Fiko Borizqy]]></dc:creator><pubDate>Wed, 27 Sep 2023 03:37:28 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1695784622132/72530464-8167-4f94-8b4d-26ff1befb435.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Magento does not provide this feature by default, but recently before posting this article, I've been created custom module to customise the order number (Increment Id)</p>
<p>Please to check this github repo for further documentation: <a target="_blank" href="https://github.com/fiko/magento2-advanced-order-number">https://github.com/fiko/magento2-advanced-order-number</a></p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/fiko/magento2-advanced-order-number">https://github.com/fiko/magento2-advanced-order-number</a></div>
]]></content:encoded></item><item><title><![CDATA[Magento 2 - How to Get Configuration Value Programmatically?]]></title><description><![CDATA[💡
I wrote this article under Magento 2 version of 2.4.6, latest version might have difference approach.


There are several ways to retrieve system configuration, but there are 2 common approaches, they are using object manager and by injecting into...]]></description><link>https://fiko.me/magento-2-how-to-get-configuration-value-programmatically</link><guid isPermaLink="true">https://fiko.me/magento-2-how-to-get-configuration-value-programmatically</guid><category><![CDATA[Magento]]></category><category><![CDATA[magento 2]]></category><category><![CDATA[magento development]]></category><dc:creator><![CDATA[Fiko Borizqy]]></dc:creator><pubDate>Fri, 22 Sep 2023 00:08:19 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/zbILyELGOtk/upload/e1550d6cc6daeb375735873f8f4f1896.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">I wrote this article under Magento 2 version of 2.4.6, latest version might have difference approach.</div>
</div>

<p>There are several ways to retrieve system configuration, but there are 2 common approaches, they are using <s>object manager</s> and by injecting into construct method <em>(__construct is the recommended one by Magento itself).</em></p>
<h3 id="heading-1-by-object-manager">1. by Object Manager</h3>
<pre><code class="lang-php">.....
$scopeConfig = \Magento\Framework\App\ObjectManager::getInstance()
    -&gt;get(\Magento\Framework\App\Config\ScopeConfigInterface::class);

$configValue = $scopeConfig-&gt;getValue(
        <span class="hljs-string">'fiko/general/testing_config'</span>,
        \Magento\Store\Model\ScopeInterface::SCOPE_STORE,
    );
.....
</code></pre>
<p>Notes:</p>
<ul>
<li><p><mark>$scopeConfig = \Magento\Framewo....</mark>: we need to define what's the instance / class we want to import / use.</p>
</li>
<li><p><mark>$configValue = $scopeCon....</mark>: time to retrieve the configuration, further notes will be on 2nd solution below</p>
</li>
</ul>
<h3 id="heading-2-by-injecting-into-construct-method-recommended">2. by Injecting into construct method <strong>(Recommended)</strong></h3>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-keyword">namespace</span> <span class="hljs-title">Fiko</span>\<span class="hljs-title">Training</span>\<span class="hljs-title">Helper</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Data</span>
</span>{
    <span class="hljs-keyword">public</span> $scopeConfig;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params">
        \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
    </span>) </span>{
        <span class="hljs-keyword">$this</span>-&gt;scopeConfig = $scopeConfig;
    }
}
</code></pre>
<p>Notes:</p>
<ul>
<li><p><mark>public $scopeConfig;</mark>: by the time PHP 8 released, it is mandatory to define the visibility <em>(no dynamic property allowed)</em>. it can be public/protected/private, but in this case I would use public as it can be used by other instances.</p>
</li>
<li><p><mark>ScopeConfigInterface $scopeConfig</mark>: interface we need to have in order to retrieve configuration.</p>
</li>
</ul>
<pre><code class="lang-php"><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getExampleConfig</span>(<span class="hljs-params"></span>)
</span>{
    $configValue = <span class="hljs-keyword">$this</span>-&gt;scopeConfig-&gt;getValue(
        <span class="hljs-string">'fiko/general/testing_config'</span>,
        \Magento\Store\Model\ScopeInterface::SCOPE_STORE
    );

    <span class="hljs-keyword">return</span> $configValue;
}
</code></pre>
<p>Notes:</p>
<ul>
<li><p><mark>fiko/general/testing_config</mark>: it is the path of the configuration.</p>
</li>
<li><p><mark>\Magento\Store\Model\ScopeInterface::SCOPE_STORE</mark>: It is the scope area (I assume you already know this).</p>
<ul>
<li>I recommend to use SCOPE_STORE, as it will automatically retrieve the higher scope level (website or default) if it doesn't exist on store level.</li>
</ul>
</li>
</ul>
<hr />
<p>References:</p>
<ul>
<li><p><a target="_blank" href="https://s.id/1UhIy">https://www.magetrend.com/blog/magento-2-get-config-value/</a></p>
</li>
<li><p><a target="_blank" href="https://s.id/1UhIA">https://magento.stackexchange.com/a/87835/106128</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Magento 2 - Type vs VirtualType]]></title><description><![CDATA[What is the differences between type and virtualType? in this article, I assume you already understand about the preferences & type. In this article, I tried to create custom command line of fiko:training

I defined helper file of app/code/Fiko/Train...]]></description><link>https://fiko.me/magento-2-type-vs-virtualtype</link><guid isPermaLink="true">https://fiko.me/magento-2-type-vs-virtualtype</guid><category><![CDATA[Magento]]></category><category><![CDATA[magento 2]]></category><category><![CDATA[PHP]]></category><category><![CDATA[magento development]]></category><dc:creator><![CDATA[Fiko Borizqy]]></dc:creator><pubDate>Tue, 19 Sep 2023 01:48:01 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1695088270997/447188c4-76d9-48df-a348-cb16f398c668.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>What is the differences between <code>type</code> and <code>virtualType</code>? <em>in this article, I assume you already understand about the preferences &amp; type</em>. In this article, I tried to create custom command line of <code>fiko:training</code></p>
<ol>
<li><p>I defined helper file of <code>app/code/Fiko/Training/Helper/Data.php</code> <em>(scroll down to see the file)</em>.</p>
</li>
<li><p><code>app/code/Fiko/Training/Console/Command/Testing.php</code> defined for the custom command class.</p>
</li>
<li><p><code>app/code/Fiko/Training/etc/di.xml</code> to define custom command and define <code>type</code> &amp; <code>virtualType</code></p>
</li>
</ol>
<ul>
<li><p>The basic difference is: type will affect all instances, whereas virtualType affects only on sub-class (specific instances)</p>
</li>
<li><p>if you use <code>type</code> to change class attribute, it will be used by all instances. All instances / classes use that class (<code>app/code/Fiko/Training/Helper/Data.php</code>) will have this value.</p>
</li>
</ul>
<h3 id="heading-appcodefikotraininghelperdataphp">app/code/Fiko/Training/Helper/Data.php</h3>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-keyword">declare</span>(strict_types=<span class="hljs-number">1</span>);

<span class="hljs-keyword">namespace</span> <span class="hljs-title">Fiko</span>\<span class="hljs-title">Training</span>\<span class="hljs-title">Helper</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Data</span>
</span>{
    <span class="hljs-comment">/** <span class="hljs-doctag">@var</span> array */</span>
    <span class="hljs-keyword">public</span> $data;

    <span class="hljs-comment">/**
     * Constructor
     *
     * <span class="hljs-doctag">@param</span> array $data
     */</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params"><span class="hljs-keyword">array</span> $data = []</span>)
    </span>{
        <span class="hljs-keyword">$this</span>-&gt;data = $data;
    }

    <span class="hljs-comment">/**
     * This method will return what's the bypassed parameter
     *
     * <span class="hljs-doctag">@param</span> string $name
     * <span class="hljs-doctag">@return</span> string
     */</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getName</span>(<span class="hljs-params">$name</span>): <span class="hljs-title">string</span>
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">"<span class="hljs-subst">{$this-&gt;data['prefix']}</span> <span class="hljs-subst">{$name}</span>"</span>;
    }
}
</code></pre>
<p>Notes:</p>
<ul>
<li>This class is original file that I will use to practice.</li>
</ul>
<h3 id="heading-appcodefikotrainingconsolecommandtestingphp">app/code/Fiko/Training/Console/Command/Testing.php</h3>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-keyword">declare</span>(strict_types=<span class="hljs-number">1</span>);

<span class="hljs-keyword">namespace</span> <span class="hljs-title">Fiko</span>\<span class="hljs-title">Training</span>\<span class="hljs-title">Console</span>\<span class="hljs-title">Command</span>;

<span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">Console</span>\<span class="hljs-title">Command</span>\<span class="hljs-title">Command</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">Console</span>\<span class="hljs-title">Input</span>\<span class="hljs-title">InputInterface</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">Console</span>\<span class="hljs-title">Output</span>\<span class="hljs-title">OutputInterface</span>;

<span class="hljs-keyword">use</span> <span class="hljs-title">Fiko</span>\<span class="hljs-title">Training</span>\<span class="hljs-title">Helper</span>\<span class="hljs-title">Data</span> <span class="hljs-title">as</span> <span class="hljs-title">HelperData</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Testing</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Command</span>
</span>{
    <span class="hljs-keyword">private</span> $helper;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params">HelperData $helper</span>)
    </span>{
        <span class="hljs-keyword">$this</span>-&gt;helper = $helper;

        <span class="hljs-built_in">parent</span>::__construct(<span class="hljs-literal">null</span>);
    }

    <span class="hljs-keyword">protected</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">configure</span>(<span class="hljs-params"></span>): <span class="hljs-title">void</span>
    </span>{
        <span class="hljs-keyword">$this</span>-&gt;setName(<span class="hljs-string">'fiko:training'</span>);

        <span class="hljs-built_in">parent</span>::configure();
    }

    <span class="hljs-comment">/**
     * Execute the command
     *
     * <span class="hljs-doctag">@param</span> InputInterface $input
     * <span class="hljs-doctag">@param</span> OutputInterface $output
     *
     * <span class="hljs-doctag">@return</span> int
     */</span>
     <span class="hljs-keyword">protected</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">execute</span>(<span class="hljs-params">InputInterface $input, OutputInterface $output</span>): <span class="hljs-title">int</span>
     </span>{
        $output-&gt;writeln(<span class="hljs-keyword">$this</span>-&gt;helper-&gt;getName(<span class="hljs-string">'Borizqy'</span>));

        <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>;
     }
}
</code></pre>
<p>Notes:</p>
<ul>
<li>this class is used as the command line executable class.</li>
</ul>
<h3 id="heading-appcodefikotrainingetcdixml">app/code/Fiko/Training/etc/di.xml</h3>
<pre><code class="lang-xml"><span class="hljs-meta">&lt;?xml version="1.0"?&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">config</span> <span class="hljs-attr">xmlns:xsi</span>=<span class="hljs-string">"http://www.w3.org/2001/XMLSchema-instance"</span> <span class="hljs-attr">xsi:noNamespaceSchemaLocation</span>=<span class="hljs-string">"urn:magento:framework:ObjectManager/etc/config.xsd"</span>&gt;</span>
   <span class="hljs-comment">&lt;!-- BEGIN: Defining custom command --&gt;</span>
   <span class="hljs-tag">&lt;<span class="hljs-name">type</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"Magento\Framework\Console\CommandList"</span>&gt;</span>
       <span class="hljs-tag">&lt;<span class="hljs-name">arguments</span>&gt;</span>
           <span class="hljs-tag">&lt;<span class="hljs-name">argument</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"commands"</span> <span class="hljs-attr">xsi:type</span>=<span class="hljs-string">"array"</span>&gt;</span>
               <span class="hljs-tag">&lt;<span class="hljs-name">item</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"fiko:training"</span> <span class="hljs-attr">xsi:type</span>=<span class="hljs-string">"object"</span>&gt;</span>Fiko\Training\Console\Command\Testing<span class="hljs-tag">&lt;/<span class="hljs-name">item</span>&gt;</span>
           <span class="hljs-tag">&lt;/<span class="hljs-name">argument</span>&gt;</span>
       <span class="hljs-tag">&lt;/<span class="hljs-name">arguments</span>&gt;</span>
   <span class="hljs-tag">&lt;/<span class="hljs-name">type</span>&gt;</span>
   <span class="hljs-comment">&lt;!-- END: Defining custom command --&gt;</span>

   <span class="hljs-comment">&lt;!-- BEGIN: example of type implementation --&gt;</span>
   <span class="hljs-tag">&lt;<span class="hljs-name">type</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"Fiko\Training\Helper\Data"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">arguments</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">argument</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"data"</span> <span class="hljs-attr">xsi:type</span>=<span class="hljs-string">"array"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">item</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"prefix"</span> <span class="hljs-attr">xsi:type</span>=<span class="hljs-string">"string"</span>&gt;</span>Mr.<span class="hljs-tag">&lt;/<span class="hljs-name">item</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">argument</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">arguments</span>&gt;</span>
   <span class="hljs-tag">&lt;/<span class="hljs-name">type</span>&gt;</span>
   <span class="hljs-comment">&lt;!-- END: example of type implementation --&gt;</span>

   <span class="hljs-comment">&lt;!-- BEGIN: example of virtualType implementation --&gt;</span>
   <span class="hljs-tag">&lt;<span class="hljs-name">type</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"Fiko\Training\Console\Command\Testing"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">arguments</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">argument</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"helper"</span> <span class="hljs-attr">xsi:type</span>=<span class="hljs-string">"object"</span>&gt;</span>data_example<span class="hljs-tag">&lt;/<span class="hljs-name">argument</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">arguments</span>&gt;</span>
   <span class="hljs-tag">&lt;/<span class="hljs-name">type</span>&gt;</span>
   <span class="hljs-tag">&lt;<span class="hljs-name">virtualType</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"data_example"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"Fiko\Training\Helper\Data"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">arguments</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">argument</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"data"</span> <span class="hljs-attr">xsi:type</span>=<span class="hljs-string">"array"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">item</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"prefix"</span> <span class="hljs-attr">xsi:type</span>=<span class="hljs-string">"string"</span>&gt;</span>Tuan<span class="hljs-tag">&lt;/<span class="hljs-name">item</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">argument</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">arguments</span>&gt;</span>
   <span class="hljs-tag">&lt;/<span class="hljs-name">virtualType</span>&gt;</span>
   <span class="hljs-comment">&lt;!-- END: example of virtualType implementation --&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">config</span>&gt;</span>
</code></pre>
<p>Notes:</p>
<ul>
<li><p><mark>Defining custom command</mark>, to define the custom command line of <code>bin/magento fiko:training</code></p>
</li>
<li><p><mark>example of type implementation</mark>, all instances use <code>Fiko\Training\Helper\Data</code> will have <code>$data['prefix']</code> and the value is <code>Mr.</code>.</p>
</li>
<li><p><mark>example of virtualType implementation</mark>, specifically <code>Fiko\Training\Helper\Data</code> used by <code>Fiko\Training\Console\Command\Testing</code> will have have <code>$data['prefix']</code> and the value is <code>Tuan</code>.</p>
</li>
</ul>
<hr />
<p>References:</p>
<ul>
<li><p><a target="_blank" href="https://s.id/1U7lx">https://www.codedecorator.com/blog/what-is-the-difference-between-type-and-virtualtype-practical-example/</a></p>
</li>
<li><p><a target="_blank" href="https://s.id/1U7lM">https://medium.com/@mishra.anshu1710/magento2-difference-between-type-and-virtual-type-5ac4d2e46568</a></p>
</li>
<li><p><a target="_blank" href="https://s.id/1U7lO">https://magently.com/blog/magento-2-design-patterns-preferences-virtual-types/</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[How to use GPG?]]></title><description><![CDATA[How to create key?
Simply we can run this:
gpg --full-gen-key

Then we will have some interactives.

Key Type
 It's optional, but I oftenly use RSA and RSA (number 1)

Keysize (Bits)
 It's more secure to have more bit or simply we can take the maximu...]]></description><link>https://fiko.me/how-to-use-gpg</link><guid isPermaLink="true">https://fiko.me/how-to-use-gpg</guid><category><![CDATA[Linux]]></category><category><![CDATA[gpg]]></category><category><![CDATA[Security]]></category><dc:creator><![CDATA[Fiko Borizqy]]></dc:creator><pubDate>Mon, 24 Apr 2023 00:47:46 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/eNxYF6cexYU/upload/cc973b356751e4990ee3ba109e5dcaa6.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-how-to-create-key">How to create key?</h3>
<p>Simply we can run this:</p>
<pre><code class="lang-bash">gpg --full-gen-key
</code></pre>
<p>Then we will have some interactives.</p>
<ol>
<li><p>Key Type</p>
<p> It's optional, but I oftenly use RSA and RSA (number 1)</p>
</li>
<li><p>Keysize (Bits)</p>
<p> It's more secure to have more bit or simply we can take the maximum bit, let's say maximum number is 4096, then we can put 4096</p>
</li>
<li><p>Expiration Time</p>
<p> If we want to use this key on all the time, we can set to <code>0</code> to have the never expired key.</p>
</li>
<li><p>Expiration confirmation</p>
<p> let say I set <code>0</code> as the expiration date which mean it will never get expired, then it will try to confirm us that we really want to create a key which never get expired.</p>
</li>
<li><p>Identity</p>
<ol>
<li><p>Name</p>
<p> Put your name, minimum length is 5.</p>
</li>
<li><p>Email</p>
<p> You'll never get email for this, it's just for identification purposes. (optional)</p>
</li>
<li><p>Comment</p>
<p> Just another information we want to put, maybe to identifying something. (optional)</p>
</li>
</ol>
</li>
<li><p>Identity confirmation</p>
<p> It will ask you to confirm your identity, we can input <code>O</code> (O / Oscar character) to confirm that it's correct.</p>
</li>
<li><p>Password</p>
<p> Finally we can put password for the created key, we're going to need this password to decrypt encrypted file.</p>
</li>
</ol>
<h3 id="heading-how-to-encrypt-file">How to Encrypt file?</h3>
<pre><code class="lang-bash">gpg -r &lt;uid&gt; -e your-whatever-file.zip
</code></pre>
<p>replace &lt;uid&gt; with your created key, then a new file with the <code>.gpg</code> extension will be created.</p>
<h3 id="heading-how-to-decrypt-file">How to Decrypt File?</h3>
<pre><code class="lang-bash">gpg -d your-whatever-file.zip.gpg
</code></pre>
<p>or if we want to put the unlocked data into a file, we can use</p>
<pre><code class="lang-bash">gpg -d your-whatever-file.zip.gpg &gt; your-whatever-file.zip
</code></pre>
<h3 id="heading-how-to-list-all-existing-keys">How to List all existing keys?</h3>
<pre><code class="lang-bash">gpg --list-keys
</code></pre>
<p>or we can just specify a &lt;uid&gt; to know the information of specific key</p>
<pre><code class="lang-bash">gpg --list-keys &lt;uid&gt;
</code></pre>
<h3 id="heading-how-to-export-key">How to Export Key?</h3>
<pre><code class="lang-bash">gpg --export-secret-keys &lt;uid&gt; &gt; output.key
</code></pre>
<p>You're going to type your password to able to export the key.</p>
<h3 id="heading-how-to-import-key">How to Import Key?</h3>
<pre><code class="lang-bash">gpg --import output.key
</code></pre>
<p>Or use gpg2 if you don’t want to input passphrase</p>
<pre><code class="lang-bash">gpg2 --batch --import output.key
</code></pre>
<h3 id="heading-how-to-delete-key">How to Delete Key?</h3>
<p>to be able to delete the keys, we need to delete the secret key first, then deleting the key.</p>
<pre><code class="lang-bash">gpg --delete-secret-keys &lt;uid&gt;
gpg --delete-keys &lt;ui&gt;
</code></pre>
<hr />
<p>References:</p>
<ul>
<li><p><a target="_blank" href="https://s.id/1GInV">https://youtu.be/DMGIlj7u7Eo</a></p>
</li>
<li><p><a target="_blank" href="https://s.id/1GIo1">https://linuxhint.com/solve-gpg-decryption-failed-no-secret-key-error/</a></p>
</li>
<li><p><a target="_blank" href="https://s.id/1GIqA">https://stackoverflow.com/a/34132924</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[MySQL - Running multiple version of mysql using Docker]]></title><description><![CDATA[In case to run multiple versions of MySQL, we can do in several ways. In this article, I'm going to run MySQL multiple versions using Docker & using MariaDB instead of mysql.
1. Install Docker
since we're going to use docker, of course we need to ins...]]></description><link>https://fiko.me/mysql-running-multiple-version-of-mysql-using-docker</link><guid isPermaLink="true">https://fiko.me/mysql-running-multiple-version-of-mysql-using-docker</guid><category><![CDATA[MySQL]]></category><category><![CDATA[Docker]]></category><category><![CDATA[Linux]]></category><category><![CDATA[Ubuntu]]></category><dc:creator><![CDATA[Fiko Borizqy]]></dc:creator><pubDate>Tue, 11 Apr 2023 06:14:53 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/Y9kOsyoWyaU/upload/f4ee72efb639df1f050b08dfa8d2caf1.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In case to run multiple versions of MySQL, we can do in several ways. In this article, I'm going to run MySQL multiple versions using Docker &amp; using MariaDB instead of mysql.</p>
<h2 id="heading-1-install-docker">1. Install Docker</h2>
<p>since we're going to use docker, of course we need to install docker. Please to follow <a target="_blank" href="https://s.id/1FGuh">official documentation by Docker to install</a> on your machine.</p>
<h2 id="heading-2-run-the-mysql-version">2. Run The mysql Version</h2>
<p>You can choose between MySQL, MariaDB, or other version. in this case I'm going to use MariaDB, so I need to run this:</p>
<pre><code class="lang-bash">docker run -d --restart=always --name mariadb-10.4.20 --env MARIADB_ROOT_PASSWORD=root -p 1042:3306 mariadb:10.4.20
</code></pre>
<p>Descriptions:</p>
<ul>
<li><p><code>--detach, -d</code> Run container in background and print container ID</p>
</li>
<li><p><code>--restart</code> Restart policy to apply when a container exits</p>
</li>
<li><p><code>--name</code> Assign a name to the container</p>
</li>
<li><p><code>--env, -e</code> Set environment variables</p>
</li>
<li><p><code>--expose, -p</code> Expose a port or a range of ports</p>
</li>
<li><p><code>mariadb:10.4.20</code> Package-Name:version</p>
</li>
</ul>
<h2 id="heading-3-faq">3. FAQ:</h2>
<p>3.1. How to ByPass password?</p>
<p>try to ssh on the running database by running:</p>
<pre><code class="lang-bash">docker <span class="hljs-built_in">exec</span> -it mariadb-10.4.20 bash
</code></pre>
<p>then try to move to <code>HOME</code> directory by running</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span>
</code></pre>
<p>and then add new file called <code>.my.cnf</code>, and the content are:</p>
<pre><code class="lang-bash">[client]
user=root
password=root
host=localhost

[mysqldump]
host=localhost
user=root
password=root
</code></pre>
<h3 id="heading-32-how-to-run-execute">3.2. How to Run Execute?</h3>
<pre><code class="lang-bash">docker <span class="hljs-built_in">exec</span> -it mariadb-10.2.44 mysql
</code></pre>
<p>Once you configured 3.1. you don't need to type the password.</p>
<h3 id="heading-33-how-to-import-database">3.3. How to Import Database</h3>
<pre><code class="lang-bash">docker <span class="hljs-built_in">exec</span> -i mariadb-10.2.44 mysql -u user -p database_name &lt; database.sql
</code></pre>
<p>Or if you want to have the progress bar whilst importing database, you can use this command: (don't forget to <a target="_blank" href="https://s.id/1FGAU">install pv</a> if you don't have this package)</p>
<pre><code class="lang-bash">pv databse.sql | docker <span class="hljs-built_in">exec</span> -i mariadb-10.2.44 sh -c <span class="hljs-string">'mysql database_name'</span>
</code></pre>
<h3 id="heading-34-how-to-export-database">3.4. How to export Database</h3>
<pre><code class="lang-bash">docker <span class="hljs-built_in">exec</span> -i mariadb-10.4.20 mysqldump database_name &gt; database.sql
</code></pre>
<p>If you want to directly compress the file for the output, you can run this: (don't forget to <a target="_blank" href="https://s.id/1FGEu">install gzip</a> if you don't have it.)</p>
<pre><code class="lang-bash">docker <span class="hljs-built_in">exec</span> -i mariadb-10.4.20 mysqldump database_name | sed -e <span class="hljs-string">'s/\sDEFINER=`[^`]*`@`[^`]*`//g'</span> | gzip -c &gt; database.sql.gz
</code></pre>
<h3 id="heading-35-remove-definer">3.5. Remove DEFINER?</h3>
<pre><code class="lang-bash">sed -e <span class="hljs-string">'s/\sDEFINER=`[^`]*`@`[^`]*`//g'</span> -i database.sql
</code></pre>
<hr />
<h3 id="heading-preferences">Preferences:</h3>
<ul>
<li><p><a target="_blank" href="https://s.id/1FGuh">https://docs.docker.com/engine/install/</a></p>
</li>
<li><p><a target="_blank" href="https://s.id/1FGEM">https://hub.docker.com/_/mysql</a></p>
</li>
<li><p><a target="_blank" href="https://s.id/1FGEP">https://hub.docker.com/_/mariadb</a></p>
</li>
<li><p><a target="_blank" href="https://s.id/1FGEY">https://docs.docker.com/engine/reference/commandline/run/#options</a></p>
</li>
<li><p><a target="_blank" href="https://s.id/1FGAU">https://howtoinstall.co/en/pv</a></p>
</li>
<li><p><a target="_blank" href="https://s.id/1FGEu">https://howtoinstall.co/en/gzip</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Apache 2 - Setup Free SSL using Certbot]]></title><description><![CDATA[SSL is important thing for the security for your web application, some of the SSL are paid features, but we can have free SSL provided by Let’s Encrypt. In this article, we're going to try to configure SSL on ubuntu + apache2 server.
1. Install Requi...]]></description><link>https://fiko.me/apache-2-setup-free-ssl-using-certbot</link><guid isPermaLink="true">https://fiko.me/apache-2-setup-free-ssl-using-certbot</guid><category><![CDATA[apache]]></category><category><![CDATA[SSL]]></category><category><![CDATA[certbot]]></category><category><![CDATA[Linux]]></category><dc:creator><![CDATA[Fiko Borizqy]]></dc:creator><pubDate>Tue, 11 Apr 2023 05:47:25 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/DoWZMPZ-M9s/upload/61b2ecb12c1a5a5cf5a1e293398ce396.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>SSL is important thing for the security for your web application, some of the SSL are paid features, but we can have free SSL provided by Let’s Encrypt. In this article, we're going to try to configure SSL on ubuntu + apache2 server.</p>
<h3 id="heading-1-install-required-packages">1. Install Required Packages</h3>
<p>We need two packages in order to start creating SSL certficates, they are <code>certbot</code> and <code>python3-certbot-apache</code>.</p>
<pre><code class="lang-bash">sudo apt update
sudo apt install certbot python3-certbot-apache
</code></pre>
<h3 id="heading-2-configure-apache2-virtual-host">2. Configure Apache2 Virtual Host</h3>
<p>in this case, I'm going to try to create a virtual host for magento245.dev.fiko.me. You just need to setup the port 80 and skipping the 443 port.</p>
<pre><code class="lang-bash">&lt;VirtualHost *:80&gt;
    ServerAdmin hi@fiko.me
    DocumentRoot /home/fiko/sites/magento245/pub/
    ServerName magento245.dev.fiko.me

    &lt;Directory /home/fiko/sites/magento245/pub/&gt;
        Options Indexes FollowSymLinks MultiViews
        AllowOverride All
        Require all granted
    &lt;/Directory&gt;

    &lt;FilesMatch \.php$&gt;
    SetHandler <span class="hljs-string">"proxy:unix:/run/php/php8.1-fpm.sock|fcgi://localhost"</span>
    &lt;/FilesMatch&gt;

    ErrorLog <span class="hljs-variable">${APACHE_LOG_DIR}</span>/error.log
    CustomLog <span class="hljs-variable">${APACHE_LOG_DIR}</span>/access.log combined
&lt;/VirtualHost&gt;
</code></pre>
<p>then restart your apache2 by running:</p>
<pre><code class="lang-bash">sudo service apache2 restart
</code></pre>
<h3 id="heading-3-install-ssl">3. Install SSL</h3>
<p>Once you created the virtual host, try to create the certificate by running:</p>
<pre><code class="lang-bash">sudo certbot --apache
</code></pre>
<p>Follow the steps, and restart apache2 service.</p>
<hr />
<p>Preferences:</p>
<ul>
<li><p><a target="_blank" href="https://s.id/1FGso">https://www.digitalocean.com/community/tutorials/how-to-set-up-apache-virtual-hosts-on-ubuntu-20-04</a></p>
</li>
<li><p><a target="_blank" href="https://s.id/1FGsA">https://towardsdatascience.com/how-to-host-multiple-website-with-apache-virtual-hosts-4423bd0aefbf</a></p>
</li>
<li><p><a target="_blank" href="https://s.id/1FGsD">https://www.digitalocean.com/community/tutorials/how-to-secure-apache-with-let-s-encrypt-on-ubuntu-20-04</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Apache 2 - Setup Reverse Proxy to Access Private Network Over The Internet]]></title><description><![CDATA[Do you already have apache2 configured on your server, and you want to have another application running on the same port as apache have? which is port 80.
We can do it by implementing reverse proxy, so how to do it?
1. Create Virtual Host
We need to ...]]></description><link>https://fiko.me/apache-2-setup-reverse-proxy-to-access-private-network-over-the-internet</link><guid isPermaLink="true">https://fiko.me/apache-2-setup-reverse-proxy-to-access-private-network-over-the-internet</guid><category><![CDATA[apache]]></category><category><![CDATA[Linux]]></category><category><![CDATA[Web Development]]></category><dc:creator><![CDATA[Fiko Borizqy]]></dc:creator><pubDate>Mon, 10 Apr 2023 05:58:40 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/tN344soypQM/upload/6ac229f4b0cb718514e5124b226d9ee5.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Do you already have apache2 configured on your server, and you want to have another application running on the same port as apache have? which is port 80.</p>
<p>We can do it by implementing reverse proxy, so how to do it?</p>
<h3 id="heading-1-create-virtual-host">1. Create Virtual Host</h3>
<p>We need to create a virtual host, in this case I will try to create magento245.dev.fiko.me</p>
<pre><code class="lang-apache"><span class="hljs-section">&lt;VirtualHost *<span class="hljs-number">:80</span>&gt;</span>
    <span class="hljs-attribute">ServerAdmin</span> hi@fiko.me
    <span class="hljs-attribute"><span class="hljs-nomarkup">ServerName</span></span> testing.dev.fiko.me
<span class="hljs-section">&lt;/VirtualHost&gt;</span>
</code></pre>
<h3 id="heading-2-setup-reverse-proxy">2. Setup Reverse Proxy</h3>
<p>Next we need to place reverse proxy, and point this virtual host to original port you have previously installed on. In this case I already installed my application locally on port of 8082, so I need to point to port of 8082.</p>
<pre><code class="lang-apache"><span class="hljs-section">&lt;VirtualHost *<span class="hljs-number">:80</span>&gt;</span>
    <span class="hljs-attribute">ServerAdmin</span> hi@fiko.me
    <span class="hljs-attribute"><span class="hljs-nomarkup">ServerName</span></span> testing.dev.fiko.me

    <span class="hljs-attribute">SSLProxyEngine</span> <span class="hljs-literal">On</span>
    <span class="hljs-attribute">RequestHeader</span> set Front-End-Https <span class="hljs-string">"On"</span>
    <span class="hljs-attribute">ProxyPreserveHost</span> <span class="hljs-literal">On</span>
    <span class="hljs-attribute">SSLProxyVerify</span> none
    <span class="hljs-attribute">SSLProxyCheckPeerCN</span> <span class="hljs-literal">off</span>
    <span class="hljs-attribute">SSLProxyCheckPeerName</span> <span class="hljs-literal">off</span>
    <span class="hljs-attribute">SSLProxyCheckPeerExpire</span> <span class="hljs-literal">off</span>

    <span class="hljs-attribute">ProxyPass</span> / http://<span class="hljs-number">127.0.0.1:8082</span>/
    <span class="hljs-attribute">ProxyPassReverse</span> / http://<span class="hljs-number">127.0.0.1:8082</span>/
<span class="hljs-section">&lt;/VirtualHost&gt;</span>
</code></pre>
<h3 id="heading-3-try-to-test-your-apache2-configuration">3. Try to test your apache2 configuration</h3>
<p>Try to run :</p>
<pre><code class="lang-bash">sudo apache2ctl configtest
</code></pre>
<p>it should have <code>Syntax Ok</code> response.</p>
<p>Once it's good, restart your apache</p>
<pre><code class="lang-bash">sudo service apache2 restart
</code></pre>
<p>and try to access your application from browser.</p>
<h3 id="heading-4-install-required-modules-optional">4. Install Required Modules (Optional)</h3>
<p>Do you face this error?</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681106201699/9595c644-2c92-422c-a3c1-d114fde62dcb.png" alt class="image--center mx-auto" /></p>
<p>It's too general, but maybe you haven't enabled required apache2 modules, you need to enable these modules:</p>
<pre><code class="lang-bash">sudo a2enmod ssl
sudo a2enmod proxy
sudo a2enmod proxy_balancer
sudo a2enmod proxy_http
</code></pre>
<p>Then restart your apache2, and refresh the browser.</p>
<hr />
<p>References:</p>
<ul>
<li><p><a target="_blank" href="https://s.id/1FxP5">https://www.cloudflare.com/en-gb/learning/cdn/glossary/reverse-proxy/</a></p>
</li>
<li><p><a target="_blank" href="https://s.id/1FxPe">https://stackoverflow.com/questions/23931987/apache-proxy-no-protocol-handler-was-valid</a></p>
</li>
<li><p><a target="_blank" href="https://s.id/1FxPn">https://community.bitwarden.com/t/linux-installation-with-existing-apache-server/39506/4</a></p>
</li>
</ul>
]]></content:encoded></item></channel></rss>