<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Posts on 4rkal&#39;s Dev Blog</title>
    <link>https://4rkal.com/posts/</link>
    <description>Recent content in Posts on 4rkal&#39;s Dev Blog</description>
    <image>
      <url>https://4rkal.com/4rkal.png</url>
      <link>https://4rkal.com/4rkal.png</link>
    </image>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <lastBuildDate>Thu, 17 Apr 2025 17:43:47 +0300</lastBuildDate><atom:link href="https://4rkal.com/posts/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Prevent newsletter signup spam</title>
      <link>https://4rkal.com/posts/newsletter-spam/</link>
      <pubDate>Thu, 17 Apr 2025 17:43:47 +0300</pubDate>
      
      <guid>https://4rkal.com/posts/newsletter-spam/</guid>
      <description>Got spammed with fake newsletter signups? Learn how to protect your forms using double opt-in, CAPTCHA, and Cloudflare.</description>
      <content:encoded><![CDATA[<h2 id="backstory">Backstory</h2>
<p>I woke up to 200 new subscribers on the newsletter of my site <a href="https;//videiro.com">videiro.com</a>, had it finally happened? Did my site finally go viral?</p>
<p>Sadly no. After checking the new subscribers I noticed that none had verified their email addresses, not even one, that&rsquo;s definitely not a confidence.</p>
<p>After some quick research I understood that I had indeed been spammed. But all the emails look legit. Here are some examples:</p>
<pre tabindex="0"><code>kathyolynn@yahoo.com
lukeckins@gmail.com
dispatch@gonealinc.com
doug_fern@hotmail.com
</code></pre><p>After some initial research (entering the emails into <a href="https://haveibeenpwned.com/">haveibeenpwned</a>) it looks like most of these email addresses have been in some kind of hack or breach.</p>
<p>So what was happening? How can I prevent it in the future?</p>
<p>Someone, decided to use compromised email addresses to spam my form. Either to pollute my newsletter, to see how far they could go or just because they can?</p>
<h2 id="what-i-learned">What I learned</h2>
<p>When making anything publicly available on the internet, there will be spammers, there will be bots and there will be people trying to hack it. That is why you should always be making it as secure as possible.</p>
<p>It turns out that this kind of spam attack is more common that you think (especially since my <a href="https://newsletter.4rkal.com">blog&rsquo;s newsletter</a> also got spammed a couple weeks later). Bots crawl the web and look for forms, usually newsletter or contact forms and then start submitting &ldquo;leaked&rdquo; email addresses.</p>
<p>But why?
Here are some reasons I came up with:</p>
<ul>
<li>To pollute your email list (if this is a personal attack, which I don&rsquo;t think it is in this case)</li>
<li>To test the validity of the emails??</li>
<li>To annoy the leaked email addresses owners by having them subscribed to thousands of newsletters</li>
<li>To annoy the website owner (me)</li>
</ul>
<h2 id="how-i-fixed-it">How I fixed it</h2>
<p>I have a couple solutions to this problem.</p>
<h3 id="step-1-enable-double-opt-in">Step 1: Enable Double Opt-in</h3>
<p>The fist and most important step is to make sure that all your newsletters are &lsquo;double opt-in&rsquo; meaning that the user has to confirm their email address before getting subscribed</p>
<p>On listmonk (the newsletter software I am using) make sure that the list that you are subscribing your users to is <code>double opt in</code></p>
<p>This means that even if your form gets spammed you can just remove all the addresses that haven&rsquo;t verified their email (after a couple of days/weeks).</p>
<p>Want to learn how to set up your own self-hosted newsletter with Listmonk?<br>
Check out my guide: <a href="https://4rkal.com/posts/listmonk/">How to set up a self-hosted newsletter using Listmonk</a></p>
<h3 id="step-2-add-captcha-or-cloudflare-js-challenge">Step 2: Add Captcha or Cloudflare JS challenge</h3>
<p>The second step I took was to enable some sort of catcha. Initially I setup an hcaptcha via listmonk. But I don&rsquo;t think that is the best solution as it&rsquo;s kind of annoying. I am however using it for the <a href="https://videiro.com">videiro.com</a> newsletter.
If your interested in how to do it here&rsquo;s how:</p>
<ol>
<li>Open the listmonk web-ui</li>
<li>Go to settings</li>
<li>Under <code>Security</code>, enable captcha and enter an hCaptcha.com API key (you will first have to signup at <a href="https://hcaptcha.com">hcaptcha.com</a>)</li>
</ol>
<p>However with this setup if you are using custom forms (like the email subscription form bellow) the submission process will be kind of broken.</p>
<p>So instead what I came up with and I am currently using on <a href="https://4rkal.com">4rkal.com</a> newsletter is to use cloudflare JS Challenge on a specific subdomain.</p>
<p>The way that I have setup my email newsletter is that I have listmonk running on <code>newsletter.4rkal.com</code>, a seperate subdomain.</p>
<p>This means that I can set that specific subdomain as &ldquo;under attack&rdquo; on cloudflare and prompt users to sometimes complete a catcha.</p>
<p>To do this:</p>
<ol>
<li>Head to cloudflare.com</li>
<li>Login and head to the dashboard of your specific domain</li>
<li>Under <code>Security</code> select <code>WAF</code></li>
<li>Then click on <code>Create rule</code></li>
<li>Give it any name</li>
<li>Under <code>Field</code> select <code>hostname</code> and under <code>Operator</code> select <code>wildcard</code>, in <code>Value</code> enter the subdomain, in my case that&rsquo;s <code>newsletter.4rkal.com</code>. The expression should look like this <code>(http.host wildcard &quot;newsletter.4rkal.com&quot;)</code></li>
<li>Under <code>Choose action</code> select <code>JS Challenge</code></li>
<li>Click on <code>Save</code></li>
</ol>
<p>And that&rsquo;s about it</p>
<h2 id="summary">Summary</h2>
<p>Getting your website spammed is never fun, but I hope this article might have given clarity to people going through the same problem as me.</p>
<div style="text-align: left; margin: 0 auto;">
    <form method="post" action="https://newsletter.4rkal.com/subscription/form" style="background: #2c2c2c; color: #f0f0f0; border-radius: 8px; padding: 15px; max-width: 500px; box-shadow: 0 3px 6px rgba(0, 0, 0, 0.2); font-family: Arial, sans-serif;">
        <div style="display: flex; flex-direction: column; gap: 10px;">
            <h3 style="margin: 0; color: #f0f0f0; font-size: 18px;">Subscribe</h3>
            <input type="hidden" name="nonce"/>
            <input type="email" name="email" required placeholder="E-mail" style="width: 100%; padding: 10px; border: 1px solid #666; border-radius: 4px; background: #333; color: #f0f0f0; box-sizing: border-box;"/>
            <div style="display: flex; flex-direction: column; gap: 8px;">
                <label style="margin: 0; color: #f0f0f0; display: none;">
                    <input id="78a75" type="checkbox" name="l" checked value="78a75b30-472d-4790-a5d5-7f2ed49662a4" style="accent-color: #fff;"/>
                    Weekly Roundup
                </label>
                <span style="color: #d0d0d0; display: none;">Where I share what I’ve been up to that week, including articles I’ve published, cool finds, tips and tricks, and more!</span>
                <label style="margin: 0; color: #f0f0f0; display: none;">
                    <input id="b3964" type="checkbox" name="l" checked value="b3964560-37b0-43d3-9df9-26589fd6bf8d" style="accent-color: #fff;"/>
                    New Posts
                </label>
                <span style="color: #d0d0d0; display: none;">Receive an email every time I post something new on my blog</span>
            </div>
            <input type="submit" value="Subscribe" style="width: 100%; padding: 10px; border: none; border-radius: 4px; background: #fff; color: #007bff; font-size: 14px; cursor: pointer; transition: background-color 0.3s ease, box-shadow 0.3s ease; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);"/>
        </div>
        <p style="text-align: center; margin-top: 10px; color: #d0d0d0; font-size: 10px; margin-bottom:0px;">
            No spam, no ads. Unsubscribe at any time.
        </p>
    </form>
</div>
]]></content:encoded>
    </item>
    
    <item>
      <title>Introducing CypherGoat - The first open source crypto exchange aggregator</title>
      <link>https://4rkal.com/posts/launching-cyphergoat/</link>
      <pubDate>Wed, 12 Mar 2025 18:32:54 +0300</pubDate>
      
      <guid>https://4rkal.com/posts/launching-cyphergoat/</guid>
      <description>Swap your crypto at the best rate on the market. Fast, Private, Open source!</description>
      <content:encoded><![CDATA[<h2 id="why-i-built-cyphergoat">Why I built CypherGoat</h2>
<p>Ever since I first got into crypto I have been building products to make using crypto easier. In early 2022 I co-founded <a href="https://dsc.gg/rubytrades">RubyTrades</a> a (kind of p2p) non kyc fiat on ramp that allowed users to buy and sell crypto using PayPal. Although it was not as successful as we had hoped it still gained some traction and I learned a lot from it.
After that I got interested in Monero. I built <a href="https://github.com/4rkal/moneroos">MoneroOS</a> a plug and play live operating system that mines monero on boot. I also built <a href="https://github.com/4rkal/MoneroNodeMonitor">MoneroNodeMonitor</a> and some other projects.</p>
<p>I was always fascinated by cross-chain on chain swaps (like rubic.exchange), so I decided to build something similar, <em>but better</em>.</p>
<h2 id="what-is-cyphergoat">What is CypherGoat?</h2>
<p>It is a <strong>crypto swap aggregator</strong> it automatically finds the <strong>best exchange rates</strong> from our partnered exchange at no extra cost. You can then perform the swap on that exchange, without ever leaving our website!</p>
<h3 id="why-its-cool">Why it&rsquo;s cool</h3>
<ul>
<li><strong>KYC-Free</strong> – No personal verification required.</li>
<li><strong>Non-Custodial</strong> – Direct to wallet trading (on chain swaps)</li>
<li><strong>Open Source</strong> – Our web UI is open-source.</li>
<li><strong>User-Friendly for Everyone</strong> – Unlike other aggregators with complex interfaces, CypherGoat has a clean and simple UI, perfect for both beginners and advanced users.</li>
<li><strong>Fast &amp; Seamless</strong> – Just pick your tokens, swap, and receive.</li>
</ul>
<h2 id="how-it-works">How it works</h2>
<p>Using CypherGoat is ridiculously simple:</p>
<ol>
<li><strong>Choose your tokens</strong> – Select the crypto you want to send the one you want to receive and that the amount you want to swap.</li>
<li><strong>Get the Best Rate</strong> – CypherGoat &ldquo;scans&rdquo; exchanges and finds the best deal for you.</li>
<li><strong>Swap &amp; Receive</strong> – Confirm the trade, enter your address, send your funds, and get your swapped crypto in your wallet.</li>
</ol>
<h2 id="final-thoughts">Final thoughts</h2>
<p>Crypto swapping shouldn’t be complicated, and I truly believe CypherGoat makes it easier. If you have thoughts, suggestions, or just want to chat about crypto, let’s connect! You can find me and the growing CypherGoat community on <a href="https://t.me/cyphergoatcom">Telegram</a> and <a href="https://x.com/cyphergoatcom">Twitter</a> .</p>
<p>Head over to <a href="https://cyphergoat">cyphergoat.com</a>, to see the magic ; )</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Deploying Go &#43; Templ &#43; HTMX &#43; TailwindCSS to production</title>
      <link>https://4rkal.com/posts/deploy-go-htmx-templ-tailwind-to-production/</link>
      <pubDate>Thu, 06 Mar 2025 14:16:29 +0300</pubDate>
      
      <guid>https://4rkal.com/posts/deploy-go-htmx-templ-tailwind-to-production/</guid>
      <description>In this article I will be showing you how to deploy the GoTTH stack (Go Templ htmx tailwind) to production.</description>
      <content:encoded><![CDATA[<p>I recently created my very own cryptocurrency exchange aggregator called <a href="https://cyphergoat.com">cyphergoat</a> it finds you the best rate to swap your crypto from different partnered exchanges.</p>
<p>It has two parts:</p>
<ol>
<li>An API that interacts with exchanges. Written in go and uses gin</li>
<li>The Web UI that is written in go and uses a combination of HTML, HTMX, tailwindcss, CSS and Javascript in templ templates. Aka the GoTTH stack. It interacts with the api in order to find rates etc.</li>
</ol>
<p>What is extremely cool with this stack and setup is that we are able to produce <strong>a single binary</strong> with everything included for each part and ship it to the server. On the webui side this is possible since the html is compiled into go code using templ and then shipped with the binary.</p>
<p>In this article I will be going through my setup to make it easier for you to make something like this.</p>
<h2 id="setup">Setup</h2>
<p>I am using a debian 12 server which will expose my application via cloudflare tunnels. All of the static files are being served via nginx and the api and website binaries are ran as systemd services.</p>
<p>In this guide I will show you how I set this up.</p>
<h2 id="the-setup">The setup</h2>
<p>I have a single folder on my dev machine called cyphergoat:
It contains</p>
<pre tabindex="0"><code>api/
web/
builds/
</code></pre><p>The api folder houses the api source code.
The web the website source code.</p>
<p>And the builds houses all of the builds that are deployed to the server.</p>
<h3 id="tailwind">Tailwind</h3>
<p>The first real challenge comes with setting up tailwindcss correctly.</p>
<p>In my web project I have a static folder specifically for static files. Inside of it I have two files</p>
<pre tabindex="0"><code>/web
	styles.css
	tailwind.css
</code></pre><p>The <code>styles.css</code> simply contains:</p>
<pre tabindex="0"><code>@import &#34;tailwindcss&#34;;
</code></pre><p>The tailwind.css file is where tailwind-cli will save it&rsquo;s stuff.</p>
<p>To build the tailwind stuff I simply run</p>
<pre tabindex="0"><code>npx @tailwindcss/cli -i ./static/styles.css -o ./static/tailwind.css --watch
</code></pre><p>(assuming you have tailwind-cli installed)</p>
<p>In my header.templ file (the header of all the pages) at the top I have</p>
<pre tabindex="0"><code>&lt;link href=&#34;https://4rkal.com/static/tailwind.css&#34; rel=&#34;stylesheet&#34;&gt;

&lt;link href=&#34;https://4rkal.com/static/styles.css&#34; rel=&#34;stylesheet&#34;&gt;
</code></pre><p>And the files are being served using echo&rsquo;s e.Static (in my main.go file )</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>(){
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">e</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">echo</span>.<span style="color:#a6e22e">New</span>()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">e</span>.<span style="color:#a6e22e">Use</span>(<span style="color:#a6e22e">middleware</span>.<span style="color:#a6e22e">Logger</span>())
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">e</span>.<span style="color:#a6e22e">Use</span>(<span style="color:#a6e22e">middleware</span>.<span style="color:#a6e22e">Recover</span>())
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">e</span>.<span style="color:#a6e22e">Use</span>(<span style="color:#a6e22e">middleware</span>.<span style="color:#a6e22e">Secure</span>())
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">e</span>.<span style="color:#a6e22e">Static</span>(<span style="color:#e6db74">&#34;/static&#34;</span>, <span style="color:#e6db74">&#34;static&#34;</span>) <span style="color:#75715e">// Serves content from static folder.
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// Rest of the handlers
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>}
</span></span></code></pre></div><h2 id="server">Server</h2>
<p>On my server side I have a debian 12 vm running on proxmox.</p>
<p>In my users home directory I have a folder with the following contents:</p>
<pre tabindex="0"><code>cyphergoat/
├── api
├── static/
└── web
</code></pre><p>The static folder contains all of the static files (including tailwind.css and styles.css) and the <strong>web</strong> and <strong>api</strong> are the binaries.</p>
<p>I then have two systemd services for these exectuables:</p>
<p>The<code> cg-api.service</code>
<code>/etc/systemd/system/cg-api.service</code></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-systemd" data-lang="systemd"><span style="display:flex;"><span><span style="color:#66d9ef">[Unit]</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">Description</span><span style="color:#f92672">=</span><span style="color:#e6db74">CypherGoat API</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">After</span><span style="color:#f92672">=</span><span style="color:#e6db74">network.target</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">[Service]</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">User</span><span style="color:#f92672">=</span><span style="color:#e6db74">arkal</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">Group</span><span style="color:#f92672">=</span><span style="color:#e6db74">www-data</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">WorkingDirectory</span><span style="color:#f92672">=</span><span style="color:#e6db74">/home/arkal/cyphergoat</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">ExecStart</span><span style="color:#f92672">=</span><span style="color:#e6db74">/home/arkal/cyphergoat/api</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">Restart</span><span style="color:#f92672">=</span><span style="color:#e6db74">always</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">RestartSec</span><span style="color:#f92672">=</span><span style="color:#e6db74">1</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">[Install]</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">WantedBy</span><span style="color:#f92672">=</span><span style="color:#e6db74">multi-user.target</span>
</span></span></code></pre></div><p>And <code>cg-web.service</code>
<code>/etc/systemd/system/cg-web.service</code></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-systemd" data-lang="systemd"><span style="display:flex;"><span><span style="color:#66d9ef">[Unit]</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">Description</span><span style="color:#f92672">=</span><span style="color:#e6db74">CypherGoat Web</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">After</span><span style="color:#f92672">=</span><span style="color:#e6db74">network.target</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">[Service]</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">User</span><span style="color:#f92672">=</span><span style="color:#e6db74">arkal</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">Group</span><span style="color:#f92672">=</span><span style="color:#e6db74">www-data</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">WorkingDirectory</span><span style="color:#f92672">=</span><span style="color:#e6db74">/home/arkal/cyphergoat</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">ExecStart</span><span style="color:#f92672">=</span><span style="color:#e6db74">/home/arkal/cyphergoat/web</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">[Install]</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">WantedBy</span><span style="color:#f92672">=</span><span style="color:#e6db74">multi-user.target</span>
</span></span></code></pre></div><p>Both are owned by the group <code>www-data</code> (this is probably not necessary for the api), in order to make it easier to serve them via nginx.</p>
<h3 id="nginx">Nginx</h3>
<p>The website is communicating with the api but I still need to make the web-ui accessible.</p>
<p>I have setup an nginx site with the following configuration:
<code>/etc/nginx/sites-available/cg</code></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-nginx" data-lang="nginx"><span style="display:flex;"><span><span style="color:#66d9ef">server</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">server_name</span> <span style="color:#e6db74">cyphergoat.com</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">location</span> <span style="color:#e6db74">/</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">proxy_pass</span> <span style="color:#e6db74">http://127.0.0.1:4200</span>;
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">proxy_set_header</span> <span style="color:#e6db74">Host</span> $host;
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">proxy_set_header</span> <span style="color:#e6db74">X-Real-IP</span> $remote_addr;
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">proxy_set_header</span> <span style="color:#e6db74">X-Forwarded-For</span> $proxy_add_x_forwarded_for;
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">proxy_set_header</span> <span style="color:#e6db74">X-Forwarded-Proto</span> $scheme;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">location</span> <span style="color:#e6db74">/static/</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">alias</span> <span style="color:#e6db74">/var/www/static/</span>;
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">expires</span> <span style="color:#e6db74">30d</span>;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>    <span style="color:#75715e"># Optional robots.txt
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#f92672">location</span> = <span style="color:#e6db74">/robots.txt</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">root</span> <span style="color:#e6db74">/var/www/static</span>;
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">access_log</span> <span style="color:#66d9ef">off</span>;
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">log_not_found</span> <span style="color:#66d9ef">off</span>;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">listen</span> <span style="color:#ae81ff">80</span>;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>I have also setup certbot to have an ssl cert.</p>
<p>You can setup certbot by running:</p>
<pre tabindex="0"><code>sudo apt install certbot python3-certbot-nginx -y
</code></pre><p>Generate the ssl cert:</p>
<pre tabindex="0"><code>sudo certbot --nginx -d cyphergoat.com
</code></pre><p>Read <a href="https://4rkal.com/posts/shwebsite/">Self host your own website</a> for a more in depth nginx setup.</p>
<h3 id="cloudflare-tunnels">Cloudflare Tunnels</h3>
<p>I am currently making my website accessible using cloudflare pages. It is an extremely easy to use port forwarding solution</p>
<p>To do this you will need a cloudflare account and a domain pointed to cloudflare.</p>
<p>First head to the <a href="https://one.dash.cloudflare.com/">Zero Trust Dashboard</a></p>
<p>Under <code>Networks</code> click on <code>Tunnels</code> and then <code>Create a tunnel</code></p>
<p>Once created you should <code>Install and run a connector</code>, follow the instructions on the page for your specific setup.</p>
<p>After the connector is running you should click on the <code>Public Hostname</code> tab and <code>Add a public hostname</code>.</p>
<p>Now you should see something like this:
<img loading="lazy" src="/../assets/gitea2.png" type="" alt="Cloudflare dashboard"  /></p>
<p>Fill in the info as I have.
The service type should be <code>HTTP</code> and the url should be <code>127.0.0.1:80</code> or <code>localhost:80</code></p>
<p>Obviously there is no reason to make your api publicly accessible when deploying your website.</p>
<h2 id="deployment">Deployment</h2>
<p>In order to deploy my binaries I went ahead and created a quick bash script:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>cd api
</span></span><span style="display:flex;"><span>go build -o ../builds/ .
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>cd ../web
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>templ generate <span style="color:#f92672">&amp;&amp;</span> go build -o ../builds/web cmd/main.go
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>cd ..
</span></span><span style="display:flex;"><span>rsync -urvP ./builds/ user@SERVER:/home/user/cyphergoat
</span></span><span style="display:flex;"><span>rsync -urvP ./web/static user@SERVER:/home/user/cyphergoat/
</span></span><span style="display:flex;"><span>rsync -urvP ./api/coins.json user@SERVER:/user/user/cyphergoat/
</span></span></code></pre></div><p>The script will build the api, generate the templ files and build the webui and then sends everything over to my server (including the static folder)</p>
<p>I then ssh into my server</p>
<p><code>ssh user@ip</code></p>
<p>and then restart the services</p>
<p><code>sudo systemctl restart cg-api cg-web</code></p>
<p>And that&rsquo;s it.</p>
<h2 id="join-my-free-newsletter">Join my free newsletter!</h2>
<div style="text-align: left; margin: 0 auto;">
    <form method="post" action="https://newsletter.4rkal.com/subscription/form" style="background: #2c2c2c; color: #f0f0f0; border-radius: 8px; padding: 15px; max-width: 500px; box-shadow: 0 3px 6px rgba(0, 0, 0, 0.2); font-family: Arial, sans-serif;">
        <div style="display: flex; flex-direction: column; gap: 10px;">
            <h3 style="margin: 0; color: #f0f0f0; font-size: 18px;">Subscribe</h3>
            <input type="hidden" name="nonce"/>
            <input type="email" name="email" required placeholder="E-mail" style="width: 100%; padding: 10px; border: 1px solid #666; border-radius: 4px; background: #333; color: #f0f0f0; box-sizing: border-box;"/>
            <div style="display: flex; flex-direction: column; gap: 8px;">
                <label style="margin: 0; color: #f0f0f0; display: none;">
                    <input id="78a75" type="checkbox" name="l" checked value="78a75b30-472d-4790-a5d5-7f2ed49662a4" style="accent-color: #fff;"/>
                    Weekly Roundup
                </label>
                <span style="color: #d0d0d0; display: none;">Where I share what I’ve been up to that week, including articles I’ve published, cool finds, tips and tricks, and more!</span>
                <label style="margin: 0; color: #f0f0f0; display: none;">
                    <input id="b3964" type="checkbox" name="l" checked value="b3964560-37b0-43d3-9df9-26589fd6bf8d" style="accent-color: #fff;"/>
                    New Posts
                </label>
                <span style="color: #d0d0d0; display: none;">Receive an email every time I post something new on my blog</span>
            </div>
            <input type="submit" value="Subscribe" style="width: 100%; padding: 10px; border: none; border-radius: 4px; background: #fff; color: #007bff; font-size: 14px; cursor: pointer; transition: background-color 0.3s ease, box-shadow 0.3s ease; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);"/>
        </div>
        <p style="text-align: center; margin-top: 10px; color: #d0d0d0; font-size: 10px; margin-bottom:0px;">
            No spam, no ads. Unsubscribe at any time.
        </p>
    </form>
</div>
<h3 id="related-articles">Related Articles</h3>
<p><a href="https://4rkal.com/posts/go-rate-limit">Simple Rate Limiting in Go (Gin)</a></p>
<p><a href="https://4rkal.com/posts/url-shortener-go/">How to build a URL shortener in Go</a></p>
<p><a href="https://4rkal.com/posts/django-prod/">How to deploy django to production</a></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Simple Rate Limiting in Go (Gin)</title>
      <link>https://4rkal.com/posts/go-rate-limit/</link>
      <pubDate>Tue, 04 Mar 2025 19:15:40 +0300</pubDate>
      
      <guid>https://4rkal.com/posts/go-rate-limit/</guid>
      <description>In this article will be showing you how to setup rate limiting in the gin library in go.</description>
      <content:encoded><![CDATA[<p>While working on my <a href="https://cyphergoat.com">CypherGoat</a> project ,when exposing the API, I needed to setup some rate limiting to avoid getting spammed. Since my API uses Gin as its HTTP library, I used for the <code>limiter</code> package to handle the rate limiting.</p>
<h2 id="setting-up-the-rate-limiting">Setting up the rate limiting</h2>
<p>In my implementation I am setting a 30 request/minute limit on each IP interacting with my API.</p>
<p>Here is some example code:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> (
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;time&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;github.com/gin-gonic/gin&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;github.com/ulule/limiter/v3&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">ginlimiter</span> <span style="color:#e6db74">&#34;github.com/ulule/limiter/v3/drivers/middleware/gin&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">memory</span> <span style="color:#e6db74">&#34;github.com/ulule/limiter/v3/drivers/store/memory&#34;</span>
</span></span><span style="display:flex;"><span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">router</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">gin</span>.<span style="color:#a6e22e">Default</span>()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">rate</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">limiter</span>.<span style="color:#a6e22e">Rate</span>{
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">Period</span>: <span style="color:#ae81ff">1</span> <span style="color:#f92672">*</span> <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Minute</span>,
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">Limit</span>:  <span style="color:#ae81ff">30</span>, <span style="color:#75715e">// 30 Requests/minute limit
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>	}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">store</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">memory</span>.<span style="color:#a6e22e">NewStore</span>()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#75715e">// Create the rate limiter
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>	<span style="color:#a6e22e">instance</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">limiter</span>.<span style="color:#a6e22e">New</span>(<span style="color:#a6e22e">store</span>, <span style="color:#a6e22e">rate</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#75715e">// Middleware to apply rate limiting per IP
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>	<span style="color:#a6e22e">router</span>.<span style="color:#a6e22e">Use</span>(<span style="color:#a6e22e">ginlimiter</span>.<span style="color:#a6e22e">NewMiddleware</span>(<span style="color:#a6e22e">instance</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#75715e">// Example endpoint
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>	<span style="color:#a6e22e">router</span>.<span style="color:#a6e22e">GET</span>(<span style="color:#e6db74">&#34;/&#34;</span>, <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">c</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">gin</span>.<span style="color:#a6e22e">Context</span>) {
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">JSON</span>(<span style="color:#ae81ff">200</span>, <span style="color:#a6e22e">gin</span>.<span style="color:#a6e22e">H</span>{<span style="color:#e6db74">&#34;message&#34;</span>: <span style="color:#e6db74">&#34;Hello World!&#34;</span>})
</span></span><span style="display:flex;"><span>	})
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#75715e">// Start server
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>	<span style="color:#a6e22e">router</span>.<span style="color:#a6e22e">Run</span>(<span style="color:#e6db74">&#34;:8080&#34;</span>)
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>We first create a new gin router called router.</p>
<p>After that we setup a rate limiting policy. In this case it is 30 Requests/minute</p>
<p>After that we create an in memory store to store all of the IP&rsquo;s and their request counts.</p>
<p>Then we create a new rate limiting instance and use it using router.Use</p>
<p>After that we define a standard example route to &ldquo;/&rdquo; that returns Hello World and run it on port 8080</p>
<p>You can test this by going to your web browser to <code>localhost:8080/</code> and send 30 requests (30 refreshes) in one minute and you should see <code>Limit exceeded</code></p>
<p>That&rsquo;s about it.</p>
<h3 id="join-my-free-newsletter">Join my free newsletter</h3>
<div style="text-align: left; margin: 0 auto;">
    <form method="post" action="https://newsletter.4rkal.com/subscription/form" style="background: #2c2c2c; color: #f0f0f0; border-radius: 8px; padding: 15px; max-width: 500px; box-shadow: 0 3px 6px rgba(0, 0, 0, 0.2); font-family: Arial, sans-serif;">
        <div style="display: flex; flex-direction: column; gap: 10px;">
            <h3 style="margin: 0; color: #f0f0f0; font-size: 18px;">Subscribe</h3>
            <input type="hidden" name="nonce"/>
            <input type="email" name="email" required placeholder="E-mail" style="width: 100%; padding: 10px; border: 1px solid #666; border-radius: 4px; background: #333; color: #f0f0f0; box-sizing: border-box;"/>
            <div style="display: flex; flex-direction: column; gap: 8px;">
                <label style="margin: 0; color: #f0f0f0; display: none;">
                    <input id="78a75" type="checkbox" name="l" checked value="78a75b30-472d-4790-a5d5-7f2ed49662a4" style="accent-color: #fff;"/>
                    Weekly Roundup
                </label>
                <span style="color: #d0d0d0; display: none;">Where I share what I’ve been up to that week, including articles I’ve published, cool finds, tips and tricks, and more!</span>
                <label style="margin: 0; color: #f0f0f0; display: none;">
                    <input id="b3964" type="checkbox" name="l" checked value="b3964560-37b0-43d3-9df9-26589fd6bf8d" style="accent-color: #fff;"/>
                    New Posts
                </label>
                <span style="color: #d0d0d0; display: none;">Receive an email every time I post something new on my blog</span>
            </div>
            <input type="submit" value="Subscribe" style="width: 100%; padding: 10px; border: none; border-radius: 4px; background: #fff; color: #007bff; font-size: 14px; cursor: pointer; transition: background-color 0.3s ease, box-shadow 0.3s ease; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);"/>
        </div>
        <p style="text-align: center; margin-top: 10px; color: #d0d0d0; font-size: 10px; margin-bottom:0px;">
            No spam, no ads. Unsubscribe at any time.
        </p>
    </form>
</div>
<h3 id="related-articles">Related Articles</h3>
<p><a href="https://4rkal.com/posts/deploy-go-htmx-templ-tailwind-to-production/">Deploying Go + Templ + HTMX + TailwindCSS to production</a></p>
<p><a href="https://4rkal.com/posts/url-shortener-go/">How to build a URL shortener in Go</a></p>
<p><a href="https://4rkal.com/posts/django-prod/">How to deploy django to production</a></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>If Linux is so great why isn&#39;t everyone using it?</title>
      <link>https://4rkal.com/posts/linux/</link>
      <pubDate>Sun, 13 Oct 2024 17:33:38 +0300</pubDate>
      
      <guid>https://4rkal.com/posts/linux/</guid>
      <description>Curious why more people aren’t using Linux if it’s so awesome? This article breaks down what Linux is, why it&amp;#39;s great and how it secretly powers most of your favorite devices, from smartphones to servers.</description>
      <content:encoded><![CDATA[<h2 id="what-even-is-linux">What even is Linux?</h2>
<p>Linux is a family of free and open source operating systems based on the <a href="https://kernel.org/">Linux kernel</a>.</p>
<p>Although being completely free (unlike alternatives) Linux currently only has <a href="https://gs.statcounter.com/os-market-share/desktop/worldwide">4.5% of the global desktop operating system market</a>, a very low percentage.</p>
<h2 id="what-makes-linux-great">What makes Linux great?</h2>
<p>The core difference between Linux and other mainstream desktop operating systems (windows, macOS) is the fact that it is <strong>free and open source</strong>. This allows it to be:</p>
<ol>
<li><strong>Highly performant</strong> - Linux is often faster and more efficient than its counterparts.</li>
<li><strong>Free from spyware and ads</strong> -  Unlike Windows 11 which is <a href="https://www.theverge.com/2024/4/24/24138949/microsoft-windows-11-start-menu-ads-recommendations-setting-disable">adding ads to the start menu</a></li>
<li><strong>Arguably more secure</strong> - Being open source often makes it more secure</li>
<li><strong><a href="https://www.reddit.com/r/unixporn/">Endlessly customizable</a></strong></li>
<li><strong>Completely free forever</strong> - Because it is published under a free and open source GPL license.</li>
<li>and much much more</li>
</ol>
<p>Read <a href="https://4rkal.com/posts/opensource">The importance of open source software</a> for more information about open source software and it&rsquo;s superiority.</p>
<p>If Windows and macOS are like apartments with rules and restrictions on what you can change, then Linux is like a house that you own that you can renovate, decorate and modify any way you like.</p>
<h2 id="if-linux-is-so-great-why-isnt-everyone-using-it">If Linux is so great why isn&rsquo;t everyone using it?</h2>
<p>We (all Linux users) can probably agree that the main drawback of Linux is user-friendliness. The average user never cared and will never care about what bootloader their laptop is using.</p>
<p>The fun part however is that most people are using Linux, they just don&rsquo;t know it!</p>
<h3 id="android">Android</h3>
<p>Android is the most widely used mobile operating system in the world. With a staggering <a href="https://gs.statcounter.com/os-market-share/mobile/worldwide">71% of the global mobile operating system market</a></p>
<p>A lesser known fact is that android is based on the Linux kernel.</p>
<p>So basically 71% of smartphones are running Linux!</p>
<h3 id="servers">Servers</h3>
<p>Linux is the leading operating system on servers (over 96.4% of the top one million web servers&rsquo; operating systems are Linux)
It also leads other systems such as mainframe computers, and is used on all of the world&rsquo;s 500 fastest supercomputers.</p>
<p>This website is being served from a Linux server.</p>
<p>The majority if not all of the websites that you visit every single day are being served from a Linux server.</p>
<h3 id="iot-and-embedded-systems">IoT and embedded systems</h3>
<p>Most IoT (Internet Of Things) devices run Linux because of it&rsquo;s lightweight nature and robustness. <a href="https://ubuntu.com/blog/eclipse-2018-survey-the-iot-landscape-what-it-empirically-looks-like">This article</a> from 2018 suggests that 71% of IoT devices run Linux</p>
<p>Most embedded systems (smart TV&rsquo;s, routers etc) run Linux</p>
<h2 id="conclusion">Conclusion</h2>
<p>Linux is quietly running behind the scenes. It may only capture a small slice of the desktop operating system market but it&rsquo;s a huge player in mobile, server and IoT spaces. In fact a majority of people are using Linux daily without even realizing it! It’s in your phone, your favorite websites and countless devices around you.</p>
<p>Ultimately I highly recommend anyone interested to at least try and play around with Linux (especially if you are in the IT field I feel like it&rsquo;s a must)</p>
<p><em>PS: this article was written on a Framework 13 running Fedora 40 (Linux)</em></p>
<h2 id="join-my-free-newsletter">Join my free newsletter</h2>
<div style="text-align: left; margin: 0 auto;">
    <form method="post" action="https://newsletter.4rkal.com/subscription/form" style="background: #2c2c2c; color: #f0f0f0; border-radius: 8px; padding: 15px; max-width: 500px; box-shadow: 0 3px 6px rgba(0, 0, 0, 0.2); font-family: Arial, sans-serif;">
        <div style="display: flex; flex-direction: column; gap: 10px;">
            <h3 style="margin: 0; color: #f0f0f0; font-size: 18px;">Subscribe</h3>
            <input type="hidden" name="nonce"/>
            <input type="email" name="email" required placeholder="E-mail" style="width: 100%; padding: 10px; border: 1px solid #666; border-radius: 4px; background: #333; color: #f0f0f0; box-sizing: border-box;"/>
            <div style="display: flex; flex-direction: column; gap: 8px;">
                <label style="margin: 0; color: #f0f0f0; display: none;">
                    <input id="78a75" type="checkbox" name="l" checked value="78a75b30-472d-4790-a5d5-7f2ed49662a4" style="accent-color: #fff;"/>
                    Weekly Roundup
                </label>
                <span style="color: #d0d0d0; display: none;">Where I share what I’ve been up to that week, including articles I’ve published, cool finds, tips and tricks, and more!</span>
                <label style="margin: 0; color: #f0f0f0; display: none;">
                    <input id="b3964" type="checkbox" name="l" checked value="b3964560-37b0-43d3-9df9-26589fd6bf8d" style="accent-color: #fff;"/>
                    New Posts
                </label>
                <span style="color: #d0d0d0; display: none;">Receive an email every time I post something new on my blog</span>
            </div>
            <input type="submit" value="Subscribe" style="width: 100%; padding: 10px; border: none; border-radius: 4px; background: #fff; color: #007bff; font-size: 14px; cursor: pointer; transition: background-color 0.3s ease, box-shadow 0.3s ease; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);"/>
        </div>
        <p style="text-align: center; margin-top: 10px; color: #d0d0d0; font-size: 10px; margin-bottom:0px;">
            No spam, no ads. Unsubscribe at any time.
        </p>
    </form>
</div>]]></content:encoded>
    </item>
    
    <item>
      <title>How to build a URL shortener in Go</title>
      <link>https://4rkal.com/posts/url-shortener-go/</link>
      <pubDate>Sun, 22 Sep 2024 18:24:11 +0300</pubDate>
      
      <guid>https://4rkal.com/posts/url-shortener-go/</guid>
      <description>In this article will be showing you how to build a url shortener in go.</description>
      <content:encoded><![CDATA[<p>In this article I will be going through how to make a url shortener in go. The final result will look something like this <a href="https://app.4rkal.com">shortr</a>, <a href="https://github.com/4rkal/shortr">source code</a></p>
<p>This is a great weekend project especially if you&rsquo;re new to go.</p>
<h2 id="what-is-a-url-shortener">What is a url shortener?</h2>
<p>A URL shortener is a tool that takes a long URL and shrinks it down into something much shorter and easier to share. Instead of copying and pasting a long string of letters, numbers, and symbols, you get a compact version that leads to the same destination. For example, a long URL like <code>www.somelongwebsite.com/articles/this-is-a-super-long-link</code> could become something like <code>bit.ly/abc123</code>. It&rsquo;s super handy for sharing links on social media, in texts, or anywhere space is limited. And most url shorteners provide analytics like link clicks.</p>
<h2 id="requirements">Requirements</h2>
<ol>
<li>Go installed on your system.</li>
<li>A code editor, eg <a href="https://code.visualstudio.com/">vs code</a>, <a href="https://neovim.io/">neovim</a></li>
</ol>
<p>In this project I will be using <a href="https://echo.labstack.com/">echo</a> as the http server and the standard html library.</p>
<h2 id="project-setup">Project Setup</h2>
<p>Create a new directory to house our project</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>mkdir project-name
</span></span><span style="display:flex;"><span>cd project-name
</span></span></code></pre></div><p>Assuming you have golang installed.</p>
<p>Create a new go module (project):</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>go mod init project-name
</span></span></code></pre></div><p>Before we start writing any code we first have to install echo:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>go get github.com/labstack/echo/v4
</span></span></code></pre></div><p>Now create a new file called main.go</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>touch main.go
</span></span></code></pre></div><p>And open it in your favorite editor.</p>
<h2 id="creating-url-handlers">Creating url handlers</h2>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">e</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">echo</span>.<span style="color:#a6e22e">New</span>()
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">e</span>.<span style="color:#a6e22e">Use</span>(<span style="color:#a6e22e">middleware</span>.<span style="color:#a6e22e">Logger</span>())
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">e</span>.<span style="color:#a6e22e">Use</span>(<span style="color:#a6e22e">middleware</span>.<span style="color:#a6e22e">Recover</span>())
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">e</span>.<span style="color:#a6e22e">Use</span>(<span style="color:#a6e22e">middleware</span>.<span style="color:#a6e22e">Secure</span>())
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">e</span>.<span style="color:#a6e22e">GET</span>(<span style="color:#e6db74">&#34;/:id&#34;</span>, <span style="color:#a6e22e">RedirectHandler</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">e</span>.<span style="color:#a6e22e">GET</span>(<span style="color:#e6db74">&#34;/&#34;</span>, <span style="color:#a6e22e">IndexHandler</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">e</span>.<span style="color:#a6e22e">POST</span>(<span style="color:#e6db74">&#34;/submit&#34;</span>, <span style="color:#a6e22e">SubmitHandler</span>)
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">e</span>.<span style="color:#a6e22e">Logger</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">e</span>.<span style="color:#a6e22e">Start</span>(<span style="color:#e6db74">&#34;:8080&#34;</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>This will create three different routes/handlers.</p>
<p>The <code>/:id</code>, which will redirect the user to the required website</p>
<p>The <code>/</code> which will display a url submission form for new urls to be added</p>
<p>Finally the <code>/submit</code> which will handle url submissions from the form in <code>/</code></p>
<h3 id="redirect-handler">Redirect Handler</h3>
<p>The most important part of our application is the redirect handler, which will redirect the user to the url that was specified.</p>
<p>Before we create any urls we first have to declare some variables and make a helper function</p>
<p>In order to have a random ending to our url. eg <code>/M61YlA</code>, we will create a new function called <code>GenerateRandomString</code></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#66d9ef">const</span> <span style="color:#a6e22e">charset</span> = <span style="color:#e6db74">&#34;abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">generateRandomString</span>(<span style="color:#a6e22e">length</span> <span style="color:#66d9ef">int</span>) <span style="color:#66d9ef">string</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">seededRand</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">rand</span>.<span style="color:#a6e22e">New</span>(<span style="color:#a6e22e">rand</span>.<span style="color:#a6e22e">NewSource</span>(<span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Now</span>().<span style="color:#a6e22e">UnixNano</span>()))
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">result</span> []<span style="color:#66d9ef">byte</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">i</span> <span style="color:#f92672">:=</span> <span style="color:#ae81ff">0</span>; <span style="color:#a6e22e">i</span> &lt; <span style="color:#a6e22e">length</span>; <span style="color:#a6e22e">i</span><span style="color:#f92672">++</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">index</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">seededRand</span>.<span style="color:#a6e22e">Intn</span>(len(<span style="color:#a6e22e">charset</span>))
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">result</span> = append(<span style="color:#a6e22e">result</span>, <span style="color:#a6e22e">charset</span>[<span style="color:#a6e22e">index</span>])
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> string(<span style="color:#a6e22e">result</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>This will select <code>length</code> random characters from the charset. If you want your slugs (urls), to not contain any capital letters, you can remove them from the charset.</p>
<p>Now we will need to have a place to store all of our links. In this example we will be storing them in memory and not a database.</p>
<p>Create a new struct called <code>Link</code> and a map called <code>LinkMap</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#66d9ef">type</span> <span style="color:#a6e22e">Link</span> <span style="color:#66d9ef">struct</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">Id</span> <span style="color:#66d9ef">string</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">Url</span> <span style="color:#66d9ef">string</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">var</span> <span style="color:#a6e22e">linkMap</span> = <span style="color:#66d9ef">map</span>[<span style="color:#66d9ef">string</span>]<span style="color:#f92672">*</span><span style="color:#a6e22e">models</span>.<span style="color:#a6e22e">Link</span>{}
</span></span></code></pre></div><p>You can also add some sample data to it.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#66d9ef">var</span> <span style="color:#a6e22e">linkMap</span> = <span style="color:#66d9ef">map</span>[<span style="color:#66d9ef">string</span>]<span style="color:#f92672">*</span><span style="color:#a6e22e">Link</span>{ <span style="color:#e6db74">&#34;example&#34;</span>: { <span style="color:#a6e22e">Id</span>: <span style="color:#e6db74">&#34;example&#34;</span>, <span style="color:#a6e22e">Url</span>: <span style="color:#e6db74">&#34;https://example.com&#34;</span>, }, }
</span></span></code></pre></div><p>Now we can (finally) create our <code>RedirectHandler</code>, which will handle all of the redirects for our url shortener.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">RedirectHandler</span>(<span style="color:#a6e22e">c</span> <span style="color:#a6e22e">echo</span>.<span style="color:#a6e22e">Context</span>) <span style="color:#66d9ef">error</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">id</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">Param</span>(<span style="color:#e6db74">&#34;id&#34;</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">link</span>, <span style="color:#a6e22e">found</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">linkMap</span>[<span style="color:#a6e22e">id</span>]
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">if</span> !<span style="color:#a6e22e">found</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">String</span>(<span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">StatusNotFound</span>, <span style="color:#e6db74">&#34;Link not found&#34;</span>)
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">Redirect</span>(<span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">StatusMovedPermanently</span>, <span style="color:#a6e22e">link</span>.<span style="color:#a6e22e">Url</span>)
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>This function will get the id of the link eg <code>/123</code> and will look for it in the global <code>LinkMap</code>, if it is not available it will return an error that the link was not found. Otherwise it will redirect the user to the specified url using a <code>301 Permanently Moved</code> http response code.</p>
<h2 id="recap-1">Recap #1</h2>
<p>The code so far should look something like this:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> (
</span></span><span style="display:flex;"><span><span style="color:#e6db74">&#34;math/rand&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#e6db74">&#34;time&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#e6db74">&#34;github.com/labstack/echo/v4&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#e6db74">&#34;github.com/labstack/echo/v4/middleware&#34;</span>
</span></span><span style="display:flex;"><span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">type</span> <span style="color:#a6e22e">Link</span> <span style="color:#66d9ef">struct</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">Id</span> <span style="color:#66d9ef">string</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">Url</span> <span style="color:#66d9ef">string</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">const</span> <span style="color:#a6e22e">charset</span> = <span style="color:#e6db74">&#34;abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">var</span> <span style="color:#a6e22e">linkMap</span> = <span style="color:#66d9ef">map</span>[<span style="color:#66d9ef">string</span>]<span style="color:#f92672">*</span><span style="color:#a6e22e">Link</span>{ <span style="color:#e6db74">&#34;example&#34;</span>: { <span style="color:#a6e22e">Id</span>: <span style="color:#e6db74">&#34;example&#34;</span>, <span style="color:#a6e22e">Url</span>: <span style="color:#e6db74">&#34;https://example.com&#34;</span>, }, }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">e</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">echo</span>.<span style="color:#a6e22e">New</span>()
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">e</span>.<span style="color:#a6e22e">Use</span>(<span style="color:#a6e22e">middleware</span>.<span style="color:#a6e22e">Logger</span>())
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">e</span>.<span style="color:#a6e22e">Use</span>(<span style="color:#a6e22e">middleware</span>.<span style="color:#a6e22e">Recover</span>())
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">e</span>.<span style="color:#a6e22e">Use</span>(<span style="color:#a6e22e">middleware</span>.<span style="color:#a6e22e">Secure</span>())
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">e</span>.<span style="color:#a6e22e">GET</span>(<span style="color:#e6db74">&#34;/:id&#34;</span>, <span style="color:#a6e22e">RedirectHandler</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#75715e">//e.GET(&#34;/&#34;, IndexHandler)
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>	<span style="color:#75715e">//e.POST(&#34;/submit&#34;, SubmitHandler)
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>	
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">e</span>.<span style="color:#a6e22e">Logger</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">e</span>.<span style="color:#a6e22e">Start</span>(<span style="color:#e6db74">&#34;:8080&#34;</span>))
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">RedirectHandler</span>(<span style="color:#a6e22e">c</span> <span style="color:#a6e22e">echo</span>.<span style="color:#a6e22e">Context</span>) <span style="color:#66d9ef">error</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">id</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">Param</span>(<span style="color:#e6db74">&#34;id&#34;</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">link</span>, <span style="color:#a6e22e">found</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">linkMap</span>[<span style="color:#a6e22e">id</span>]
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">if</span> !<span style="color:#a6e22e">found</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">String</span>(<span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">StatusNotFound</span>, <span style="color:#e6db74">&#34;Link not found&#34;</span>)
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">Redirect</span>(<span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">StatusMovedPermanently</span>, <span style="color:#a6e22e">link</span>.<span style="color:#a6e22e">Url</span>)
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">generateRandomString</span>(<span style="color:#a6e22e">length</span> <span style="color:#66d9ef">int</span>) <span style="color:#66d9ef">string</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">seededRand</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">rand</span>.<span style="color:#a6e22e">New</span>(<span style="color:#a6e22e">rand</span>.<span style="color:#a6e22e">NewSource</span>(<span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Now</span>().<span style="color:#a6e22e">UnixNano</span>()))
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">result</span> []<span style="color:#66d9ef">byte</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">i</span> <span style="color:#f92672">:=</span> <span style="color:#ae81ff">0</span>; <span style="color:#a6e22e">i</span> &lt; <span style="color:#a6e22e">length</span>; <span style="color:#a6e22e">i</span><span style="color:#f92672">++</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">index</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">seededRand</span>.<span style="color:#a6e22e">Intn</span>(len(<span style="color:#a6e22e">charset</span>))
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">result</span> = append(<span style="color:#a6e22e">result</span>, <span style="color:#a6e22e">charset</span>[<span style="color:#a6e22e">index</span>])
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> string(<span style="color:#a6e22e">result</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Run the server</p>
<pre tabindex="0"><code>go run .
</code></pre><p>You might also want to install any missing dependencies:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>go mod tidy
</span></span></code></pre></div><p>If you head to
<code>localhost:8080/example</code> you should be redirected to example.com</p>
<h3 id="submission-handlers">Submission Handlers</h3>
<p>We will now define two new routes inside of our main function</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#a6e22e">e</span>.<span style="color:#a6e22e">GET</span>(<span style="color:#e6db74">&#34;/&#34;</span>, <span style="color:#a6e22e">IndexHandler</span>)
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">e</span>.<span style="color:#a6e22e">POST</span>(<span style="color:#e6db74">&#34;/submit&#34;</span>, <span style="color:#a6e22e">SubmitHandler</span>)
</span></span></code></pre></div><p>These two handlers will handle the default page displayed in / which will contain a form that will be submitted to /submit in a post request.</p>
<p>For the <code>IndexHandler</code> our code will look something like this:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">IndexHandler</span>(<span style="color:#a6e22e">c</span> <span style="color:#a6e22e">echo</span>.<span style="color:#a6e22e">Context</span>) <span style="color:#66d9ef">error</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">html</span> <span style="color:#f92672">:=</span> <span style="color:#e6db74">`
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">		&lt;h1&gt;Submit a new website&lt;/h1&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">		&lt;form action=&#34;https://4rkal.com/submit&#34; method=&#34;POST&#34;&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">		&lt;label for=&#34;url&#34;&gt;Website URL:&lt;/label&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">		&lt;input type=&#34;text&#34; id=&#34;url&#34; name=&#34;url&#34;&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">		&lt;input type=&#34;submit&#34; value=&#34;Submit&#34;&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">		&lt;/form&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">		&lt;h2&gt;Existing Links &lt;/h2&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">		&lt;ul&gt;`</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">_</span>, <span style="color:#a6e22e">link</span> <span style="color:#f92672">:=</span> <span style="color:#66d9ef">range</span> <span style="color:#a6e22e">linkMap</span> {
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">html</span> <span style="color:#f92672">+=</span> <span style="color:#e6db74">`&lt;li&gt;&lt;a href=&#34;https://4rkal.com/`</span> <span style="color:#f92672">+</span> <span style="color:#a6e22e">link</span>.<span style="color:#a6e22e">Id</span> <span style="color:#f92672">+</span> <span style="color:#e6db74">`&#34;&gt;`</span> <span style="color:#f92672">+</span> <span style="color:#a6e22e">link</span>.<span style="color:#a6e22e">Id</span> <span style="color:#f92672">+</span> <span style="color:#e6db74">`&lt;/a&gt;&lt;/li&gt;`</span>
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">html</span> <span style="color:#f92672">+=</span> <span style="color:#e6db74">`&lt;/ul&gt;`</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">HTML</span>(<span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">StatusOK</span>, <span style="color:#a6e22e">html</span>)
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>When we visit <code>/</code> a submission for will be rendered, to submit a new website. Under the form we will see all registered links from our <code>Linkmap</code></p>
<p>PS it is not recommended that you use html like this. You should be separating the html file or using a library like <a href="https://templ.guide">templ</a>.</p>
<p>The submission handler <code>SubmitHandler</code> should look something like this</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">SubmitHandler</span>(<span style="color:#a6e22e">c</span> <span style="color:#a6e22e">echo</span>.<span style="color:#a6e22e">Context</span>) <span style="color:#66d9ef">error</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">url</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">FormValue</span>(<span style="color:#e6db74">&#34;url&#34;</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">url</span> <span style="color:#f92672">==</span> <span style="color:#e6db74">&#34;&#34;</span> {
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">String</span>(<span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">StatusBadRequest</span>, <span style="color:#e6db74">&#34;URL is required&#34;</span>)
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">if</span> !(len(<span style="color:#a6e22e">url</span>) <span style="color:#f92672">&gt;=</span> <span style="color:#ae81ff">4</span> <span style="color:#f92672">&amp;&amp;</span> (<span style="color:#a6e22e">url</span>[:<span style="color:#ae81ff">4</span>] <span style="color:#f92672">==</span> <span style="color:#e6db74">&#34;http&#34;</span> <span style="color:#f92672">||</span> <span style="color:#a6e22e">url</span>[:<span style="color:#ae81ff">5</span>] <span style="color:#f92672">==</span> <span style="color:#e6db74">&#34;https&#34;</span>)) {
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">url</span> = <span style="color:#e6db74">&#34;https://&#34;</span> <span style="color:#f92672">+</span> <span style="color:#a6e22e">url</span>
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">id</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">generateRandomString</span>(<span style="color:#ae81ff">8</span>)
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">linkMap</span>[<span style="color:#a6e22e">id</span>] = <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">Link</span>{<span style="color:#a6e22e">Id</span>: <span style="color:#a6e22e">id</span>, <span style="color:#a6e22e">Url</span>: <span style="color:#a6e22e">url</span>}
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">Redirect</span>(<span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">StatusSeeOther</span>, <span style="color:#e6db74">&#34;/&#34;</span>)
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>This handler will take a url from the form that was submitted, do some (simple) input validation and then append it to the linkMap.</p>
<h2 id="final-recap">Final Recap</h2>
<p>The code for our url shortener is:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> (
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;math/rand&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;net/http&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;time&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;github.com/labstack/echo/v4&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;github.com/labstack/echo/v4/middleware&#34;</span>
</span></span><span style="display:flex;"><span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">type</span> <span style="color:#a6e22e">Link</span> <span style="color:#66d9ef">struct</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">Id</span> <span style="color:#66d9ef">string</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">Url</span> <span style="color:#66d9ef">string</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">const</span> <span style="color:#a6e22e">charset</span> = <span style="color:#e6db74">&#34;abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">var</span> <span style="color:#a6e22e">linkMap</span> = <span style="color:#66d9ef">map</span>[<span style="color:#66d9ef">string</span>]<span style="color:#f92672">*</span><span style="color:#a6e22e">Link</span>{<span style="color:#e6db74">&#34;example&#34;</span>: {<span style="color:#a6e22e">Id</span>: <span style="color:#e6db74">&#34;example&#34;</span>, <span style="color:#a6e22e">Url</span>: <span style="color:#e6db74">&#34;https://example.com&#34;</span>}}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">e</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">echo</span>.<span style="color:#a6e22e">New</span>()
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">e</span>.<span style="color:#a6e22e">Use</span>(<span style="color:#a6e22e">middleware</span>.<span style="color:#a6e22e">Logger</span>())
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">e</span>.<span style="color:#a6e22e">Use</span>(<span style="color:#a6e22e">middleware</span>.<span style="color:#a6e22e">Recover</span>())
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">e</span>.<span style="color:#a6e22e">Use</span>(<span style="color:#a6e22e">middleware</span>.<span style="color:#a6e22e">Secure</span>())
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">e</span>.<span style="color:#a6e22e">GET</span>(<span style="color:#e6db74">&#34;/:id&#34;</span>, <span style="color:#a6e22e">RedirectHandler</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">e</span>.<span style="color:#a6e22e">GET</span>(<span style="color:#e6db74">&#34;/&#34;</span>, <span style="color:#a6e22e">IndexHandler</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">e</span>.<span style="color:#a6e22e">POST</span>(<span style="color:#e6db74">&#34;/submit&#34;</span>, <span style="color:#a6e22e">SubmitHandler</span>)
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">e</span>.<span style="color:#a6e22e">Logger</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">e</span>.<span style="color:#a6e22e">Start</span>(<span style="color:#e6db74">&#34;:8080&#34;</span>))
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">generateRandomString</span>(<span style="color:#a6e22e">length</span> <span style="color:#66d9ef">int</span>) <span style="color:#66d9ef">string</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">seededRand</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">rand</span>.<span style="color:#a6e22e">New</span>(<span style="color:#a6e22e">rand</span>.<span style="color:#a6e22e">NewSource</span>(<span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Now</span>().<span style="color:#a6e22e">UnixNano</span>()))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">result</span> []<span style="color:#66d9ef">byte</span> 
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">i</span> <span style="color:#f92672">:=</span> <span style="color:#ae81ff">0</span>; <span style="color:#a6e22e">i</span> &lt; <span style="color:#a6e22e">length</span>; <span style="color:#a6e22e">i</span><span style="color:#f92672">++</span> {
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">index</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">seededRand</span>.<span style="color:#a6e22e">Intn</span>(len(<span style="color:#a6e22e">charset</span>))
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">result</span> = append(<span style="color:#a6e22e">result</span>, <span style="color:#a6e22e">charset</span>[<span style="color:#a6e22e">index</span>])
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> string(<span style="color:#a6e22e">result</span>)
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">RedirectHandler</span>(<span style="color:#a6e22e">c</span> <span style="color:#a6e22e">echo</span>.<span style="color:#a6e22e">Context</span>) <span style="color:#66d9ef">error</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">id</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">Param</span>(<span style="color:#e6db74">&#34;id&#34;</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">link</span>, <span style="color:#a6e22e">found</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">linkMap</span>[<span style="color:#a6e22e">id</span>]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">if</span> !<span style="color:#a6e22e">found</span> {
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">String</span>(<span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">StatusNotFound</span>, <span style="color:#e6db74">&#34;Link not found&#34;</span>)
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">Redirect</span>(<span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">StatusMovedPermanently</span>, <span style="color:#a6e22e">link</span>.<span style="color:#a6e22e">Url</span>)
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">IndexHandler</span>(<span style="color:#a6e22e">c</span> <span style="color:#a6e22e">echo</span>.<span style="color:#a6e22e">Context</span>) <span style="color:#66d9ef">error</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">html</span> <span style="color:#f92672">:=</span> <span style="color:#e6db74">`
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">		&lt;h1&gt;Submit a new website&lt;/h1&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">		&lt;form action=&#34;https://4rkal.com/submit&#34; method=&#34;POST&#34;&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">		&lt;label for=&#34;url&#34;&gt;Website URL:&lt;/label&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">		&lt;input type=&#34;text&#34; id=&#34;url&#34; name=&#34;url&#34;&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">		&lt;input type=&#34;submit&#34; value=&#34;Submit&#34;&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">		&lt;/form&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">		&lt;h2&gt;Existing Links &lt;/h2&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">		&lt;ul&gt;`</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">_</span>, <span style="color:#a6e22e">link</span> <span style="color:#f92672">:=</span> <span style="color:#66d9ef">range</span> <span style="color:#a6e22e">linkMap</span> {
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">html</span> <span style="color:#f92672">+=</span> <span style="color:#e6db74">`&lt;li&gt;&lt;a href=&#34;https://4rkal.com/`</span> <span style="color:#f92672">+</span> <span style="color:#a6e22e">link</span>.<span style="color:#a6e22e">Id</span> <span style="color:#f92672">+</span> <span style="color:#e6db74">`&#34;&gt;`</span> <span style="color:#f92672">+</span> <span style="color:#a6e22e">link</span>.<span style="color:#a6e22e">Id</span> <span style="color:#f92672">+</span> <span style="color:#e6db74">`&lt;/a&gt;&lt;/li&gt;`</span>
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">html</span> <span style="color:#f92672">+=</span> <span style="color:#e6db74">`&lt;/ul&gt;`</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">HTML</span>(<span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">StatusOK</span>, <span style="color:#a6e22e">html</span>)
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">SubmitHandler</span>(<span style="color:#a6e22e">c</span> <span style="color:#a6e22e">echo</span>.<span style="color:#a6e22e">Context</span>) <span style="color:#66d9ef">error</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">url</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">FormValue</span>(<span style="color:#e6db74">&#34;url&#34;</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">url</span> <span style="color:#f92672">==</span> <span style="color:#e6db74">&#34;&#34;</span> {
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">String</span>(<span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">StatusBadRequest</span>, <span style="color:#e6db74">&#34;URL is required&#34;</span>)
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">if</span> !(len(<span style="color:#a6e22e">url</span>) <span style="color:#f92672">&gt;=</span> <span style="color:#ae81ff">4</span> <span style="color:#f92672">&amp;&amp;</span> (<span style="color:#a6e22e">url</span>[:<span style="color:#ae81ff">4</span>] <span style="color:#f92672">==</span> <span style="color:#e6db74">&#34;http&#34;</span> <span style="color:#f92672">||</span> <span style="color:#a6e22e">url</span>[:<span style="color:#ae81ff">5</span>] <span style="color:#f92672">==</span> <span style="color:#e6db74">&#34;https&#34;</span>)) {
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">url</span> = <span style="color:#e6db74">&#34;https://&#34;</span> <span style="color:#f92672">+</span> <span style="color:#a6e22e">url</span>
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">id</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">generateRandomString</span>(<span style="color:#ae81ff">8</span>)
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">linkMap</span>[<span style="color:#a6e22e">id</span>] = <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">Link</span>{<span style="color:#a6e22e">Id</span>: <span style="color:#a6e22e">id</span>, <span style="color:#a6e22e">Url</span>: <span style="color:#a6e22e">url</span>}
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">Redirect</span>(<span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">StatusSeeOther</span>, <span style="color:#e6db74">&#34;/&#34;</span>)
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><h2 id="closing-words">Closing words</h2>
<p>This is a great small project if you are new to/learning go.</p>
<p>It can be very helpful if you extend beyond this tutorial. For example here are some other ideas that you can add to the project:</p>
<ol>
<li>Enhance the input validation</li>
<li>Track link clicks + Statistics Page</li>
<li>Improve UI (html)</li>
<li>Dockerizing the application</li>
<li>++</li>
</ol>
<p>I did all of those and my url shortener (called shortr) can be accessed under the url <a href="https://app.4rkal.com">app.4rkal.com</a> and the source code is <a href="https://github.com/4rkal/shortr">here</a></p>
<h3 id="join-my-mailing-list">Join my mailing list</h3>
<div style="text-align: left; margin: 0 auto;">
    <form method="post" action="https://newsletter.4rkal.com/subscription/form" style="background: #2c2c2c; color: #f0f0f0; border-radius: 8px; padding: 15px; max-width: 500px; box-shadow: 0 3px 6px rgba(0, 0, 0, 0.2); font-family: Arial, sans-serif;">
        <div style="display: flex; flex-direction: column; gap: 10px;">
            <h3 style="margin: 0; color: #f0f0f0; font-size: 18px;">Subscribe</h3>
            <input type="hidden" name="nonce"/>
            <input type="email" name="email" required placeholder="E-mail" style="width: 100%; padding: 10px; border: 1px solid #666; border-radius: 4px; background: #333; color: #f0f0f0; box-sizing: border-box;"/>
            <div style="display: flex; flex-direction: column; gap: 8px;">
                <label style="margin: 0; color: #f0f0f0; display: none;">
                    <input id="78a75" type="checkbox" name="l" checked value="78a75b30-472d-4790-a5d5-7f2ed49662a4" style="accent-color: #fff;"/>
                    Weekly Roundup
                </label>
                <span style="color: #d0d0d0; display: none;">Where I share what I’ve been up to that week, including articles I’ve published, cool finds, tips and tricks, and more!</span>
                <label style="margin: 0; color: #f0f0f0; display: none;">
                    <input id="b3964" type="checkbox" name="l" checked value="b3964560-37b0-43d3-9df9-26589fd6bf8d" style="accent-color: #fff;"/>
                    New Posts
                </label>
                <span style="color: #d0d0d0; display: none;">Receive an email every time I post something new on my blog</span>
            </div>
            <input type="submit" value="Subscribe" style="width: 100%; padding: 10px; border: none; border-radius: 4px; background: #fff; color: #007bff; font-size: 14px; cursor: pointer; transition: background-color 0.3s ease, box-shadow 0.3s ease; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);"/>
        </div>
        <p style="text-align: center; margin-top: 10px; color: #d0d0d0; font-size: 10px; margin-bottom:0px;">
            No spam, no ads. Unsubscribe at any time.
        </p>
    </form>
</div>]]></content:encoded>
    </item>
    
    <item>
      <title>How to deploy django to production</title>
      <link>https://4rkal.com/posts/django-prod/</link>
      <pubDate>Fri, 20 Sep 2024 11:54:29 +0300</pubDate>
      
      <guid>https://4rkal.com/posts/django-prod/</guid>
      <description>In this article I will show you how to deploy django to production. We will be using nginx, gunicorn and cloudflare tunnels</description>
      <content:encoded><![CDATA[<p>I recently deployed my very own django application to production. The website is called <a href="https://videiro.com">videiro.com</a> and was developed in django + HTML/CSS/JS + Tailwind.</p>
<h2 id="setup">Setup</h2>
<p>I am using a debian 12 server which will expose my application via cloudflare tunnels. All of the static files are being served via nginx and the Django project is being ran by gunicorn.</p>
<p>In this guide I will show you how I set this up.</p>
<h2 id="preparing-the-django-project">Preparing the Django project</h2>
<p>The first thing you will have to do is open the settings.py and change the following</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>Debug <span style="color:#f92672">=</span> <span style="color:#66d9ef">False</span>
</span></span><span style="display:flex;"><span>ALLOWED_HOSTS <span style="color:#f92672">=</span> [<span style="color:#e6db74">&#39;yourdomain.tld&#39;</span>]
</span></span><span style="display:flex;"><span>CSRF_COOKIE_SECURE <span style="color:#f92672">=</span> <span style="color:#66d9ef">True</span>
</span></span><span style="display:flex;"><span>CSRF_TRUSTED_ORIGINS <span style="color:#f92672">=</span> [
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#39;yourdomain.tld&#39;</span>,
</span></span><span style="display:flex;"><span>]
</span></span></code></pre></div><p>You should also change the <code>SECRET_KEY</code> to a long random string, that you should never share with anyone.</p>
<p>After that create a new file called <code>.gitignore</code> and paste the following:</p>
<pre tabindex="0"><code class="language-gitignore" data-lang="gitignore">db.sqlite3
*.pyc
</code></pre><p>This will make sure that the database is not uploaded to our server and that no pyc files are either.</p>
<p>Now you can upload your project to a new github repository (or gitea repository). If you don&rsquo;t want everyone to have access to your source code make sure to set the repository as private.</p>
<p>If you want to make sure that your source code stays private I recommend you setup a selfhosted gitea instance, read  <a href="https://4rkal.com/posts/gitea/">Selfhost your own gitea instance - selfhosted, lightweight github alternative</a>, to learn how to do that.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>git init
</span></span><span style="display:flex;"><span>git branch -M main
</span></span><span style="display:flex;"><span>git add .
</span></span><span style="display:flex;"><span>git commit -m <span style="color:#e6db74">&#34;initial commit&#34;</span>
</span></span><span style="display:flex;"><span>git remote add origin https://...
</span></span><span style="display:flex;"><span>git push -u origin main
</span></span></code></pre></div><p>Now that you we have done that you should login to your server</p>
<h2 id="server-setup">Server setup</h2>
<p>Before configuring anything make sure that you don&rsquo;t allow any ssh logins with a password. Follow <a href="https://4rkal.com/posts/sssh/">Securing ssh with Key-Based authentication</a> to secure your server from those kinds of attacks.</p>
<p>Login to your server</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>ssh user@server.ip
</span></span></code></pre></div><p>Make sure that your packages are up to data</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>sudo apt update <span style="color:#f92672">&amp;&amp;</span> sudo apt upgrade
</span></span></code></pre></div><p>Now install python, pip, git and nginx</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>sudo apt install python3 python3-pip git nginx
</span></span></code></pre></div><p>Now clone your project into your home directory.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>git clone https://...
</span></span><span style="display:flex;"><span>cd my-project
</span></span></code></pre></div><p>Once you&rsquo;re in install the following:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>pip install django django-crispy-forms 
</span></span></code></pre></div><p>Now try to run the project:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>python3 manage.py runserver
</span></span></code></pre></div><p>if you get an error that a package is missing install it and re run.</p>
<h2 id="configuring-gunicorn">Configuring gunicorn</h2>
<p>Now we will setup gunicorn</p>
<p>First install it</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>pip install gunicorn
</span></span></code></pre></div><p>Now create a new file called gunicorn.service with your favorite text editor:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>sudo vim /etc/systemd/system/gunicorn.service
</span></span></code></pre></div><p>And paste the following:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span><span style="color:#f92672">[</span>Unit<span style="color:#f92672">]</span>
</span></span><span style="display:flex;"><span>Description<span style="color:#f92672">=</span>gunicorn daemon
</span></span><span style="display:flex;"><span>After<span style="color:#f92672">=</span>network.target
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">[</span>Service<span style="color:#f92672">]</span>
</span></span><span style="display:flex;"><span>User<span style="color:#f92672">=</span>YOURUSER
</span></span><span style="display:flex;"><span>Group<span style="color:#f92672">=</span>www-data
</span></span><span style="display:flex;"><span>WorkingDirectory<span style="color:#f92672">=</span>/home/YOURUSER/PROJECT
</span></span><span style="display:flex;"><span>ExecStart<span style="color:#f92672">=</span>/path/to/gunicorn --access-logfile - --workers <span style="color:#ae81ff">3</span> --bind 127.0.0.1:8000 PROJECTNAME.wsgi:application
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">[</span>Install<span style="color:#f92672">]</span>
</span></span><span style="display:flex;"><span>WantedBy<span style="color:#f92672">=</span>multi-user.target
</span></span></code></pre></div><p>Change <code>YOURUSER</code> to your user.</p>
<p>To find the path to <code>gunicorn</code> run:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>which gunicorn
</span></span></code></pre></div><p>And your project name is the name of the folder inside of your project that contains the <code>settings.py</code> file.</p>
<p>Now run the following commands to start and enable gunicorn (start on boot)</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>sudo systemctl daemon-reload
</span></span><span style="display:flex;"><span>sudo systemctl start gunicorn.service
</span></span><span style="display:flex;"><span>sudo systemctl enable gunicorn.service
</span></span></code></pre></div><p>Now if you head to 127.0.0.1:8000 you should see your project running.</p>
<p>But were not finished yet</p>
<h2 id="setting-up-nginx">Setting up nginx</h2>
<p>Now we need to serve our static content via nginx.</p>
<p>First create a new file nginx configuration file with your favorite text editor:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>sudo vim /etc/nginx/sites-available/PROJECT
</span></span></code></pre></div><p>Change PROJECT to whatever you want</p>
<p>Now paste the following content:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-nginx" data-lang="nginx"><span style="display:flex;"><span><span style="color:#66d9ef">server</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">listen</span> <span style="color:#ae81ff">80</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">server_name</span> <span style="color:#e6db74">YOURDOMAIN</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">location</span> <span style="color:#e6db74">/static/</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#f92672">alias</span> <span style="color:#e6db74">/var/www/staticfiles/</span>;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">location</span> <span style="color:#e6db74">/</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">proxy_pass</span> <span style="color:#e6db74">http://127.0.0.1:8000</span>;
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">proxy_set_header</span> <span style="color:#e6db74">Host</span> $host;
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">proxy_set_header</span> <span style="color:#e6db74">X-Real-IP</span> $remote_addr;
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">proxy_set_header</span> <span style="color:#e6db74">X-Forwarded-For</span> $proxy_add_x_forwarded_for;
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">proxy_set_header</span> <span style="color:#e6db74">X-Forwarded-Proto</span> $scheme;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Just change YOURDOMAIN to the domain that this will be hosted on.</p>
<p>Create a symbolic link to enable your website:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>sudo ln -s /etc/nginx/sites-available/PROJECT /etc/nginx/sites-enabled/
</span></span></code></pre></div><p>Start and enable nginx:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>sudo systemctl start nginx
</span></span><span style="display:flex;"><span>sudo systemctl enable nginx
</span></span></code></pre></div><h2 id="setup-static-files">Setup static files</h2>
<p>The first thing you will have to do is cd into your (django) project</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>cd project
</span></span></code></pre></div><p>Now run the following command:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>python3 manage.py collectstatic
</span></span></code></pre></div><p>This will create a new folder called <code>staticfiles</code></p>
<p>Now to set up the static files we have two options:</p>
<ol>
<li>Change the user in  <code>/etc/nginx/nginx.conf</code> to your user (less secure)</li>
<li>Copy over the staticfiles to <code>/var/www/</code> (more secure)</li>
</ol>
<p>I will be doing the 2nd option:</p>
<p>First create a new file called staticfiles in /var/www</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>sudo mkdir -p /var/www/staticfiles
</span></span></code></pre></div><p>Now copy over all of the staticfiles from your project there:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>sudo cp staticfiles/* /var/www/staticfiles
</span></span></code></pre></div><p>Now cd into /var/www</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>cd /var/www
</span></span></code></pre></div><p>Change the ownership of all the files</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>sudo chown www-data:www-data staticfiles
</span></span><span style="display:flex;"><span>sudo chown www-data:www-data staticfiles/*
</span></span></code></pre></div><p>Restart the nginx service:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>sudo systemctl restart nginx
</span></span></code></pre></div><p>Now if you head to:</p>
<p><code>127.0.0.1</code></p>
<p>You should see your website running with all of the static files being served!</p>
<h2 id="exposing-via-cloudflare-tunnels">Exposing via cloudflare tunnels</h2>
<p>Now to make your website publicly accessible.</p>
<p>To do this you will need a cloudflare account and a domain pointed to cloudflare.</p>
<p>First head to the <a href="https://one.dash.cloudflare.com/">Zero Trust Dashboard</a></p>
<p>Under <code>Networks</code> click on <code>Tunnels</code> and then <code>Create a tunnel</code></p>
<p>Once created you should <code>Install and run a connector</code>, follow the instructions on the page for your specific setup.</p>
<p>After the connector is running you should click on the <code>Public Hostname</code> tab and <code>Add a public hostname</code>.</p>
<p>Now you should see something like this:
<img loading="lazy" src="/../assets/gitea2.png" type="" alt="Cloudflare dashboard"  /></p>
<p>Fill in the info as I have.
The service type should be <code>HTTP</code> and the url should be <code>127.0.0.1:80</code> or <code>localhost:80</code></p>
<p>Now if you head to the domain that you specified you should see your app up and running.</p>
<p>Congratulations!</p>
<p><strong>If you enjoyed this post and want to support my (mostly unpaid) work , you can <a href="https://4rkal.com/donate">donate here</a>.</strong></p>
<h2 id="join-my-free-newsletter">Join my free newsletter!</h2>
<div style="text-align: left; margin: 0 auto;">
    <form method="post" action="https://newsletter.4rkal.com/subscription/form" style="background: #2c2c2c; color: #f0f0f0; border-radius: 8px; padding: 15px; max-width: 500px; box-shadow: 0 3px 6px rgba(0, 0, 0, 0.2); font-family: Arial, sans-serif;">
        <div style="display: flex; flex-direction: column; gap: 10px;">
            <h3 style="margin: 0; color: #f0f0f0; font-size: 18px;">Subscribe</h3>
            <input type="hidden" name="nonce"/>
            <input type="email" name="email" required placeholder="E-mail" style="width: 100%; padding: 10px; border: 1px solid #666; border-radius: 4px; background: #333; color: #f0f0f0; box-sizing: border-box;"/>
            <div style="display: flex; flex-direction: column; gap: 8px;">
                <label style="margin: 0; color: #f0f0f0; display: none;">
                    <input id="78a75" type="checkbox" name="l" checked value="78a75b30-472d-4790-a5d5-7f2ed49662a4" style="accent-color: #fff;"/>
                    Weekly Roundup
                </label>
                <span style="color: #d0d0d0; display: none;">Where I share what I’ve been up to that week, including articles I’ve published, cool finds, tips and tricks, and more!</span>
                <label style="margin: 0; color: #f0f0f0; display: none;">
                    <input id="b3964" type="checkbox" name="l" checked value="b3964560-37b0-43d3-9df9-26589fd6bf8d" style="accent-color: #fff;"/>
                    New Posts
                </label>
                <span style="color: #d0d0d0; display: none;">Receive an email every time I post something new on my blog</span>
            </div>
            <input type="submit" value="Subscribe" style="width: 100%; padding: 10px; border: none; border-radius: 4px; background: #fff; color: #007bff; font-size: 14px; cursor: pointer; transition: background-color 0.3s ease, box-shadow 0.3s ease; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);"/>
        </div>
        <p style="text-align: center; margin-top: 10px; color: #d0d0d0; font-size: 10px; margin-bottom:0px;">
            No spam, no ads. Unsubscribe at any time.
        </p>
    </form>
</div>]]></content:encoded>
    </item>
    
    <item>
      <title>How to setup a selfhosted newsletter using listmonk</title>
      <link>https://4rkal.com/posts/listmonk/</link>
      <pubDate>Fri, 23 Aug 2024 11:19:17 +0300</pubDate>
      
      <guid>https://4rkal.com/posts/listmonk/</guid>
      <description>Listmonk is an amazing feature packed selfhosted email newsletter manager. It offers loads of features like analytics (clicks, opens, bounces), templates, public subscription pages, importing subscribers and much more!</description>
      <content:encoded><![CDATA[<h2 id="what-is-listmonk">What is listmonk?</h2>
<p><a href="https://listmonk.app">Listmonk</a> is a selfhosted newsletter and mailing list manager. It is free and opensource, so you have full control over your data. It also offers a super clean webui:</p>
<p><img loading="lazy" src="/../assets/listmonk.png" type="" alt="Listmonk WebUI"  /></p>
<h2 id="why-choose-listmonk-over-mailchimp-buttodown-etc">Why choose listmonk over mailchimp, buttodown etc</h2>
<p>For me, running a newsletter means owning my email list.</p>
<p>When people create newsletters they want to break free from the big platforms like Twitter or YouTube. When you use a proprietary service like Mailchimp, you’re still tied down to their rules and limitations. With Listmonk, you get more control and independence, which for me is a huge win.</p>
<p>The other reason is that listmonk is completely free (if you don&rsquo;t count electricity bills/vps hosting bills). Even if you include the cost of your email host + hosting fees it is still tiny compared to mailchimp or buttondown.</p>
<h2 id="listmonk-feature-overview">Listmonk feature overview</h2>
<ol>
<li>Analytics - Tracking email opens, link clicks and bounces</li>
<li>Templates - Advanced html templates with template variables</li>
<li>Public subscription page - See mine <a href="https://newsletter.4rkal.com/subscription/form">here</a></li>
<li>Subscribers import - Import subscribers from other platforms using CSV.</li>
<li>Media Uploads - Upload images etc</li>
<li>Email lists - Separate lists eg Weekly roundup and new posts.</li>
</ol>
<p>And more</p>
<h2 id="requirements-for-running-listmonk">Requirements for running listmonk</h2>
<ol>
<li>A server running linux, either in the cloud or at home. We will be using debian 12, but you can use any other distribution.</li>
<li>An email address to send the newsletter from. Can either be a gmail or a custom one.</li>
</ol>
<h2 id="server-setup">Server Setup</h2>
<p>Before doing anything I highly recommend that you disable password logins for ssh. See <a href="https://4rkal.com/posts/sssh/">Securing ssh with Key-Based authentication</a> for more info on how to do that.</p>
<p>Login to your server via ssh</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>ssh user@server.ip
</span></span></code></pre></div><p>Make sure that all packages are up to date</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>sudo apt update <span style="color:#f92672">&amp;&amp;</span> sudo apt upgrade
</span></span></code></pre></div><p>You will also have to have docker installed, if you don&rsquo;t install it, <a href="https://docs.docker.com/engine/install/debian/">instructions for debian</a></p>
<p>Create a new directory to host listmonk&rsquo;s configuration files</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>mkdir listmonk <span style="color:#f92672">&amp;&amp;</span> cd listmonk
</span></span></code></pre></div><p>Download the listmonk docker-compose file</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>curl -O https://github.com/knadh/listmonk/blob/master/docker-compose.yml
</span></span></code></pre></div><p>Run it using docker:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>docker compose up -d
</span></span></code></pre></div><p>Now if you head to</p>
<pre tabindex="0"><code>localhost:9000
</code></pre><p>You should see listmonk up and running</p>
<p>But first we should change some settings in the configuration files</p>
<pre tabindex="0"><code>vim config.toml
</code></pre><p>Here you can change the default admin password. I also changed the address to 0.0.0.0 so that I can access it via the servers ip.</p>
<h2 id="listmonk-customization">Listmonk customization</h2>
<p>Now head to the webui at</p>
<pre tabindex="0"><code>localhost:9000
</code></pre><p>Login and head to the settings</p>
<p>In the <code>General</code> tab you can customize the default from email, root url, site name, favicon and admin notification emails</p>
<p>Here&rsquo;s what my settings look like:</p>
<p><img loading="lazy" src="/listmonk2.png" type="" alt="Listmonk Settings"  /></p>
<p>You can customize the page to your liking.</p>
<p>Save by clicking on the save button in the top right corner.</p>
<h2 id="email-setup">Email setup</h2>
<p>For the next part you will either need a gmail account or any other email provider that give you smtp connection</p>
<p>If you want a great custom email I recommend ionos, you can get up to 10$ in credits by using my link <a href="http://aklam.io/bbxioA">Ionos - Email &amp; Office 10$ credits </a> that is the provider that I am currently using.</p>
<p>In this guide I will show you how to set this up for these two providers, but the setup should be similar for others too.</p>
<p><strong>IMPORTANT</strong>: Both of these hosts have a limit on how many emails can be sent out per hour or per day. For ionos that is 500/hour. Setting up a <a href="#sliding-window-limit">Sliding Window Limit</a> is very important.</p>
<h3 id="setup-for-gmail">Setup for gmail</h3>
<p>I recommend that you use a different gmail account from your personal one.</p>
<p>The first thing you will have to do is generate an app password, to do that head to <a href="https://myaccount.google.com/apppasswords">Create and manage app passwords</a> and create a new one called listmonk. Copy the password that is generated and save it somewhere safe.</p>
<p>Now head over to the listmonk webui</p>
<p>In the <code>SMTP</code> tab in settings you will find this:</p>
<p><img loading="lazy" src="/../assets/listmonk3.png" type="" alt="Gmail SMTP"  /></p>
<p>Click on the gmail option as circled.</p>
<p>Now enter your full email address (including @gmail.com) in the username field</p>
<p>And in the password field enter the app password we generated before.</p>
<p>Now click on the <code>Test connection</code> button in the bottom right corner, enter a test email and click on <code>Send e-mail</code>.</p>
<p>If you configured everything correctly you should now get a test message to the email specified.</p>
<p>Don&rsquo;t forget to save!</p>
<h3 id="setup-for-ionos">Setup for ionos</h3>
<p>You should probably generate a new email for the newsletter, eg `<a href="mailto:newsletter@yourdomain.tld">newsletter@yourdomain.tld</a>.</p>
<p>Head over to the listmonk webui</p>
<p>Now in the <code>SMTP</code> tab in the settings you see this</p>
<p><img loading="lazy" src="/../assets/listmonk4.png" type="" alt="Gmail SMTP"  /></p>
<p>The ionos smtp server settings are:</p>
<p>Host: <code>smtp.ionos.com</code></p>
<p>Port: <code>465</code></p>
<p>TLS: <code>SSL/TLS</code></p>
<p><strong>IMPORTANT</strong>: If you’re using IONOS UK or another specific regional version, you need to adjust the host name. For example, if you’re on IONOS UK, you should use <code>smtp.ionos.co.uk</code> instead of the global <code>smtp.ionos.com</code>.</p>
<p>Now in the username field you should enter the full email address <code>newsletter@yourdomain.tld</code> and the password is the normal user password.</p>
<p>Now to test the connection click on the <code>Test connection</code> button in the bottom right corner, enter a test email and click on <code>Send e-mail</code>.</p>
<p>If you configured everything correctly you should now get a test message to the email specified.</p>
<p>Don&rsquo;t forget to save!</p>
<h2 id="sliding-window-limit">Sliding window limit</h2>
<p>This is very important to setup when email providers limit the amount of email to be sent per hour or per day. You can access the Sliding window limit in <code>Settings</code> under the performance tab. For ionos I have it set at 500 emails/hour</p>
<h2 id="exposing-via-cloudflare-tunnels">Exposing via cloudflare tunnels</h2>
<p>I will be making my instance publicly accessible using cloudflare tunnels.</p>
<p>To do this you will need a cloudflare account and a domain pointed to cloudflare.</p>
<p>First head to the <a href="https://one.dash.cloudflare.com/">Zero Trust Dashboard</a></p>
<p>Under <code>Networks</code> click on <code>Tunnels</code> and then <code>Create a tunnel</code></p>
<p>Once created you should <code>Install and run a connector</code>, follow the instructions on the page for your specific setup.</p>
<p>After the connector is running you should click on the <code>Public Hostname</code> tab and <code>Add a public hostname</code>.</p>
<p>Now you should see something like this:
<img loading="lazy" src="/../assets/listmonk5.png" type="" alt="Zero Trust Dashboard"  /></p>
<p>Fill in the info as I have.</p>
<p>The service type should be <code>HTTP</code> and the url should be <code>yourserverurl:9000</code>, in my case that&rsquo;s 127.0.0.1:9000</p>
<p>Now if you head to the domain that you specified you should see gitea up and running.</p>
<p>In my case you can access my newsletter page <a href="https://newsletter.4rkal.com/subscription/form">here</a></p>
<h2 id="listmonk-feature-overview-1">Listmonk feature overview</h2>
<p>These are all of the features that listmonk offers:</p>
<h3 id="templates">Templates</h3>
<p>Listmonk offers amazing built in template support.</p>
<p>All templates are written in HTML.</p>
<p>You can access the templates by going to <code>Campaigns &gt; Templates</code>.</p>
<p>Don&rsquo;t forget to always include <code>{{ template &quot;content&quot; . }}</code> (for the main content) and also an unsubscribe button in all of your templates</p>
<h3 id="campaigns">Campaigns</h3>
<p>You can create a new campaign (email) by going to <code>Campaigns &gt; All Campaigns</code></p>
<p>Here you can select a campaign name, subject the list&rsquo;s you want to target and the template</p>
<h3 id="email-lists">Email lists</h3>
<p>You can create new lists by going to <code>Lists &gt; All Lists</code>.</p>
<p>For example I have two lists:</p>
<ol>
<li>New posts - Receive an email every time I post something new on my blog</li>
<li>Weekly Roundup - Join my weekly roundup, where I share what I’ve been up to that week, including articles I’ve published, cool finds, tips and tricks and more!</li>
</ol>
<p>Not everyone wants to receive an email every time I post a new article, so I created two lists!</p>
<h3 id="html-forms">HTML Forms</h3>
<p>Listmonk also offers embeddable html forms, to subscribe to the email list. You can access the form builder by going to <code>Lists &gt; Forms</code></p>
<h3 id="public-subscription-page">Public subscription page</h3>
<p>Except for the HTML forms listmonk also has a public subscription page. For example <a href="https://newsletter.4rkal.com/subscription/form">here</a> is mine.</p>
<p>It can also be accessed under `Lists &gt; Forms</p>
<h3 id="campaign-analytics">Campaign analytics</h3>
<p>You can track the views, clicks and bounces of your email campaigns by going to <code>Campaigns &gt; Analytics</code>.</p>
<h3 id="import-subscribers">Import subscribers</h3>
<p>You can import subscribers from other platforms by going to <code>Subscribers &gt; Import</code>. It currently supports CSV or ZIP files.</p>
<p>These are the most important features that listmonk offers (I&rsquo;m sure I forgot some).</p>
<h2 id="thats-all-folks">That&rsquo;s all folks</h2>
<p>If this article helped you out, consider joining my (listmonk) <strong>newsletter bellow</strong>:</p>
<div style="text-align: left; margin: 0 auto;">
    <form method="post" action="https://newsletter.4rkal.com/subscription/form" style="background: #2c2c2c; color: #f0f0f0; border-radius: 8px; padding: 15px; max-width: 500px; box-shadow: 0 3px 6px rgba(0, 0, 0, 0.2); font-family: Arial, sans-serif;">
        <div style="display: flex; flex-direction: column; gap: 10px;">
            <h3 style="margin: 0; color: #f0f0f0; font-size: 18px;">Subscribe</h3>
            <input type="hidden" name="nonce"/>
            <input type="email" name="email" required placeholder="E-mail" style="width: 100%; padding: 10px; border: 1px solid #666; border-radius: 4px; background: #333; color: #f0f0f0; box-sizing: border-box;"/>
            <div style="display: flex; flex-direction: column; gap: 8px;">
                <label style="margin: 0; color: #f0f0f0; display: none;">
                    <input id="78a75" type="checkbox" name="l" checked value="78a75b30-472d-4790-a5d5-7f2ed49662a4" style="accent-color: #fff;"/>
                    Weekly Roundup
                </label>
                <span style="color: #d0d0d0; display: none;">Where I share what I’ve been up to that week, including articles I’ve published, cool finds, tips and tricks, and more!</span>
                <label style="margin: 0; color: #f0f0f0; display: none;">
                    <input id="b3964" type="checkbox" name="l" checked value="b3964560-37b0-43d3-9df9-26589fd6bf8d" style="accent-color: #fff;"/>
                    New Posts
                </label>
                <span style="color: #d0d0d0; display: none;">Receive an email every time I post something new on my blog</span>
            </div>
            <input type="submit" value="Subscribe" style="width: 100%; padding: 10px; border: none; border-radius: 4px; background: #fff; color: #007bff; font-size: 14px; cursor: pointer; transition: background-color 0.3s ease, box-shadow 0.3s ease; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);"/>
        </div>
        <p style="text-align: center; margin-top: 10px; color: #d0d0d0; font-size: 10px; margin-bottom:0px;">
            No spam, no ads. Unsubscribe at any time.
        </p>
    </form>
</div>
]]></content:encoded>
    </item>
    
    <item>
      <title>Selfhost your own gitea instance - selfhosted, lightweight github alternative</title>
      <link>https://4rkal.com/posts/gitea/</link>
      <pubDate>Mon, 19 Aug 2024 19:21:15 +0300</pubDate>
      
      <guid>https://4rkal.com/posts/gitea/</guid>
      <description>In this article I&amp;rsquo;ll walk you through how you can run your own gitea instance. But first
What is gitea? Gitea is a painless selfhosted Git service. It is written in Go and is extremely lightweight. I run a gitea instance on my Le Potato and it barely uses any resources.
Why use gitea (vs GitHub, GitLab etc) I started running my own Gitea instance because I wanted a private place to host my Obsidian notes.</description>
      <content:encoded><![CDATA[<p>In this article I&rsquo;ll walk you through how you can run your own gitea instance. But first</p>
<h2 id="what-is-gitea">What is gitea?</h2>
<p>Gitea is a painless selfhosted Git service. It is written in Go and is extremely lightweight. I run a gitea instance on my <a href="https://libre.computer/products/aml-s905x-cc/">Le Potato</a> and it barely uses any resources.</p>
<h2 id="why-use-gitea-vs-github-gitlab-etc">Why use gitea (vs GitHub, GitLab etc)</h2>
<p>I started running my own Gitea instance because I wanted a private place to host my <a href="https://obsidian.md">Obsidian</a> notes. I did not want to have them in a private GitHub repository since it&rsquo;s not on my own hardware. GitLab is harder to spin up and has a lot of features that I do not need.</p>
<p>If you want an easy to spin up, private git service gitea is your way to go.</p>
<h1 id="setup">Setup</h1>
<p>In this guide I will be using debian 12. The setup should be the same on any other distribution since we will be using docker.</p>
<h2 id="installing-and-setting-up-docker">Installing and setting up docker</h2>
<p>The first thing you will need is docker installed on your system.</p>
<p><a href="https://docs.docker.com/engine/install/debian/">Install docker on debian</a></p>
<p>Also make sure to add your user to the docker group. This will allow you to run docker commands without sudo.</p>
<pre tabindex="0"><code>usermod -aG docker $USER
</code></pre><p>Now reboot</p>
<h2 id="docker-composeyml">Docker-compose.yml</h2>
<p>Once docker is installed. We have to get gitea up and running</p>
<p>First create a new directory. This will host our docker-compose file.</p>
<p><code>mkdir gitea</code></p>
<p>Then create/edit docker-compose.yml in your favourite text editor.</p>
<p><code>vim docker-compose.yml</code></p>
<p>Then paste the following content:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">version</span>: <span style="color:#e6db74">&#34;3&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">networks</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">gitea</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">external</span>: <span style="color:#66d9ef">false</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">services</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">server</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">gitea/gitea:latest</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">container_name</span>: <span style="color:#ae81ff">gitea</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">environment</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">USER_UID=1000</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">USER_GID=1000</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">restart</span>: <span style="color:#ae81ff">always</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">networks</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">gitea</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">volumes</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">./gitea:/data</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">/etc/timezone:/etc/timezone:ro</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">/etc/localtime:/etc/localtime:ro</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">ports</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#e6db74">&#34;3000:3000&#34;</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#e6db74">&#34;222:22&#34;</span>
</span></span></code></pre></div><p>You can change any of the default ports eg switching 3000 to 8000 can be done like this:</p>
<pre tabindex="0"><code>ports:
- &#34;8080:3000&#34;
</code></pre><p>You can setup gitea using a <a href="https://docs.gitea.com/installation/install-with-docker#postgresql-database">PostgreSQL</a> or <a href="https://docs.gitea.com/installation/install-with-docker#mysql-database">MySQL</a> database. But at least for my needs a simple SQLite3 database is more than enough.</p>
<p>Since I want my repositories to still exist even if the container is deleted I will use named volumes. The configuration file with named volumes should look something like this:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">version</span>: <span style="color:#e6db74">&#34;3&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">networks</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">gitea</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">external</span>: <span style="color:#66d9ef">false</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">volumes</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">gitea</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">driver</span>: <span style="color:#ae81ff">local</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">services</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">server</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">gitea/gitea:latest</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">container_name</span>: <span style="color:#ae81ff">gitea</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">restart</span>: <span style="color:#ae81ff">always</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">networks</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">gitea</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">volumes</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">gitea:/data</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">/etc/timezone:/etc/timezone:ro</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">/etc/localtime:/etc/localtime:ro</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">ports</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#e6db74">&#34;3000:3000&#34;</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#e6db74">&#34;222:22&#34;</span>
</span></span></code></pre></div><h2 id="starting-the-container-and-additional-configuration">Starting the container and additional configuration</h2>
<p>Now you can start the container by typing:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker compose up -d
</span></span></code></pre></div><p>The -d flag will run it in detach mode. If you want to see the logs live you can remove it.</p>
<p>After docker is done pulling, gitea should be up and running.</p>
<p>Now open up:</p>
<p><code>localhost:3000</code> or <code>yourserverip:3000</code></p>
<p>And you should see something like this:</p>
<p><img loading="lazy" src="/../assets/gitea.png" type="" alt="Gitea Setup Dashboard"  /></p>
<p>Fill in all of the required information. Since I will be using my subdomain <code>git.4rkal.com</code> I set the server domain and gitea base url to that.</p>
<p>Here you will also have the option to enable sending emails for email verification and notifications. I will be enabling that by using a free (shitposting) email from <a href="https://cock.li">cock.li</a>.</p>
<p>After you have entered all the required info click on <code>Install Gitea</code>.</p>
<p>After the installation is complete you should be up and running</p>
<h1 id="make-publicly-accessible-with-cloudflare-tunnels-optional">Make publicly accessible with cloudflare tunnels (optional)</h1>
<p>I will be making my instance publicly accessible using cloudflare tunnels.</p>
<p>To do this you will need a cloudflare account and a domain pointed to cloudflare.</p>
<p>First head to the <a href="https://one.dash.cloudflare.com/">Zero Trust Dashboard</a></p>
<p>Under <code>Networks</code> click on <code>Tunnels</code> and then <code>Create a tunnel</code></p>
<p>Once created you should <code>Install and run a connector</code>, follow the instructions on the page for your specific setup.</p>
<p>After the connector is running you should click on the <code>Public Hostname</code> tab and <code>Add a public hostname</code>.</p>
<p>Now you should see something like this:
<img loading="lazy" src="/../assets/gitea2.png" type="" alt="Zero Trust Dashboard"  /></p>
<p>Fill in the info as I have.</p>
<p>You can  create a new subdomain eg git or gitea</p>
<p>The service type should be <code>HTTP</code> and the url should be <code>yourserverurl:3000</code></p>
<p>Now if you head to the domain that you specified you should see gitea up and running.</p>
<p>In my case you can access my public gitea instance at <a href="https://git.4rkal.com">git.4rkal.com</a></p>
<p>Congratulations, you now have your very own gitea instance!</p>
<p><strong>If you enjoyed this article, consider <a href="https://4rkal.eu.org/donate">supporting me</a></strong></p>
<div style="text-align: left; margin: 0 auto;">
    <form method="post" action="https://newsletter.4rkal.com/subscription/form" style="background: #2c2c2c; color: #f0f0f0; border-radius: 8px; padding: 15px; max-width: 500px; box-shadow: 0 3px 6px rgba(0, 0, 0, 0.2); font-family: Arial, sans-serif;">
        <div style="display: flex; flex-direction: column; gap: 10px;">
            <h3 style="margin: 0; color: #f0f0f0; font-size: 18px;">Subscribe</h3>
            <input type="hidden" name="nonce"/>
            <input type="email" name="email" required placeholder="E-mail" style="width: 100%; padding: 10px; border: 1px solid #666; border-radius: 4px; background: #333; color: #f0f0f0; box-sizing: border-box;"/>
            <div style="display: flex; flex-direction: column; gap: 8px;">
                <label style="margin: 0; color: #f0f0f0; display: none;">
                    <input id="78a75" type="checkbox" name="l" checked value="78a75b30-472d-4790-a5d5-7f2ed49662a4" style="accent-color: #fff;"/>
                    Weekly Roundup
                </label>
                <span style="color: #d0d0d0; display: none;">Where I share what I’ve been up to that week, including articles I’ve published, cool finds, tips and tricks, and more!</span>
                <label style="margin: 0; color: #f0f0f0; display: none;">
                    <input id="b3964" type="checkbox" name="l" checked value="b3964560-37b0-43d3-9df9-26589fd6bf8d" style="accent-color: #fff;"/>
                    New Posts
                </label>
                <span style="color: #d0d0d0; display: none;">Receive an email every time I post something new on my blog</span>
            </div>
            <input type="submit" value="Subscribe" style="width: 100%; padding: 10px; border: none; border-radius: 4px; background: #fff; color: #007bff; font-size: 14px; cursor: pointer; transition: background-color 0.3s ease, box-shadow 0.3s ease; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);"/>
        </div>
        <p style="text-align: center; margin-top: 10px; color: #d0d0d0; font-size: 10px; margin-bottom:0px;">
            No spam, no ads. Unsubscribe at any time.
        </p>
    </form>
</div>]]></content:encoded>
    </item>
    
    <item>
      <title>How to Improve Go API request performance</title>
      <link>https://4rkal.com/posts/goapi/</link>
      <pubDate>Sat, 17 Aug 2024 12:25:15 +0300</pubDate>
      
      <guid>https://4rkal.com/posts/goapi/</guid>
      <description>In this post I&amp;#39;ll show you how I improved the performance of my go based cryptocurrency exchange aggregator. By making small changes, like using goroutines, switching JSON libraries and reusing HTTP handlers.</description>
      <content:encoded><![CDATA[<h1 id="the-project">The project</h1>
<p>I recently started working on a <em>cryptocurrency exchange aggregator</em>. Basically I send out requests to a bunch of different exchanges and compare rates. This has to be made as fast as possible.
In this post, I’ll some show some tweaks that I made in order to boost my performance significantly.</p>
<p>However keep in mind that I am not an expert (especially in go) and I am just sharing my findings from my own personal project.</p>
<h1 id="improvements">Improvements</h1>
<p>These improvements come in order of biggest improvement of runtime.</p>
<h3 id="1-using-goroutines">1. Using goroutines</h3>
<p>In any Go program, goroutines are essential for speed. The biggest boost I made was by sending requests concurrently. Since I need to hit up 12 different exchanges, sending these requests at the same time dropped my runtime from around 24 seconds to just ~3.</p>
<p>Goroutines are amazing and extremely easy to use. You should include them wherever possible. But always be careful of <a href="https://go.dev/doc/articles/race_detector">Data Races</a></p>
<h3 id="2-upgrading-the-json-library">2. Upgrading the JSON Library</h3>
<p>I swapped out <code>encoding/json</code> for <code>github.com/json-iterator/go</code>.
<code>jsoniter</code> is a fast JSON processing library that works as a drop-in replacement for the standard library, so I didn’t have to change any code, just a library switch.</p>
<p><strong>Benchmark Results</strong></p>
<p>To measure the performance improvements, I ran some benchmarks comparing <code>encoding/json</code> and <code>jsoniter</code>. Here’s a summary of the results:</p>
<pre tabindex="0"><code>goos: linux
goarch: amd64
pkg: apiSpeedImprove
cpu: AMD Ryzen 5 7640U w/ Radeon 760M Graphics      
BenchmarkEncodingJSON-12          140383              7381 ns/op
BenchmarkJSONIter-12              974605              1217 ns/op
PASS
ok      apiSpeedImprove 3.216s
</code></pre><p>So, <code>jsoniter</code> is about 6 times faster than the standard library.</p>
<h3 id="3-reusing-http-handlers">3. Reusing HTTP Handlers</h3>
<p>I started reusing HTTP handlers instead of creating new ones for each request. By setting up a handler once and reusing it, I cut down on the overhead of making new handlers for each request.</p>
<p><strong>Benchmark Results</strong></p>
<p>Here are the results of the benchmarks comparing reused handlers versus creating new handlers for each request:</p>
<pre tabindex="0"><code>goos: linux
goarch: amd64
pkg: apiSpeedImprove/httpReuse
cpu: AMD Ryzen 5 7640U w/ Radeon 760M Graphics      
BenchmarkNewHttpClientEachRequest-12                3360            300058 ns/op
BenchmarkReuseHttpClient-12                         6470            175472 ns/op
PASS
ok      apiSpeedImprove/httpReuse       4.010s
</code></pre><p>Reusing HTTP handlers gave a solid performance boost compared to making a new handler for each request.</p>
<h1 id="conclusion">Conclusion</h1>
<p>With these tweaks I managed to cut the time it took to gather all the info from 24 seconds initially to about 2 seconds. Pretty solid improvement!</p>
<p>If you are interested the code for my benchmarks, it is available <a href="https://git.4rkal.com/4rkal/goapiperf">here</a></p>
<p><strong>If you enjoyed this post and want to support my work, you can <a href="https://4rkal.com/donate">donate here</a>.</strong></p>
<div style="text-align: left; margin: 0 auto;">
    <form method="post" action="https://newsletter.4rkal.com/subscription/form" style="background: #2c2c2c; color: #f0f0f0; border-radius: 8px; padding: 15px; max-width: 500px; box-shadow: 0 3px 6px rgba(0, 0, 0, 0.2); font-family: Arial, sans-serif;">
        <div style="display: flex; flex-direction: column; gap: 10px;">
            <h3 style="margin: 0; color: #f0f0f0; font-size: 18px;">Subscribe</h3>
            <input type="hidden" name="nonce"/>
            <input type="email" name="email" required placeholder="E-mail" style="width: 100%; padding: 10px; border: 1px solid #666; border-radius: 4px; background: #333; color: #f0f0f0; box-sizing: border-box;"/>
            <div style="display: flex; flex-direction: column; gap: 8px;">
                <label style="margin: 0; color: #f0f0f0; display: none;">
                    <input id="78a75" type="checkbox" name="l" checked value="78a75b30-472d-4790-a5d5-7f2ed49662a4" style="accent-color: #fff;"/>
                    Weekly Roundup
                </label>
                <span style="color: #d0d0d0; display: none;">Where I share what I’ve been up to that week, including articles I’ve published, cool finds, tips and tricks, and more!</span>
                <label style="margin: 0; color: #f0f0f0; display: none;">
                    <input id="b3964" type="checkbox" name="l" checked value="b3964560-37b0-43d3-9df9-26589fd6bf8d" style="accent-color: #fff;"/>
                    New Posts
                </label>
                <span style="color: #d0d0d0; display: none;">Receive an email every time I post something new on my blog</span>
            </div>
            <input type="submit" value="Subscribe" style="width: 100%; padding: 10px; border: none; border-radius: 4px; background: #fff; color: #007bff; font-size: 14px; cursor: pointer; transition: background-color 0.3s ease, box-shadow 0.3s ease; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);"/>
        </div>
        <p style="text-align: center; margin-top: 10px; color: #d0d0d0; font-size: 10px; margin-bottom:0px;">
            No spam, no ads. Unsubscribe at any time.
        </p>
    </form>
</div>]]></content:encoded>
    </item>
    
    <item>
      <title>My Obsidian &#43; Hugo blogging setup</title>
      <link>https://4rkal.com/posts/obsidianhugo/</link>
      <pubDate>Tue, 13 Aug 2024 17:15:57 +0300</pubDate>
      
      <guid>https://4rkal.com/posts/obsidianhugo/</guid>
      <description>In this post I go through how I have setup my Obsidian and Hugo blogging workflow. I use a single vault and auto publish my articles with hotkeys.</description>
      <content:encoded><![CDATA[<p>If you clicked on this article you probably know what Obsidian and Hugo are but if you don&rsquo;t here&rsquo;s a quick explanation:</p>
<h3 id="obsidian">Obsidian</h3>
<p><a href="https://obsidian.md">Obsidian</a> is a feature packed markdown editor. But it&rsquo;s not just a markdown editor. It&rsquo;s a way to manage knowledge. It&rsquo;s great for organizing your thoughts in a flexible, non-linear way.</p>
<p>Obsidian works on all platforms. So you can write articles from basically any platform.</p>
<p>I have been taking all of my notes in it for a couple of months now and it&rsquo;s amazing!</p>
<h3 id="hugo">Hugo</h3>
<p><a href="https://gohugo.io">Hugo</a> is an ultra fast static website generator made in golang. I have been using hugo for my blog for almost 2 years now. I recently switched the theme of my my blog. Read more about the change <a href="https://4rkal.eu.org/posts/newlook?utm_source=internal&amp;utm_campaign=obsidianhugo">New Look, new start</a>.</p>
<h3 id="using-obsidian-with-hugo">Using Obsidian with Hugo</h3>
<p>In this guide, I’ll show you how to get Obsidian and Hugo working together. I won’t cover the initial setup of either tool, but I’ll explain how to integrate them for a smooth blogging workflow.</p>
<p>If you need help setting up Hugo, check out my guide: <a href="https://4rkal.com/posts/thisblog?utm_source=internal&amp;utm_campaign=obsidianhugo">How I Setup This Blog for Free (Domain, Hosting, SSL) Complete Guide</a>. And if you’re new to Obsidian, check out this <a href="https://help.obsidian.md/Getting+started/Download+and+install+Obsidian">Getting Started Guide</a> .</p>
<h3 id="goals-for-using-hugo-with-obsidian">Goals for Using Hugo with Obsidian</h3>
<p>My goals for the setup are:</p>
<ol>
<li>Using a single <a href="https://help.obsidian.md/Getting+started/Create+a+vault">obsidian vault</a></li>
<li>Have an easy to use <a href="https://help.obsidian.md/Plugins/Templates">obsidian template</a> that I can use for my blog posts.</li>
<li>Keep my personal vault folders private.</li>
<li>Auto publish using obsidian hotkeys.</li>
<li>Have all markdown files in a <a href="https://github.com/4rkal/blog/">public github repository</a>, so that people can propose changes</li>
</ol>
<h2 id="existing-setup">Existing setup</h2>
<p>Here’s how my current workflow with Obsidian and Hugo looks:</p>
<ol>
<li>I write and edit articles directly in Obsidian, within the <code>content</code> folder of my Hugo project.</li>
<li>I run the Hugo command to generate the static site.</li>
<li>I push the changes to GitHub.</li>
<li><a href="https://render.com">Render.com</a> automatically picks up the changes and deploys the updated site.</li>
</ol>
<h2 id="journey">Journey</h2>
<p><em>If you want to skip the journey part you can go straight to <a href="#the-sauce">The Sauce</a></em></p>
<p>I will be going through a couple of mistakes that I made while setting this up.</p>
<h3 id="mistake-1">Mistake #1</h3>
<p>The first idea that I had was to create a simple symlink (I use linux btw) that would link the two folders together.</p>
<p>Basically I have two folders:</p>
<pre tabindex="0"><code>blog/
vault/
</code></pre><p>The blog folder contains all the blog folders and the vault is my personal vault.</p>
<p>The symlink would link these folders</p>
<pre tabindex="0"><code>blog/content
vault/Blog
</code></pre><p>However <strong>the problem</strong> with a symlink is that the folder content is not visible in my git repo.
This means that people can not propose changes to any of my articles</p>
<h3 id="mistake-2">Mistake #2</h3>
<p>I wanted to have my folders synced. I tried writing a couple of bash scripts that automatically synced the two folders using a cronjob.
However having that constantly running the background is a waste of resources when I am not writing.
Simply running the scripts via cli is just not that smooth.</p>
<h2 id="the-sauce">The Sauce</h2>
<p>Basically the way that I have set this up is I have two folders:</p>
<pre tabindex="0"><code>blog
vault
</code></pre><p>The blog folder contains all the necessary hugo files and also has a sub directory called content that houses all of the markdown blog files.</p>
<p>I created a new folder inside of my vault called Blog</p>
<pre tabindex="0"><code>blog/content
vault/Blog
</code></pre><p>After that I copied over all of my files from the content directory to the Blog.</p>
<p><em>I then started writing this very article</em></p>
<h2 id="obsidian-templates">Obsidian templates</h2>
<p>I needed some way to setup a simple obsidian template to contains all of the required hugo front matter.</p>
<p>That is quite easy.</p>
<p>Read about how to setup templates <a href="https://help.obsidian.md/Plugins/Templates">Templates - obsidian.md</a></p>
<p>I created a file called <code>Blog Post</code> in my templates folder</p>
<p>My <code>Blog Post</code> template contains the following:</p>
<pre tabindex="0"><code>---
title: &#34;{{Title}}&#34;
description: 
date: &#34;{{date:YYYY-MM-DD}}T{{time:HH:mm:ss}}+00:00&#34;
draft: true
---


**If you enjoyed this article consider [supporting me](https://4rkal.com/donate)**
</code></pre><p>I have all the required front matter including a title, description and a date in the format that hugo asks.</p>
<p>I also added a small donation text that I include at the bottom of every article.</p>
<p>This means that I can automatically insert this template into any file and start writing!</p>
<h2 id="folder-syncing">Folder Syncing</h2>
<p>Now I want all of my files in my vault/Blog directory to be copied over to the blog/content. Essentially connecting Hugo and Obsidian.</p>
<p>Thank&rsquo;s to a helpful discord user I found the <a href="https://github.com/Taitava/obsidian-shellcommands">obsidian-shellcommands</a> plugin.</p>
<p><strong>NOTE:</strong> this plugin does not currently work very well with the flatpak version of obsidian (since flatpak isolates the environment) . Using another alternative (.deb or appimage) seems to work.</p>
<p>It allows you to run shell commands in the background with a hotkey.</p>
<p>The steps to set this up are the following:</p>
<ol>
<li><a href="https://obsidian.md/plugins?search=shell%20commands">Install the plugin</a></li>
<li>Enable the plugin</li>
<li>Go to the plugin options</li>
<li>Click on <code>New shell command</code></li>
<li>Now you will need to enter a shell command to copy the files from the one folder to the other.</li>
</ol>
<p>On Linux/MacOS that is:</p>
<p><code>cp -a ~/folder1/. ~/folder2/</code></p>
<p>in my case that is <code>cp -a ~/Documents/vault/Blog/. ~/Documents/blog/content/</code></p>
<p>On windows it most probably is:</p>
<p><code>robocopy &quot;%USERPROFILE%\folder1&quot; &quot;%USERPROFILE%\folder2&quot; /E /COPYALL</code></p>
<p>After that we need to set a hotkey that will run the command</p>
<p>Click on the (+) icon to go to the hotkey settings and assign a hotkey</p>
<p>My hotkey is <code>CTR + 0</code>, simply because that was available.</p>
<p>Now every time that I run the hotkey it copies over all of my files to the hugo folder ready to be published</p>
<h2 id="auto-publishing-scripts">Auto publishing scripts</h2>
<p>I also want to be able to automatically publish my articles. But I want it to happen when hitting a hotkey.</p>
<p>I wrote a small script that does exactly that:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span><span style="color:#75715e">#!/bin/bash
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>cd ~/Documents/blog
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>hugo
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>git add .
</span></span><span style="display:flex;"><span>git commit -m <span style="color:#e6db74">&#34;new&#34;</span>
</span></span><span style="display:flex;"><span>git push -u origin main
</span></span></code></pre></div><p>This script will build my website, commit and push to my github repo, where it is picked up and published. Read <a href="https://4rkal.eu.org/posts/thisblog?utm_source=internal&amp;utm_campaign=obsidianhugo">How I setup this blog for free (domain, hosting, ssl) Complete Guide</a> to learn how to setup your own blog for free.</p>
<p>Don&rsquo;t forget to make the script executable by running</p>
<p><code>chmod +x ./YOURSCRIPT.sh</code></p>
<p>Then create a new shell command for the shellcommand plugin (as we did before) and enter the path to your script.</p>
<p>In my case that is:</p>
<p><code>~/Documents/blog/push.sh</code></p>
<p>Then enter a hotkey and you&rsquo;re done!</p>
<h2 id="conclusion">Conclusion</h2>
<p>I can now simply open my obsidian vault, create a new file, insert my template and have all the info automatically entered.</p>
<p>I then write my article inside of obsidian</p>
<p>Run my hotkey and copy all the files into the hugo directory</p>
<p>Hit another key and my blog is published!</p>
<p><strong>If you enjoyed this article consider <a href="https://4rkal.eu.org/donate">supporting me</a></strong></p>
<div style="text-align: left; margin: 0 auto;">
    <form method="post" action="https://newsletter.4rkal.com/subscription/form" style="background: #2c2c2c; color: #f0f0f0; border-radius: 8px; padding: 15px; max-width: 500px; box-shadow: 0 3px 6px rgba(0, 0, 0, 0.2); font-family: Arial, sans-serif;">
        <div style="display: flex; flex-direction: column; gap: 10px;">
            <h3 style="margin: 0; color: #f0f0f0; font-size: 18px;">Subscribe</h3>
            <input type="hidden" name="nonce"/>
            <input type="email" name="email" required placeholder="E-mail" style="width: 100%; padding: 10px; border: 1px solid #666; border-radius: 4px; background: #333; color: #f0f0f0; box-sizing: border-box;"/>
            <div style="display: flex; flex-direction: column; gap: 8px;">
                <label style="margin: 0; color: #f0f0f0; display: none;">
                    <input id="78a75" type="checkbox" name="l" checked value="78a75b30-472d-4790-a5d5-7f2ed49662a4" style="accent-color: #fff;"/>
                    Weekly Roundup
                </label>
                <span style="color: #d0d0d0; display: none;">Where I share what I’ve been up to that week, including articles I’ve published, cool finds, tips and tricks, and more!</span>
                <label style="margin: 0; color: #f0f0f0; display: none;">
                    <input id="b3964" type="checkbox" name="l" checked value="b3964560-37b0-43d3-9df9-26589fd6bf8d" style="accent-color: #fff;"/>
                    New Posts
                </label>
                <span style="color: #d0d0d0; display: none;">Receive an email every time I post something new on my blog</span>
            </div>
            <input type="submit" value="Subscribe" style="width: 100%; padding: 10px; border: none; border-radius: 4px; background: #fff; color: #007bff; font-size: 14px; cursor: pointer; transition: background-color 0.3s ease, box-shadow 0.3s ease; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);"/>
        </div>
        <p style="text-align: center; margin-top: 10px; color: #d0d0d0; font-size: 10px; margin-bottom:0px;">
            No spam, no ads. Unsubscribe at any time.
        </p>
    </form>
</div>]]></content:encoded>
    </item>
    
    <item>
      <title>New look, new start</title>
      <link>https://4rkal.com/posts/newlook/</link>
      <pubDate>Sun, 11 Aug 2024 16:17:31 +0300</pubDate>
      
      <guid>https://4rkal.com/posts/newlook/</guid>
      <description>I recently switched from the hugo LoveIt theme to PaperModX . Why the switch? The LoveIt theme hasn&amp;rsquo;t been updated in 2+ years. PaperModX has a more modern look LoveIt doesn&amp;rsquo;t work that well with obsidian. The overall switch went pretty smoothly. You can see the changes I made in this commit.
For anyone wondering this what the website used to look like
More articles to come! The theme wasn&amp;rsquo;t the only change that I made.</description>
      <content:encoded><![CDATA[<h4 id="i-recently-switched-from-the-hugo-loveithttpsgithubcomdillonzqloveit-theme-to-papermodxhttpsgithubcomreorxhugo-papermodx-">I recently switched from the hugo <a href="https://github.com/dillonzq/LoveIt">LoveIt</a> theme to <a href="https://github.com/reorx/hugo-PaperModX/">PaperModX</a> .</h4>
<h2 id="why-the-switch">Why the switch?</h2>
<ul>
<li>The LoveIt theme hasn&rsquo;t been updated in 2+ years.</li>
<li>PaperModX has a more modern look</li>
<li>LoveIt doesn&rsquo;t work that well with <a href="https://obsidian.md">obsidian</a>.</li>
</ul>
<p>The overall switch went pretty smoothly. You can see the changes I made in this <a href="https://github.com/4rkal/blog/commit/15e21c2f357f8d3a4e6ba11896d5369ec3ccb315">commit</a>.</p>
<p>For anyone wondering this what <a href="https://web.archive.org/web/20240615224820/https://4rkal.eu.org/">the website used to look like</a></p>
<h2 id="more-articles-to-come">More articles to come!</h2>
<p>The theme wasn&rsquo;t the only change that I made. After a pretty long break, I have decided to start publishing articles regularly again!</p>
<p>I will also start to update any outdated articles</p>
<p>So, stay tuned - There&rsquo;s more content to come!</p>
<p>Subscribe to my RSS feed to stay up to date <a href="../../index.xml">here</a></p>
<p>There&rsquo;s also going to be a mailing list soon™️</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Ultimate Monero ColdStorage Guide (Feather X Anonero)</title>
      <link>https://4rkal.com/posts/feathernero/</link>
      <pubDate>Thu, 14 Dec 2023 21:00:30 +0300</pubDate>
      
      <guid>https://4rkal.com/posts/feathernero/</guid>
      <description>In this comprehensive guide, I will walk you through the process of easily setting up Monero cold storage using an old computer and your smartphone, using animated QR codes. No USB needed!</description>
      <content:encoded><![CDATA[<p>In this comprehensive guide, I will walk you through the process of easily setting up Monero cold storage using an old computer and your smartphone, using animated QR codes. No USB needed!</p>
<h2 id="requirements">Requirements</h2>
<ol>
<li>An old laptop/computer with a webcam (to be kept offline). Called <strong>offline</strong> or <strong>cold</strong> computer.</li>
<li>An android smartphone.</li>
<li>Your main computer</li>
</ol>
<h2 id="required-reads">Required reads</h2>
<p>Before starting this article you <strong>must</strong> read:</p>
<ol>
<li><a href="https://malvarma.org/before_we_start/what_things_mean.html">Key concepts</a></li>
<li><a href="https://monero.stackexchange.com/questions/2426/offline-transaction-signing-what-are-the-details">Monero offline transaction signing details</a></li>
</ol>
<h2 id="cold-computer-setup">Cold computer setup</h2>
<p>Your offline computer/laptop will be signing all of the transactions. It should always be kept offline i.e cold. It can not be used for other tasks.</p>
<p>I highly recommend that you use a linux distribution and NOT windows for cold storage. Linux is free and opensource. I highly recommend pepermintOS or MX linux as they are lightweight and pretty easy to setup.</p>
<p>I will not be guiding you on how to install [[linux]]. But here are some resourses to help you get started:</p>
<ul>
<li>
<p><a href="https://peppermintos.com/guide/downloading/">Installing PeperMintOS</a> &lt;&ndash;  somewhat 32 bit support, lightweight</p>
</li>
<li>
<p><a href="https://linuxmint-installation-guide.readthedocs.io/en/latest/install.html">Installing LinuxMint</a> &lt;&ndash; better for newer computers</p>
</li>
<li>
<p><a href="https://www.makeuseof.com/how-to-install-mx-linux/">Installing MX Linux</a> &lt;&ndash; 32 bit support, pretty lightweight</p>
</li>
</ul>
<h3 id="downloading--installing-necessary-software">Downloading &amp; Installing necessary software</h3>
<p>The first thing that we will need to do is download the required software.</p>
<p>We will need <a href="https://featherwallet.org">featherwallet</a></p>
<p>and that&rsquo;s about it.</p>
<h3 id="taking-the-device-offline">Taking the device offline</h3>
<p>It is highly recommended that you disable the wifi and bluetooth modules on your cold computer. This can be by physically detaching the wifi and bluetooth module or disabling it in the bios. The later is less secure if you&rsquo;re going full on <a href="https://i.imgur.com/p5h6STu.jpeg">tinfoilhat</a>.</p>
<p>Here&rsquo;s a guide on how to physically disable them from <a href="https://malvarma.org/cold_wallet/prepare_the_hardware.html">malvarma.org</a></p>
<p>A guide on how to disable it via BIOS can be found by searching your specific hardware on your <a href="https://searx.org/">favorite search engine</a>.</p>
<h3 id="computer-cold-wallet-setup">Computer cold wallet setup</h3>
<p>Now we will have to setup our wallet. Ensure that your device is completely <strong>offline</strong> and then open featherwallet.</p>
<ol>
<li>Click on <code>Create a new wallet</code>. Then click on <code>Next</code>. You will be presented with your seedphrase. <strong>Write it down!! on physical paper</strong>.</li>
<li>Select a name for your wallet and click <code>Next</code></li>
<li>Select a wallet password and click <code>Next</code>.</li>
<li>Now that the wallet is open in the bottom right corner there will be a dot. Click on it and select the offline box and then click <code>Disable all network connections (offline)</code></li>
</ol>
<h2 id="phone">Phone</h2>
<p>We will now be installing the anonero software. We will be using NERO from the ANON/NERO suite.</p>
<ol>
<li>
<p>Download and install fdroid. Apk can be downloaded from the <a href="https://fdroid.org">F-Droid website</a></p>
</li>
<li>
<p>Download and install orbot. Can be installed from google play store <a href="https://play.google.com/store/apps/details?id=org.torproject.android">here</a></p>
</li>
<li>
<p>Open orbot. Select <code>VPN Mode</code>, click on the onion logo that says <code>start</code></p>
</li>
<li>
<p>Open fdroid and in the settings scroll down and enable <code>Use Tor</code> option</p>
</li>
<li>
<p>Again in the settings that click on the repositories section and add the following:</p>
<p><code>http://anonero5wmhraxqsvzq2ncgptq6gq45qoto6fnkfwughfl4gbt44swad.onion/fdroid/repo?fingerprint=C5705FF724538F6925B6093517F53C6C6BB6CF82518ED40EB4B8CBBB87DC0D1D</code></p>
<p>Source: <a href="https://anonero.io">anonero.io</a></p>
</li>
<li>
<p>Click on  latest and then search for NERO</p>
</li>
<li>
<p>Click on install
That&rsquo;s it ; )</p>
</li>
</ol>
<h3 id="updating-nero">Updating NERO</h3>
<p>If you want to update NERO you will have to turn orbot on, open fdroid and refresh the updates tab</p>
<h3 id="nero-setup">NERO setup</h3>
<p>To set up NERO, follow these steps:</p>
<ol>
<li>
<p>Once NERO is successfully installed, open the application.</p>
</li>
<li>
<p>Click on <code>RESTORE WALLET</code> option and select <code>RESTORE FROM KEYS</code></p>
</li>
<li>
<p>Proceed to establish a node connection. You can find a lot of Monero nodes <a href="https://monero.fail">here</a>.</p>
<p>Random clearnet node:</p>
<ul>
<li><code>http://xmr.monopolymoney.eu:18089</code></li>
</ul>
<p>Random Tor node:</p>
<ul>
<li><code>http://xmrsalty4hg7lq5ci4kzc2xxcic57azapolbunmkiypnmr3wp7uvqnyd.onion:18089</code></li>
</ul>
</li>
</ol>
<p>Copy the node address into the node field. By default you shouldn&rsquo;t need a username or password</p>
<p>By default tor connectivity is enabled in NERO. You can disable it by going into the proxy settings and deleting everything.</p>
<ol start="4">
<li>Click on <code>Connect</code>. It will try connecting. If it fails check your internet connection or try another node</li>
</ol>
<h3 id="importing-view-only-wallet">Importing view-only wallet</h3>
<p>Now you will have to import your wallets <code>Primary address</code> , <code>Secret-View key</code> and <code>Restore height</code> into NERO. To import that info to nero:</p>
<p>On your offline computer open featherwallet and navigate to <code>Wallet</code> then <code>View-Only</code>. Enter your password and click on the <code>Show QR</code></p>
<p>Now in nero in the View only keys screen click on the square icon to scan the qr. Then scan the qr displayed by featherwallet. All the info should be filled in after scanning the qr code. Click <code>Next</code>.</p>
<p>Set a pin. After that your wallet should be imported into NERO.</p>
<h2 id="receiving-monero">Receiving monero</h2>
<p>To receive monero you can follow these steps</p>
<ol>
<li>Open NERO and enter your pin</li>
<li>Click on the receive tab (the one with the qr code icon)</li>
<li>Long hold on the address</li>
<li>Select one of the SubAddreses and click on the copy icon.</li>
<li>Transfer any amount of monero to that address.</li>
</ol>
<p>After 10 confirmations it should be spendable. Proceed to the next step.</p>
<h2 id="signing-transactions">Signing transactions</h2>
<p>Signing/Broadcasting transactions is easy with the NERO/Feather duo. No usbs are needed it is all done via animated QR codes.</p>
<p>To sign/broadcast a transaction follow these steps
On your phone:</p>
<ol>
<li>Open NERO and enter your pin</li>
<li>In the send tab enter the desired address and amount</li>
<li>Click on continue, you should now see an animated QR code.</li>
</ol>
<p>On your cold computer</p>
<ol>
<li>Open feather and enter your password</li>
<li>Click on <code>Tools</code> &gt; <code>Offline transaction signing</code>. You should now see your camera</li>
<li>Show your phone to the computers camera so that it can read the QR code.</li>
<li>After it has been picked up by your computer you should see a QR code displayed on your computers screen</li>
</ol>
<p>In NERO.</p>
<ol>
<li>Click on <code>SCAN KEY IMAGES</code></li>
<li>Scan the QR code from the computer&rsquo;s screen</li>
<li>Once it has been picked up you can see the <code>Address</code>, <code>Amount</code>, <code>Fee</code> and <code>Total</code>. Click on <code>confirm</code></li>
<li>You should now see the unsigned TX screen.</li>
</ol>
<p>In feather click on <code>Next</code>. Then scan the QR code displayed by NERO to your computer. Once the bar is at 100%, you should again see the <code>Address</code>, <code>Amount</code>, <code>Fee</code> and <code>Total</code>. If your ok with that click on SIGN.</p>
<p>In NERO</p>
<ol>
<li>Click on <code>SCAN SIGNED TX</code></li>
<li>Scan the QR displayed by feather wallet.</li>
<li>Click on <code>Yes</code>, once asked whether or not to broadcast transaction</li>
</ol>
<p>You have now sent the transaction.</p>
<p><strong>if this article helped you out consider <a href="https://4rkal.com/donate">supporting me</a></strong></p>
<div style="text-align: left; margin: 0 auto;">
    <form method="post" action="https://newsletter.4rkal.com/subscription/form" style="background: #2c2c2c; color: #f0f0f0; border-radius: 8px; padding: 15px; max-width: 500px; box-shadow: 0 3px 6px rgba(0, 0, 0, 0.2); font-family: Arial, sans-serif;">
        <div style="display: flex; flex-direction: column; gap: 10px;">
            <h3 style="margin: 0; color: #f0f0f0; font-size: 18px;">Subscribe</h3>
            <input type="hidden" name="nonce"/>
            <input type="email" name="email" required placeholder="E-mail" style="width: 100%; padding: 10px; border: 1px solid #666; border-radius: 4px; background: #333; color: #f0f0f0; box-sizing: border-box;"/>
            <div style="display: flex; flex-direction: column; gap: 8px;">
                <label style="margin: 0; color: #f0f0f0; display: none;">
                    <input id="78a75" type="checkbox" name="l" checked value="78a75b30-472d-4790-a5d5-7f2ed49662a4" style="accent-color: #fff;"/>
                    Weekly Roundup
                </label>
                <span style="color: #d0d0d0; display: none;">Where I share what I’ve been up to that week, including articles I’ve published, cool finds, tips and tricks, and more!</span>
                <label style="margin: 0; color: #f0f0f0; display: none;">
                    <input id="b3964" type="checkbox" name="l" checked value="b3964560-37b0-43d3-9df9-26589fd6bf8d" style="accent-color: #fff;"/>
                    New Posts
                </label>
                <span style="color: #d0d0d0; display: none;">Receive an email every time I post something new on my blog</span>
            </div>
            <input type="submit" value="Subscribe" style="width: 100%; padding: 10px; border: none; border-radius: 4px; background: #fff; color: #007bff; font-size: 14px; cursor: pointer; transition: background-color 0.3s ease, box-shadow 0.3s ease; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);"/>
        </div>
        <p style="text-align: center; margin-top: 10px; color: #d0d0d0; font-size: 10px; margin-bottom:0px;">
            No spam, no ads. Unsubscribe at any time.
        </p>
    </form>
</div>
]]></content:encoded>
    </item>
    
    <item>
      <title>Easy monero cold storage</title>
      <link>https://4rkal.com/posts/coldstorage/</link>
      <pubDate>Tue, 07 Nov 2023 18:03:15 +0200</pubDate>
      
      <guid>https://4rkal.com/posts/coldstorage/</guid>
      <description>In this article I will show you how to &amp;ldquo;easily&amp;rdquo; generate a live archlinux usb with the monero gui pre-installed.
Requirements An archlinux install A usb Setup In this guide I will show you how to build a custom archlinux iso with monerogui installed. I will not be providing any pre-built images.
The first thing you will have to do is install archuseriso. You can install it from the aur using this command:</description>
      <content:encoded><![CDATA[<p>In this article I will show you how to &ldquo;easily&rdquo; generate a live archlinux usb with the monero gui pre-installed.</p>
<h2 id="requirements">Requirements</h2>
<ol>
<li>An archlinux install</li>
<li>A usb</li>
</ol>
<h2 id="setup">Setup</h2>
<p>In this guide I will show you how to build a custom archlinux iso with monerogui installed. I will not be providing any pre-built images.</p>
<p>The first thing you will have to do is install <a href="https://github.com/laurent85v/archuseriso">archuseriso</a>. You can install it from the aur using this command:</p>
<p><code>yay -S archuseriso</code></p>
<p>Now open a terminal and navigate to any directory. Then run the following command:</p>
<p><code>sudo aui-mkiso -m 'img' --add-pkg=monero-gui xfce --verbose</code></p>
<p>This will build a new gpt image with persistense, add the monero-gui package and use xfce as the default desktop. The &ndash;verbose flag is optional.</p>
<p>After that is finished building you can use your favourite image writter to write the image. I will be using dd
<code>sudo dd if=out/aui-xfce*.img of=/dev/CHANGEME</code></p>
<p>You will have to write that to your usb, so in /dev/CHANGEME just put your usb. You can find it by running <code>lsblk</code>
<strong>Don&rsquo;t be stupid</strong>
If you enter the wrong device this could lead to data loss. Be careful!</p>
<p>After the image is written you will have to boot to your usb.</p>
<p>First however it is recommended that you disconnect any ethernet/other cables plugged in so that it is trully offline.</p>
<p>You can also <a href="https://www.google.com/search?q=disable+wifi+and+bluetooth+bios">disable wifi and bluetooth from the bios</a> . &ldquo;Advanced&rdquo; users only don&rsquo;t be retarded</p>
<p>Now only plug in your usb drive and reboot into the usb. You will generaly have to press either F8,F9,F10,F11 upon booting and then select your usb.</p>
<p>Now you have two options</p>
<ol>
<li>Boot into persistent.</li>
<li>Boot into memory.</li>
</ol>
<p>When booting into persistent your files will be saved. This however does also involve your wallet file.</p>
<p>For the more secure option you can select boot into memory. This will delete all the traces of the wallet after reboot. You will have to write the seed down and manually enter it upon every boot if you want to authorize transactions.</p>
<p>I will boot into persistent since I will use a strong password and will keep the usb in a safe place. If you want to be extra paranoid use the second option.</p>
<p>After the os has fully booted you will have to click on the <code>Applications</code> icon &gt; internet &gt; <code>Monero GUI</code>. Alternatively open a terminal and type <code>monero-wallet-gui</code></p>
<p>You will now be greated by the monero gui setup guide.</p>
<p>Select your language etc.</p>
<p>Select advanced &gt; Click on <code>Create a new wallet</code> . You can select whatever you want in the wallet name and location &gt; Click next.</p>
<p>Now you will be prompted with your recovery phrase. Write it down on PHYSICAL PAPER and keep it in a safe place. Also note the height and or creation date.</p>
<p>Write it down!
If you don&rsquo;t write down your seed and keep it in a secure place you will lose access to your monero!</p>
<p>Then click next. Now select a strong password. Alteast 12 chars!. Remeber it!</p>
<p>Click next. Then click on <code>Connect to a remote node</code> but don&rsquo;t add one, we don&rsquo;t need it.</p>
<p>Then click on create wallet.</p>
<p>After you have opened your wallet, click on <code>settings</code> and then <code>Create view-only wallet</code>. Then click on ok. Logout of your wallet. Click on <code>Open wallet from file</code> and select the new file called WALLETNAME_viewonly.</p>
<p>Once you have logged into your view only wallet click on settings again and select <code>Show seeds and keys</code>. Scroll down to the botton and import your view only wallet via qr to your mobile wallet. Here are some guides for every wallet:</p>
<ul>
<li><a href="https://guides.cakewallet.com/docs/basic-features/restore-wallet-from-qr-code/">Cake wallet</a></li>
<li><a href="https://www.monerujo.io/resources/monerujo_manual.html">Monerujo</a></li>
</ul>
<h2 id="what-have-we-acomplished">What have we acomplished?</h2>
<p>You now have a cold wallet for offline signing on your usb and a view-only wallet on your phone. Basicly you can view all incoming transactions on your phone but can&rsquo;t spend them there. Only your computer booted into the usb can sign them.</p>
<h2 id="signing-transactions">Signing transactions</h2>
<p>I won&rsquo;t cover doing this in this article. But you can find out more about how to send transactions from cold storage <a href="https://monerodocs.org/cold-storage/offline-transaction-signing/">here</a></p>
<div style="text-align: left; margin: 0 auto;">
    <form method="post" action="https://newsletter.4rkal.com/subscription/form" style="background: #2c2c2c; color: #f0f0f0; border-radius: 8px; padding: 15px; max-width: 500px; box-shadow: 0 3px 6px rgba(0, 0, 0, 0.2); font-family: Arial, sans-serif;">
        <div style="display: flex; flex-direction: column; gap: 10px;">
            <h3 style="margin: 0; color: #f0f0f0; font-size: 18px;">Subscribe</h3>
            <input type="hidden" name="nonce"/>
            <input type="email" name="email" required placeholder="E-mail" style="width: 100%; padding: 10px; border: 1px solid #666; border-radius: 4px; background: #333; color: #f0f0f0; box-sizing: border-box;"/>
            <div style="display: flex; flex-direction: column; gap: 8px;">
                <label style="margin: 0; color: #f0f0f0; display: none;">
                    <input id="78a75" type="checkbox" name="l" checked value="78a75b30-472d-4790-a5d5-7f2ed49662a4" style="accent-color: #fff;"/>
                    Weekly Roundup
                </label>
                <span style="color: #d0d0d0; display: none;">Where I share what I’ve been up to that week, including articles I’ve published, cool finds, tips and tricks, and more!</span>
                <label style="margin: 0; color: #f0f0f0; display: none;">
                    <input id="b3964" type="checkbox" name="l" checked value="b3964560-37b0-43d3-9df9-26589fd6bf8d" style="accent-color: #fff;"/>
                    New Posts
                </label>
                <span style="color: #d0d0d0; display: none;">Receive an email every time I post something new on my blog</span>
            </div>
            <input type="submit" value="Subscribe" style="width: 100%; padding: 10px; border: none; border-radius: 4px; background: #fff; color: #007bff; font-size: 14px; cursor: pointer; transition: background-color 0.3s ease, box-shadow 0.3s ease; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);"/>
        </div>
        <p style="text-align: center; margin-top: 10px; color: #d0d0d0; font-size: 10px; margin-bottom:0px;">
            No spam, no ads. Unsubscribe at any time.
        </p>
    </form>
</div>]]></content:encoded>
    </item>
    
    <item>
      <title>SSH Remote Access NO Port-Forwarding NO Cloudflare</title>
      <link>https://4rkal.com/posts/onionssh/</link>
      <pubDate>Wed, 04 Oct 2023 19:17:04 +0300</pubDate>
      
      <guid>https://4rkal.com/posts/onionssh/</guid>
      <description>In this article I will show you how I securely connect to my remote machines without having to configure port forwarding.
Requirements: A computer &amp;ldquo;server&amp;rdquo; (running linux) A internet connection Another computer to connect to your server (running linux) Why? If you want to access your server without portforwarding in a extremely secure fashion you will want to follow this tutorial. You will be connecting to the server via tor which will make it harder for anyone to find the url of the server and ill show you how to setup keybased auth for even more security!</description>
      <content:encoded><![CDATA[<p>In this article I will show you how I securely connect to my remote machines without having to configure port forwarding.</p>
<h2 id="requirements">Requirements:</h2>
<ol>
<li>A computer &ldquo;server&rdquo; (running linux)</li>
<li>A internet connection</li>
<li>Another computer to connect to your server (running linux)</li>
</ol>
<h2 id="why">Why?</h2>
<p>If you want to access your server without portforwarding in a extremely secure fashion you will want to follow this tutorial. You will be connecting to the server via tor which will make it harder for anyone to find the url of the server and ill show you how to setup keybased auth for even more security!</p>
<h2 id="setup">Setup</h2>
<p>You will have to install the following packages (ssh, tor)</p>
<p>On debian</p>
<p><code>sudo apt install openssh-client</code></p>
<p>On arch</p>
<p><code>sudo pacman -S openssh</code></p>
<p>After that enable the ssh service</p>
<p>Debian:</p>
<p><code>sudo systemctl enable ssh</code></p>
<p>Arch:</p>
<p><code>sudo systemctl enable sshd</code></p>
<p>If you want to check if this worked just use another computer and run</p>
<p><code>ssh USER@IP</code></p>
<p>for example I run</p>
<p><code>ssh arkal@192.168.1.69</code></p>
<p>After this you can enable KeyBased authentication for more security</p>
<p>Here is my article how to enable that :</p>
<p><a href="https://4rkal.eu.org/posts/sssh/">Enable keybased authentication</a></p>
<p>Now we need to install tor:</p>
<p>On debian</p>
<p><code>sudo apt install tor</code></p>
<p>On arch</p>
<p><code>sudo pacman -S tor</code></p>
<p>Then start and enable the tor service with</p>
<p><code>sudo systemctl start tor &amp;&amp; sudo systemctl enable tor</code></p>
<p>After you have done that you want to edit your torrc file. Using your favorite text editor</p>
<p><code>sudo vim /etc/tor/torrc</code></p>
<p>Now you will want to navigate to the part that says HiddenService. And paste the following</p>
<pre tabindex="0"><code>HiddenServiceDir /var/lib/tor/ssh/
HiddenServicePort 22 127.0.0.1:22
</code></pre><p>Save your file and exit the editor (for nano cntrl s, cntrl x)</p>
<p>Now you want will have to restart the tor service</p>
<p><code>sudo systemctl restart tor</code></p>
<p>After that run the following:</p>
<p><code>sudo cat /var/lib/tor/ssh/hostname</code></p>
<p>You should see a string of letters and characters ending in .onion </p>
<p>Now on your other machine:</p>
<h2 id="connecting-to-the-server">Connecting to the server</h2>
<p>On your main machine you will have to do the following:</p>
<p>Have ssh, tor, and socat installed</p>
<p>After you have installed them you will have to edit the ssh config</p>
<p><code>vim .ssh/config</code></p>
<p>And paste the following</p>
<pre tabindex="0"><code>Host NAME
 Hostname URL.onion
 User USER
 Port 22
 Proxycommand socat - SOCKS4A:127.0.0.1:%h:%p,socksport=9050
</code></pre><p>You will have to change the NAME, URL and USER. The user is the user you want to connect as to your server and the url is the url you that ends in .onion from above.</p>
<p>Now save the file and exit.</p>
<p>Now edit the torrc file. Using your favorite text editor:</p>
<p><code>vim /etc/tor/torrc</code></p>
<p>Find the line that says SOCKSPort and uncomment it</p>
<p><code>SOCKSPort 9050</code></p>
<p>Restart the tor service</p>
<p><code>systemctl restart tor</code></p>
<p>To connect to the server run the following command:</p>
<p><code>ssh NAME</code></p>
<p>With NAME being the name that you gave to the server in the config file.</p>
<p><strong>If this article helped you out consider <a href="https://4rkal.eu.org/donate">supporting me</a></strong></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>How I setup this blog for free (domain, hosting, ssl) Complete Guide</title>
      <link>https://4rkal.com/posts/thisblog/</link>
      <pubDate>Thu, 23 Mar 2023 18:13:03 +0300</pubDate>
      
      <guid>https://4rkal.com/posts/thisblog/</guid>
      <description>In this article I’ll show you how I setup this blog completely for free. I’ll show you how to use hugo to write your blog, Cloudflare and eu.org for your domain and ssl, Render and github for the hosting and even how to get your blog on google.
What is hugo? Hugo is a fast and popular open-source static site generator used for creating static websites without requiring a database or dynamic components.</description>
      <content:encoded><![CDATA[<p>In this article I’ll show you how I setup this blog completely for free. I’ll show you how to use hugo to write your blog, Cloudflare and eu.org for your domain and ssl, Render and github for the hosting and even how to get your blog on google.</p>
<h1 id="what-is-hugo">What is hugo?</h1>
<p>Hugo is a fast and popular open-source static site generator used for creating static websites without requiring a database or dynamic components.</p>
<h1 id="hugo-setup">Hugo setup</h1>
<p>Download and install hugo</p>
<p>On debian type</p>
<p><code>sudo apt install hugo</code></p>
<p>On arch type</p>
<p><code>sudo pacman -S hugo</code></p>
<p>On fedora type</p>
<p><code>sudo dnf install hugo</code>
On windows:</p>
<p>Navigate to <a href="https://github.com/gohugoio/hugo/releases/latest">https://github.com/gohugoio/hugo/releases/latest</a></p>
<p>Find the windows version and download it.</p>
<p>Unzip the file to your desired directory</p>
<p>Add this directory to the PATH environment variable</p>
<p>Read more: <a href="https://gohugo.io/installation/windows/">https://gohugo.io/installation/windows/</a></p>
<h1 id="creating-the-hugo-site">Creating the hugo site</h1>
<p>Open up a terminal and type:</p>
<p><code>hugo new site my_website</code></p>
<p>And then cd into that directory</p>
<p><code>cd my_website</code></p>
<p>After that we will have to install a theme. I will be using the LoveIt theme but you can use any other theme</p>
<p>All hugo themes
<a href="https://themes.gohugo.io/">https://themes.gohugo.io/</a></p>
<p><strong>NOTE: I now use a completely different theme <a href="https://4rkal.eu.org/posts/newlook/">New look, new start</a></strong></p>
<p>For the LoveIt theme:</p>
<p>The first thing we will have to do is type</p>
<p><code>git clone https://github.com/dillonzq/LoveIt.git themes/LoveIt</code></p>
<p>You will have to have git installed if you don’t, follow the instructions on the page to download it.</p>
<p>Now we will have to create some basic configuration. Every theme has its own so you should first check your themes documentation. Some basic settings work for all themes.</p>
<p>Here is an example of the most basic settings for the LoveIt theme. (it has to be saved in config.toml)</p>
<pre tabindex="0"><code>baseURL = &#34;http://example.org/&#34;

# Change the default theme to be use when building the site with Hugo
theme = &#34;LoveIt&#34;

# website title
title = &#34;My New Hugo Site&#34;

# language code [&#34;en&#34;, &#34;zh-CN&#34;, &#34;fr&#34;, &#34;pl&#34;, ...]
languageCode = &#34;en&#34;
# language name [&#34;English&#34;, &#34;简体中文&#34;, &#34;Français&#34;, &#34;Polski&#34;, ...]
languageName = &#34;English&#34;

# Author config
[author]
  name = &#34;xxxx&#34;
  email = &#34;&#34;
  link = &#34;&#34;

# Menu config
[menu]
  [[menu.main]]
    weight = 1
    identifier = &#34;posts&#34;
    # you can add extra information before the name (HTML format is supported), such as icons
    pre = &#34;&#34;
    # you can add extra information after the name (HTML format is supported), such as icons
    post = &#34;&#34;
    name = &#34;Posts&#34;
    url = &#34;/posts/&#34;
    # title will be shown when you hover on this menu link
    title = &#34;&#34;
  [[menu.main]]
    weight = 2
    identifier = &#34;tags&#34;
    pre = &#34;&#34;
    post = &#34;&#34;
    name = &#34;Tags&#34;
    url = &#34;/tags/&#34;
    title = &#34;&#34;
  [[menu.main]]
    weight = 3
    identifier = &#34;categories&#34;
    pre = &#34;&#34;
    post = &#34;&#34;
    name = &#34;Categories&#34;
    url = &#34;/categories/&#34;
    title = &#34;&#34;

# Markup related configuration in Hugo
[markup]
  # Syntax Highlighting (https://gohugo.io/content-management/syntax-highlighting)
  [markup.highlight]
    # false is a necessary configuration (https://github.com/dillonzq/LoveIt/issues/158)
    noClasses = false
</code></pre><p>You can find my configuration <a href="https://github.com/4rkal/blog/blob/main/config.toml">here</a></p>
<p>You can view your page live by running</p>
<p><code>hugo serve</code></p>
<p>Let’s move on to the next step.</p>
<h1 id="adding-articles-to-our-blog">Adding articles to our blog</h1>
<p>The first thing we will have to do is create a new file with any name ending in .md inside of our content folder. I like to separate my posts from other sections so I will create another folder inside of the content one called posts.</p>
<p>You can run this command to add the file</p>
<p><code>hugo new posts/first_post.md</code></p>
<p>Now open the file that was just created using your favorite text editor.</p>
<p>You should see something like this:</p>
<pre tabindex="0"><code>---
title: &#34;Epic title&#34;
date: 2023-03-23T18:13:03+03:00
draft: true
---
</code></pre><p>If you want the post to be publicly visible on your blog delete the draft line. or set it to false.</p>
<p>Now if we want to add some content we will have to write it in markdown. Heres a great guide on some basic markdown syntax <a href="https://hugoloveit.com/basic-markdown-syntax/">https://hugoloveit.com/basic-markdown-syntax/</a></p>
<p>Heres an example of some content</p>
<pre tabindex="0"><code>---
title: &#34;My First Post&#34;
date: 2023-03-23T18:13:03+03:00
draft: false
---

# Welcome to my blog!

This is my first post. Here&#39;s a picture of my cat:

![My cat](/images/cat.jpg)
</code></pre><p>Using the above steps you can add all of your articles to the blog.</p>
<p>Now that we are done with that let me show you how we will publish our blog.</p>
<h1 id="domain">Domain</h1>
<p>More like a sub-domain. Head to eu.org and get a free domain. Create an account and submit a request for a new domain. It might take some time even months to get accepted.</p>
<p>I have already registered 4rkal.eu.org from there.</p>
<p>Now we will have to get some ssl certificates using cloudflare.</p>
<p>SSL certificates just make your site use https instead of http this is really great for seo and doesn’t make your site look sus.</p>
<p>Head over to cloudflare.com and create an account for free.</p>
<p>After you are done with that go to your dashboard and select websites and then add a site.</p>
<p>You should see something like this</p>
<p><img loading="lazy" src="/../assets/cloudflare.webp" type="" alt=""  /></p>
<p>Enter your websites url and click on add site.</p>
<p>After that select the free plan and continue.</p>
<p>Now it will review your dns records. Just select continue and confirm</p>
<p>Now you will have to change your domain’s name servers.</p>
<p>To do that head back to eu.org select your domain and click on the nameservers tab and select server names.</p>
<p>Now in the input fields enter the name servers.</p>
<p>The name servers will most probably be:</p>
<pre tabindex="0"><code>nancy.ns.cloudflare.com
uriah.ns.cloudflare.com
</code></pre><p>Here’s how it should probably look:</p>
<p><img loading="lazy" src="/../assets/euorg.webp" type="" alt=""  /></p>
<p>Now click on the submit button.</p>
<p>You should probably get</p>
<pre tabindex="0"><code>No error, applying changes...

Done
</code></pre><p>If you get an error you probably screwed up one of the above steps. Just try again.</p>
<p>After your name servers have been changed and everything is done, in your domain dashboard select SSL/TLS. Just select full encryption.</p>
<h1 id="hosting-our-site">Hosting our site.</h1>
<p>First create a github account. Head to github.com for that. You will also have to install <a href="https://git-scm.com/">git</a></p>
<p>After you have done that navigate to your blog’s root directory and type:</p>
<pre tabindex="0"><code>git init
hugo
git add .
git commit -m &#34;first commmit&#34;
git branch -M main
</code></pre><p>Now go to github and create a new repository.</p>
<p>You should now type:</p>
<p><code>git remote add origin YOURURL</code></p>
<p>instead of YOURURL enter the url to your github repo and add a .git ending</p>
<p>eg</p>
<p><code>git remote add origin https://github.com/4rkal/blog.git</code></p>
<p>Now push the changes with</p>
<p><code>git push -u origin main</code></p>
<p>After that if you refresh the page of your github repo you should see everything there.</p>
<p>Now head to <a href="https://render.com">render.com</a> and create an account</p>
<p>On your dashboard select +New and then static site.</p>
<p>Now you will be prompted to connect a github repository. Just connect your account and add that repository.</p>
<p>eg</p>
<p><img loading="lazy" src="/../assets/render.webp" type="" alt=""  /></p>
<p>Now enter a service name eg myblog and in the publish directory just add</p>
<p><code>public</code></p>
<p>Then click on create static site.</p>
<p>After it has been deployed successfully head over to the settings and in the custom domains tab click on add custom domain.</p>
<p>In the field enter the domain that we registered with eu.org previously.</p>
<p>Now go to cloudflare and in your domain dashboard select dns and click on add a new record.</p>
<p>In the type dropdown select CNAME in the name field add @ and in the target add your blog’s url from render. Mine is <a href="https://blog-ygtj.onrender.com/">https://blog-ygtj.onrender.com/</a>. Also untick the proxy status.</p>
<p>Now we will have to do the same but with the www.</p>
<p>Just do the same steps as above but instead of @ just add <code>www</code></p>
<p>That’s it. After a couple of minutes your blog should be live.</p>
<h1 id="seo-google-and-bing">SEO Google and bing</h1>
<p>If you want to get your website on google and bing it’s pretty easy</p>
<p>If you want to get your website on google follow the guide listed here
<a href="https://developers.google.com/search">https://developers.google.com/search</a></p>
<p>For bing it should be pretty much the same process on <a href="https://www.bing.com/webmasters/">https://www.bing.com/webmasters/</a></p>
<p>*<strong>If you enjoyed this article consider <a href="../../donate">supporting me</a></strong></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Python for Complete Beginners</title>
      <link>https://4rkal.com/posts/python/</link>
      <pubDate>Mon, 06 Mar 2023 20:52:42 +0300</pubDate>
      
      <guid>https://4rkal.com/posts/python/</guid>
      <description>Why you should use Python. Going over the basics of Python.
In this course/article I will be talking about why someone should use Python. Later on, I will be tackling the basics of Python. But let&amp;rsquo;s start by explaining what coding is.
What is coding? Coding means writing instructions for computers and a finished set of instructions is known as a program. Computer programs control everything from smartphones to space rockets.</description>
      <content:encoded><![CDATA[<p>Why you should use Python. Going over the basics of Python.</p>
<p>In this course/article I will be talking about why someone should use Python. Later on, I will be tackling the basics of Python. But let&rsquo;s start by explaining what coding is.</p>
<h2 id="what-is-coding">What is coding?</h2>
<p>Coding means writing instructions for computers and a finished set of instructions is known as a program. Computer programs control everything from smartphones to space rockets.</p>
<h2 id="what-is-python">What is Python?</h2>
<p>Python is a text-based computer language which means it’s made up of words and symbols (such as * and = ). Its language elements and object-oriented approach are meant to assist programmers in writing clear, logical code for both small and large-scale projects.</p>
<h2 id="why-python">Why Python?</h2>
<p>Python is one of the most popular computer languages and it’s very concise — that is, you don&rsquo;t need to type much in order to create programs that do a lot.</p>
<h2 id="advantages-of-python">Advantages of python</h2>
<ol>
<li>Simple to read, learn, and write</li>
</ol>
<p>Python is a high-level programming language with a syntax that is similar to English. This makes the code easier to read and comprehend.</p>
<p>Python is really simple to pick up and understand, which is why many people suggest it to newcomers. When compared to other prominent languages like C/C++ and Java, you require fewer lines of code to accomplish the same purpose.</p>
<ol start="2">
<li>Improved Productivity</li>
</ol>
<p>Python is an extremely useful programming language. Python’s simplicity allows developers to concentrate on solving the problem.</p>
<p>They don’t need to spend a lot of time learning the programming language’s syntax or behaviour. You write less code and accomplish more.</p>
<ol start="3">
<li>Free and Open-Source</li>
</ol>
<p>Python comes under the OSI-approved open-source license. As a result, it is both free to use and distribute. You can get the source code, change it, and even share your own Python version.</p>
<ol start="4">
<li>Portability</li>
</ol>
<p>In many languages like C/C++, you need to change your code to run the program on different platforms. With Python, however, this is not the case. You only have to write it once and it may be used wherever.</p>
<h2 id="downloading-python">Downloading Python</h2>
<p><strong>On Linux</strong>
You probably already know how to install it but I&rsquo;m gonna show it anyways.</p>
<p>Open your terminal and type python or python3; if it does not work then run: (depending on your distro)
<code>sudo apt install python3</code></p>
<p><strong>Windows 10</strong>
1 . First check if you already have Python installed. Go to the ‘Start’ menu and click on the ‘All programs’. If you see the word “Python” it means that you already have it installed. If you don&rsquo;t already have it installed go to <a href="https://python.org">https://python.org</a>, download the correct version for your computer and then install it.</p>
<ol start="2">
<li>Python comes in different versions. This course uses version 3 and upwards. I recommend always installing the latest version.</li>
</ol>
<h2 id="what-is-an-ide">What is an IDE?</h2>
<p>IDE stands for the integrated development environment (IDE) and is software for building applications that combine common developer tools into a single Graphical User Interface (GUI).</p>
<p>The IDE that we will be using in this series is called VS Code.</p>
<h2 id="downloading-vs-code">Downloading VS Code</h2>
<p>Go to <a href="https://code.visualstudio.com/">https://code.visualstudio.com/</a> and download the version that you want. Vs Code is available for Windows, Mac, and Linux. Follow the instructions on the website for installation.</p>
<h2 id="starting-in-python">Starting in Python</h2>
<p>It&rsquo;s traditional in the programming world to make the computer say ‘Hello World’ with your very first piece of code. In Python, this is very simple.</p>
<ol>
<li>Open Vs Code and click on File &gt; New File and name your file helloworld.py. The .py tells the computer that this is a Python program.</li>
<li>In your project, in VS Code type :
<code>print(&quot;Hello World!&quot;)</code></li>
<li>Save your project and click on the run button at the top of your screen</li>
<li>If you have done everything correctly you should see a Hello World message in your terminal.</li>
</ol>
<p>If it didn&rsquo;t work you should get a red error message something like this:</p>
<p><code>SyntaxError: invalid syntax</code></p>
<p>If that happens make sure that you have copied it exactly like above.</p>
<h2 id="playing-with-numbers-in-python">Playing With numbers in Python</h2>
<p>Python makes it easy to do maths. You just type in a question and get the answer</p>
<p><strong>Adding Up</strong></p>
<p>Open an empty project and type:</p>
<p><code>print(2+2)</code></p>
<p>You should see the answer:
<code>4</code></p>
<p><strong>Subtracting(and more)</strong>
If you want to subtract, use the ‘-’ symbol like this:</p>
<p><code>print(2 - 2)</code></p>
<p>To multiply use the ‘*’ symbol:</p>
<p><code>print(2 * 2)</code></p>
<p>To divide, use the ‘/’ symbol</p>
<p><code>print(2 / 2)</code></p>
<h2 id="variables">Variables</h2>
<p>A variable is like a labelled box that stores information. You can change this information but the label stays the same.</p>
<h2 id="creating-a-variable">Creating a variable:</h2>
<p>To tell the computer what you want your variable to be, you use the = sign. This is called assigning a value to a variable. It’s very simple, here&rsquo;s an example using fish.</p>
<ol>
<li>Open a new VS Code project and type:
<code>fish = 5</code></li>
</ol>
<p>Imagine a cat gets hungry and eats two fish. To create another variable for the amount eaten, write the following:</p>
<p><code>fishEaten = 2</code></p>
<p>Press enter and then type:</p>
<p><code>print(fish - fishEaten)</code></p>
<p>Save and run your code and you should get the answer:
<code>3</code></p>
<h2 id="input-in-python">Input in Python</h2>
<p>You can use the input() function to ask for information from the user.</p>
<ol>
<li>Open a new VS Code project and type:</li>
</ol>
<p><code>name = input(&quot;What is your name? &quot;)</code></p>
<ol start="2">
<li>Run the program and you should get the following message:</li>
</ol>
<p><code>What is your name? </code>
3. Now let&rsquo;s try printing your name.</p>
<p>Add the following to your program:</p>
<p><code>print(name)</code></p>
<p>You have successfully created an input field!</p>
<p>This can be very useful in creating decision games.</p>
<h2 id="making-decisions">Making Decisions</h2>
<p>To write a program that allows you to make decisions the computer needs to react differently to different answers. For this, you need conditions to compare pieces of information, and conditionals to create different paths through the program.</p>
<h2 id="what-are-conditions">What are Conditions?</h2>
<p>A condition is a bit of code that compares two pieces of information. Conditions use operators to make these comparisons. For example, the operator == checks if two pieces of information are the same.</p>
<ol>
<li>Open a new Vs Code project and type:</li>
</ol>
<pre tabindex="0"><code>age = 10
if age == 12:
 print(&#34;True&#34;)
else:
 print(&#34;False&#34;)
</code></pre><ol start="2">
<li>Save and run and you should get False</li>
</ol>
<p>That is because ‘age’ is set to 10 and not 12</p>
<h2 id="what-are-conditionals">What are conditionals</h2>
<p>To use a condition in your code you need a command called a condition. Conditionals use conditions. Conditions show if something is True or False.</p>
<h2 id="if">IF</h2>
<p>One important condition is known as an if statement which tests whether a condition is true. If it is, the computer will follow the instructions after the if statement. If not, the computer will just skip it. In Python, if is a keyword. Dont use it as a variable name because the computer will think that it&rsquo;s an if statement and get confused.</p>
<h2 id="implementing-the-if-condition">Implementing the if condition</h2>
<ol>
<li>Create a new VS Code project and type the following:</li>
</ol>
<p><code>user_reply = (&quot;Do you like python? (Type yes or no) &quot;)</code></p>
<ol start="2">
<li>Then we will implement the if condition by typing the following:</li>
</ol>
<pre tabindex="0"><code>if user_reply == &#34;yes&#34;
   print(&#34;Python likes you to ! &#34;)
</code></pre><h2 id="elif">ELIF</h2>
<p>elif is short for else if. If the conditions of the if code isn’t met it “sweeps up” whatever is left.</p>
<ol start="3">
<li>Now type the following:</li>
</ol>
<pre tabindex="0"><code>elif user_reply == &#34;maybe&#34;:
  print(&#34;Make up your mind!&#34;)
</code></pre><h2 id="else">ELSE</h2>
<p>When conditions for the if and elif code arent met, else goes into action and “sweeps up” whatever is left.</p>
<p>Let&rsquo;s implement that:
4. Now type the following:</p>
<pre tabindex="0"><code>else:
  print(&#34;Well python doesn&#39;t like you either&#34;)
</code></pre><p>The complete code should look something like this:</p>
<pre tabindex="0"><code>user_reply = (&#34;Do you like python? (Type yes or no) &#34;)
if user_reply == &#34;yes&#34;
   print(&#34;Python likes you to ! &#34;)
elif user_reply == &#34;maybe&#34;:
  print(&#34;Make up your mind!&#34;)
else:
  print(&#34;Well python doesn&#39;t like you either&#34;)
</code></pre><p><strong>Don&rsquo;t forget to press the tab after if statements.</strong></p>
<h2 id="randomness-in-python">Randomness in python</h2>
<p>In python we can use the random function in order to generate random numbers. This can be extremely useful in a variety of things.</p>
<p>The first thing we will have to do is import the random function</p>
<p><code>import random</code></p>
<p>After that we can print out a random number with the following</p>
<p><code>print(random.randint(1,10))</code></p>
<p>This will output a random number from 1–10</p>
<p>randint stands for random integer.</p>
<p>Here is the full code.</p>
<pre tabindex="0"><code>import random
print(random.randint(1,10))
</code></pre><h2 id="loops-in-python">Loops in python</h2>
<p>There are two types of loops in python</p>
<ol>
<li>While loop</li>
<li>For loop</li>
</ol>
<p>While loops only stop when something changes. If it doesn&rsquo;t change they could go on forever.</p>
<p>With for loops on the other hand you can define exactly when you want them to stop</p>
<p>The most popular example of a while loop is</p>
<p><code>while True:</code></p>
<p>Which will run forever eg</p>
<pre tabindex="0"><code>while True:
    print(&#34;hi&#34;)
</code></pre><p>This will run forever.</p>
<p>With while loops on the other hand you can define exactly how many times you want the loop to run.</p>
<pre tabindex="0"><code>for x in range(0,10):
   print(&#34;Hi&#34;)
</code></pre><p>This will print Hi exactly 10 times</p>
<h2 id="guessing-game">Guessing game</h2>
<p>Now lets combine what learned from above and from our previous articles to create a game</p>
<p>The computer will select a random number from 1–10 and you will have to guess it.</p>
<p>The first thing we will have to do is</p>
<p><code>import random</code></p>
<p>After that we will create a variable called number</p>
<p><code>number = random.randint(1,10)</code></p>
<p>After that we will create another variable called your_guess</p>
<p><code>your_guess = int(input(&quot;Im thinking of a number from 1 to 10, can you guess which one?&quot;))</code></p>
<p>We are using int as you will have to enter a number</p>
<p>Now we will create a while loop that will keep the game running until you guess the number</p>
<p><code>while your_guess != number:</code></p>
<p>The code so far is</p>
<pre tabindex="0"><code>import random
number = random.randint(1,10)
your_guess = int(input(&#34;Im thinking of a number from 1 to 10, can you guess which one?&#34;))
while your_guess != number:
    if your_guess &lt; number:
        print(&#34;Your number was too low&#34;)
    else:
        print(&#34;You number was to high&#34;)
</code></pre><p>And the following</p>
<p><code>print(&quot;GG you found it&quot;)</code></p>
<p>You code should now look like this</p>
<pre tabindex="0"><code>import random
number = random.randint(1,10)
your_guess = int(input(&#34;Im thinking of a number from 1 to 10, can you guess which one?&#34;))
while your_guess != number:
    if your_guess &lt; number:
        print(&#34;Your number was too low&#34;)
    else:
        print(&#34;You number was to high&#34;)
    your_guess = int(input(&#34;Please try again... &#34;))
print(&#34;GG you found it&#34;)
</code></pre><p><strong>Thats it for now</strong></p>
<p>Stay tuned for more</p>
<p><em><strong>If you enjoyed this article consider <a href="../../donate">supporting me</a></strong></em></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>PocketBase self-hosted Firebase alternative</title>
      <link>https://4rkal.com/posts/pocketbase/</link>
      <pubDate>Mon, 06 Mar 2023 20:44:46 +0300</pubDate>
      
      <guid>https://4rkal.com/posts/pocketbase/</guid>
      <description>What is PocketBase PocketBase is an open source backend made in go consisting of embedded database (SQLite) with realtime subscriptions, built-in auth management, convenient dashboard UI and simple REST-ish API.
Install PocketBase The first thing that you will have to do is head to https://pocketbase.io and select the file for your operating system. Since I am using linux I will show how to set this up on linux but it should be pretty similar for any other os.</description>
      <content:encoded><![CDATA[<h1 id="what-is-pocketbase">What is PocketBase</h1>
<p>PocketBase is an open source backend made in go consisting of embedded database (SQLite) with realtime subscriptions, built-in auth management, convenient dashboard UI and simple REST-ish API.</p>
<h2 id="install-pocketbase">Install PocketBase</h2>
<p>The first thing that you will have to do is head to <a href="https://pocketbase.io">https://pocketbase.io</a> and select the file for your operating system. Since I am using linux I will show how to set this up on linux but it should be pretty similar for any other os.</p>
<p>Unzip the file and open up a terminal to the path that you extracted the file to and type:</p>
<p><code>./pocketbase serve</code></p>
<p>If you want to serve some static content you can create a new directory called pb_public</p>
<p><code>mkdir pb_public</code></p>
<p>Then paste any content into that directory</p>
<p>eg.</p>
<pre tabindex="0"><code>&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta http-equiv=&#34;X-UA-Compatible&#34; content=&#34;IE=edge&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Epic Website&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;h1&gt;My epic website&lt;/h1&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre><p>And save that as index.html inside of the pb_public folder</p>
<p>Now if you head to http://127.0.0.1:8090/ you should see the website that we entered above.</p>
<p>If you go to http://127.0.0.1:8090/_/ it will take you to an admin portal. There you should create a account. After you have setted up your account you should see something like this.</p>
<p><img loading="lazy" src="/../assets/pocketbase.webp" type="" alt="1"  /></p>
<p>Here you can add and create users</p>
<p><img loading="lazy" src="/../assets/pocketbase2.webp" type="" alt="2"  /></p>
<p>And also create custom collections eg</p>
<p><img loading="lazy" src="/../assets/pocketbase3.webp" type="" alt="2"  /></p>
<p>If you click on the settings icon you can see that you will be able to add applications, mail settings, file storage (s3) , export/import collections, add or remove auth providers, token options and add/remove admins.</p>
<p>That’s it for now if you want to learn more check out <a href="https://pocketbase.io/docs/">https://pocketbase.io/docs/</a></p>
<p><em><strong>If you enjoyed this article consider <a href="../../donate">supporting me</a></strong></em></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Why Monero is the ultimate form of a cryptocurrency</title>
      <link>https://4rkal.com/posts/whymonero/</link>
      <pubDate>Mon, 06 Mar 2023 20:23:16 +0300</pubDate>
      
      <guid>https://4rkal.com/posts/whymonero/</guid>
      <description>In this article, I will tell you why Monero fits my views of what a cryptocurrency should look like.
What is Monero? Monero is a decentralized cryptocurrency. It uses a public distributed ledger with privacy-enhancing technologies that obfuscate transactions to achieve anonymity and fungibility. Observers cannot decipher addresses trading Monero, transaction amounts, address balances, or transaction histories.
Monero works like any other currency but with some privacy and decentralization innovations.</description>
      <content:encoded><![CDATA[<p>In this article, I will tell you why Monero fits my views of what a cryptocurrency should look like.</p>
<h1 id="what-is-monero">What is Monero?</h1>
<p>Monero is a decentralized cryptocurrency. It uses a public distributed ledger with privacy-enhancing technologies that obfuscate transactions to achieve anonymity and fungibility. Observers cannot decipher addresses trading Monero, transaction amounts, address balances, or transaction histories.</p>
<p>Monero works like any other currency but with some privacy and decentralization innovations.</p>
<p>Monero uses <a href="https://www.investopedia.com/terms/s/stealth-address-cryptocurrency.asp">stealth addresses</a> alongside <a href="https://web.getmonero.org/resources/moneropedia/ringsignatures.html">ring signatures</a> and <a href="https://www.getmonero.org/resources/moneropedia/ringCT.html">ring CTs</a> to &ldquo;hide&rdquo; the transaction and transaction amounts, enhancing transaction privacy. To further decentralize the network, Monero uses the <a href="https://www.getmonero.org/resources/moneropedia/randomx.html">RandomX algorithm</a> to discourage the use of ASICs.</p>
<h1 id="the-main-problems-with-bitcoin-and-other-cryptos">The Main Problems with Bitcoin and Other Cryptos</h1>
<p>Bitcoin may seem like a perfect currency. However, under the hood, Bitcoin has many flaws.</p>
<p>One of the main problems with Bitcoin is that it isn&rsquo;t actually censorship-resistant. A central bank or government can blacklist your address and block exchanges from accepting it. While there are ways to get around that, it isn&rsquo;t easy. Monero, on the other hand, is censorship-resistant as it doesn&rsquo;t display transaction amounts or receivers.</p>
<p>Another problem with Bitcoin and other PoW currencies is that they are actually controlled by a small number of people since they are really hard to mine, among many other factors. Monero is a relatively easy currency to mine and is ASIC-resistant, which makes it even more decentralized as anyone with a computer and an internet connection can start contributing to the network.</p>
<p>Bitcoin has a block size limit, which results in more expensive transactions and longer waiting times. Monero uses a <a href="https://localmonero.co/knowledge/dynamic-block-size">dynamic block size</a>.</p>
<p>Also, Bitcoin has a <a href="https://bitinfocharts.com/comparison/bitcoin-confirmationtime.html#3m">high block time</a>, which means that transactions take longer to be confirmed and executed. Bitcoin&rsquo;s block time is ~10 minutes, while <a href="https://bitinfocharts.com/comparison/monero-confirmationtime.html#3y">Monero&rsquo;s block time</a> is ~2 minutes.</p>
<p>Bitcoin has halving once every 4 years. The halving halves the amount of mined (printed) Bitcoin in every block. This, by itself, increases price volatility and transaction fee volatility.</p>
<p>Monero has chosen a 0.6 XMR block reward forever. Any good currency wants to have as little volatility as possible. Monero is a currency, not a &ldquo;number go up coin.&rdquo;</p>
<h1 id="conclusion">Conclusion</h1>
<p>Monero is basically what people think Bitcoin is. Here&rsquo;s a great <a href="https://www.youtube.com/watch?v=ak5TFr26BaE">video about it</a>.</p>
<h1 id="disclaimer">Disclaimer</h1>
<p>Tech has nothing to do with price. This article reviews the tech of this project and is thus not financial advice. Please DYOR when investing.</p>
<h1 id="support-me">Support Me</h1>
<p>If you enjoyed this article, consider supporting me:</p>
<p>Monero:</p>
<p><code>8AztDJtwb7iKaqP4KXRG39VibAacCY1mMfH3bNsVjhYMYbohtT5LKoTSRP6vJGtjeBSPEpFdHZx3ZL3iVowYdkqeQwPAG2o</code></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Create a MultiBoot USB using ventoy</title>
      <link>https://4rkal.com/posts/ventoy/</link>
      <pubDate>Mon, 06 Mar 2023 20:11:51 +0300</pubDate>
      
      <guid>https://4rkal.com/posts/ventoy/</guid>
      <description>Whats ventoy? Ventoy is a free and open-source utility used for writing image files such as .iso, .wim, .img, .vhd(x), and .efi files onto storage media to create bootable USB flash drives. Once Ventoy is installed onto a USB drive, there is no need to reformat the disk to update it with new installation files; it is enough to copy the .iso to the USB drive and boot from them directly.</description>
      <content:encoded><![CDATA[<h2 id="whats-ventoy">Whats ventoy?</h2>
<p>Ventoy is a free and open-source utility used for writing image files such as .iso, .wim, .img, .vhd(x), and .efi files onto storage media to create bootable USB flash drives. Once Ventoy is installed onto a USB drive, there is no need to reformat the disk to update it with new installation files; it is enough to copy the .iso to the USB drive and boot from them directly. Ventoy will present the user with a boot menu to select one of these files.</p>
<p>With ventoy, you don’t need to format the disk over and over, you just need to copy the ISO files to the USB drive and boot them directly.</p>
<h2 id="requirements">Requirements</h2>
<ol>
<li>a computer</li>
<li>a internet connection (pretty hard without one)</li>
<li>a usb (min 8gb)</li>
</ol>
<h2 id="installation">Installation</h2>
<p>Ventoy is available on both linux and windows.</p>
<p>The first thing you will have to do is head to ventoy.net . On the download page select your operating system and click on download.</p>
<h2 id="on-linux">On linux</h2>
<p>After you have extracted the file open the folder and click on the VentoyGUI .</p>
<p>Depending on your processor type select the file ending in either aarch64 i386 mips64el or x86_64. (It will most probably be x86_64).</p>
<p>After that you should see something like this:
<img loading="lazy" src="/../assets/ventoy.webp" type="" alt="Ventoy on linux"  /></p>
<p>Select your device from the devices tab</p>
<p>Then click on install.</p>
<h2 id="on-windows">On windows</h2>
<p>Download the file and unzip it</p>
<p>Then click on the file called Ventoy2Disk.exe</p>
<p>You should see something like this</p>
<p><img loading="lazy" src="/../assets/ventoy-win.webp" type="" alt="Ventoy on Windows"  /></p>
<p>Select your usb device from the drop down and click on install.</p>
<h1 id="using-ventoy">Using ventoy</h1>
<p>To use ventoy all you have to do is paste your iso files inside of the usb. No need for formatting etc.</p>
<p>When you boot into your usb you will be prompted which of the iso&rsquo;s to use. That&rsquo;s about it.</p>
<p>Enjoy not having to reformat your usb for each iso/OS.</p>
<h3 id="join-my-free-newsletter">Join my free newsletter!</h3>
<div style="text-align: left; margin: 0 auto;">
    <form method="post" action="https://newsletter.4rkal.com/subscription/form" style="background: #2c2c2c; color: #f0f0f0; border-radius: 8px; padding: 15px; max-width: 500px; box-shadow: 0 3px 6px rgba(0, 0, 0, 0.2); font-family: Arial, sans-serif;">
        <div style="display: flex; flex-direction: column; gap: 10px;">
            <h3 style="margin: 0; color: #f0f0f0; font-size: 18px;">Subscribe</h3>
            <input type="hidden" name="nonce"/>
            <input type="email" name="email" required placeholder="E-mail" style="width: 100%; padding: 10px; border: 1px solid #666; border-radius: 4px; background: #333; color: #f0f0f0; box-sizing: border-box;"/>
            <div style="display: flex; flex-direction: column; gap: 8px;">
                <label style="margin: 0; color: #f0f0f0; display: none;">
                    <input id="78a75" type="checkbox" name="l" checked value="78a75b30-472d-4790-a5d5-7f2ed49662a4" style="accent-color: #fff;"/>
                    Weekly Roundup
                </label>
                <span style="color: #d0d0d0; display: none;">Where I share what I’ve been up to that week, including articles I’ve published, cool finds, tips and tricks, and more!</span>
                <label style="margin: 0; color: #f0f0f0; display: none;">
                    <input id="b3964" type="checkbox" name="l" checked value="b3964560-37b0-43d3-9df9-26589fd6bf8d" style="accent-color: #fff;"/>
                    New Posts
                </label>
                <span style="color: #d0d0d0; display: none;">Receive an email every time I post something new on my blog</span>
            </div>
            <input type="submit" value="Subscribe" style="width: 100%; padding: 10px; border: none; border-radius: 4px; background: #fff; color: #007bff; font-size: 14px; cursor: pointer; transition: background-color 0.3s ease, box-shadow 0.3s ease; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);"/>
        </div>
        <p style="text-align: center; margin-top: 10px; color: #d0d0d0; font-size: 10px; margin-bottom:0px;">
            No spam, no ads. Unsubscribe at any time.
        </p>
    </form>
</div>]]></content:encoded>
    </item>
    
    <item>
      <title>Nmap(Network Mapper) For Beginners</title>
      <link>https://4rkal.com/posts/nmap/</link>
      <pubDate>Sun, 05 Mar 2023 17:37:03 +0300</pubDate>
      
      <guid>https://4rkal.com/posts/nmap/</guid>
      <description>Whether you want to scan your network for vulnerabilities or just want to see which ports you have open, nmap can be extremely useful.
What is nmap Nmap (Network Mapper) is a network scanner created by Gordon Lyon . Nmap sends packets and examines the answers to find hosts and services on a computer network. For probing computer networks, Nmap offers a variety of functionalities, including host discovery, service detection, and operating system detection.</description>
      <content:encoded><![CDATA[<p>Whether you want to scan your network for vulnerabilities or just want to see which ports you have open, nmap can be extremely useful.</p>
<h1 id="what-is-nmap">What is nmap</h1>
<p>Nmap (Network Mapper) is a network scanner created by Gordon Lyon . Nmap sends packets and examines the answers to find hosts and services on a computer network. For probing computer networks, Nmap offers a variety of functionalities, including host discovery, service detection, and operating system detection. Scripts that offer more sophisticated service discovery, vulnerability detection, and other features can extend these features. During a scan, Nmap can adjust to changing network conditions, such as latency and congestion.</p>
<h1 id="installation">Installation</h1>
<p>Nmap is available for linux, windows , mac os and even bsd</p>
<p>If you are using linux you can install it using your package manager.</p>
<p>On apt</p>
<p><code>sudo apt install nmap</code></p>
<p>On dnf</p>
<p><code>sudo dnf install nmap</code></p>
<p>With pacman</p>
<p><code>sudo pacman -S nmap</code></p>
<p>On windows you have to download the executable from the nmap website.</p>
<p><a href="https://nmap.org/download.html">https://nmap.org/download.html</a></p>
<p>The same goes for mac and any other os</p>
<h1 id="getting-started">Getting Started</h1>
<p>The first thing I will show you how to do is find all the ip addresses connected to your local network.</p>
<p>The first thing you will have to do is find your inet ip</p>
<p>On Linux type</p>
<p><code>ip a</code></p>
<p>On windows</p>
<p><code>ipconfig</code></p>
<p>You should see a lot of information, try to find inet. It should look something like this</p>
<p><code>inet 192.168.1.28/24</code></p>
<p>and copy the ip</p>
<p>Now type</p>
<p><code>nmap -sn IP</code></p>
<p>Instead of ip type the ip we found from above</p>
<p>Now you should see a large list of all the ips connected to your network.</p>
<p>-sn flag stands for no port scan</p>
<p>Now we can also get all the ports open on all the ips on your local network</p>
<p>To do that type</p>
<p><code>nmap IP</code></p>
<p>Instead of ip type the ip we found from above</p>
<p>Now if you have any computers on your local networks with open ports you should see them now</p>
<p>Eg.</p>
<p>I have a ssh port open on one of my machines so I can see</p>
<pre tabindex="0"><code>PORT   STATE SERVICE
22/tcp open  ssh
</code></pre><p>If you are running a web server ports 80 and 443 should be open.</p>
<p>Now lets say that you want to find out what operating system a specified device on your network is running.</p>
<p>To do that type</p>
<p><code>sudo nmap -O IP</code></p>
<p>Eg.</p>
<p><code>sudo nmap -O 192.168.1.16</code></p>
<p>In my case my device is running linux and you can even find out what kernel version your device is running</p>
<pre tabindex="0"><code>PORT   STATE SERVICE
22/tcp open  ssh
Device type: general purpose
Running: Linux 2.6.X
OS CPE: cpe:/o:linux:linux_kernel:2.6.32
OS details: Linux 2.6.32
</code></pre><p>You can press enter while running a scan to see how much time is left</p>
<p>Lets say that you dont want anyone monitoring a network be able to trace back the scan to you.</p>
<p>For that we can use decoy mode</p>
<p>To use decoy mode add -D followed by any random ip to any nmap command.</p>
<p>eg</p>
<p><code>sudo nmap -D 192.168.1.11 192.168.1.16</code></p>
<p>This will make it so that it looks like both your ip and 192.168.1.11 are performing a port scan on 192.168.1.16</p>
<p>You can also add multiple ips by adding commas</p>
<p>eg</p>
<p><code>sudo nmap -D 192.168.1.11,192.168.1.12 192.168.1.16</code></p>
<p>Thats all for now</p>
<p><strong>GG</strong> You have now learnt the basics of nmap
***If you enjoyed this article consider <a href="../../donate">supporting me</a></p>
<div style="text-align: left; margin: 0 auto;">
    <form method="post" action="https://newsletter.4rkal.com/subscription/form" style="background: #2c2c2c; color: #f0f0f0; border-radius: 8px; padding: 15px; max-width: 500px; box-shadow: 0 3px 6px rgba(0, 0, 0, 0.2); font-family: Arial, sans-serif;">
        <div style="display: flex; flex-direction: column; gap: 10px;">
            <h3 style="margin: 0; color: #f0f0f0; font-size: 18px;">Subscribe</h3>
            <input type="hidden" name="nonce"/>
            <input type="email" name="email" required placeholder="E-mail" style="width: 100%; padding: 10px; border: 1px solid #666; border-radius: 4px; background: #333; color: #f0f0f0; box-sizing: border-box;"/>
            <div style="display: flex; flex-direction: column; gap: 8px;">
                <label style="margin: 0; color: #f0f0f0; display: none;">
                    <input id="78a75" type="checkbox" name="l" checked value="78a75b30-472d-4790-a5d5-7f2ed49662a4" style="accent-color: #fff;"/>
                    Weekly Roundup
                </label>
                <span style="color: #d0d0d0; display: none;">Where I share what I’ve been up to that week, including articles I’ve published, cool finds, tips and tricks, and more!</span>
                <label style="margin: 0; color: #f0f0f0; display: none;">
                    <input id="b3964" type="checkbox" name="l" checked value="b3964560-37b0-43d3-9df9-26589fd6bf8d" style="accent-color: #fff;"/>
                    New Posts
                </label>
                <span style="color: #d0d0d0; display: none;">Receive an email every time I post something new on my blog</span>
            </div>
            <input type="submit" value="Subscribe" style="width: 100%; padding: 10px; border: none; border-radius: 4px; background: #fff; color: #007bff; font-size: 14px; cursor: pointer; transition: background-color 0.3s ease, box-shadow 0.3s ease; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);"/>
        </div>
        <p style="text-align: center; margin-top: 10px; color: #d0d0d0; font-size: 10px; margin-bottom:0px;">
            No spam, no ads. Unsubscribe at any time.
        </p>
    </form>
</div>]]></content:encoded>
    </item>
    
    <item>
      <title>How Microsoft is monetizing the GitHub code base</title>
      <link>https://4rkal.com/posts/githubmon/</link>
      <pubDate>Sun, 05 Mar 2023 17:21:56 +0300</pubDate>
      
      <guid>https://4rkal.com/posts/githubmon/</guid>
      <description>Microsoft purchased GitHub in 2018, something many users are not aware of. After Microsoft’s acquisition of GitHub there have been many controversies like blocking private repositories and access to GitHub pages in certain countries and of course, GitHub Copilot.
What is Github Copilot GitHub Copilot is an artificial intelligence tool developed by GitHub and OpenAI to assist users of Visual Studio Code, Visual Studio, Neovim, and JetBrains integrated development environments (IDEs) by autocompleting code.</description>
      <content:encoded><![CDATA[<p>Microsoft purchased GitHub in 2018, something many users are not aware of. After Microsoft’s acquisition of GitHub there have been many controversies like blocking private repositories and access to GitHub pages in certain countries and of course, GitHub Copilot.</p>
<h1 id="what-is-github-copilot">What is Github Copilot</h1>
<p>GitHub Copilot is an artificial intelligence tool developed by GitHub and OpenAI to assist users of Visual Studio Code, Visual Studio, Neovim, and JetBrains integrated development environments (IDEs) by autocompleting code. Currently available by subscription to individual developers, the tool was first announced by GitHub on 29 June 2021, and works best for users coding in Python, JavaScript, TypeScript, Ruby, and Go.</p>
<h1 id="how-does-copilot-work">How does copilot work?</h1>
<p>GitHub Copilot is powered by the OpenAI Codex, an artificial intelligence model created by OpenAI. The Generative Pre-trained Transformer 3 (GPT-3) language model, which uses deep learning to create text that resembles human speech, is improved and used in production as the OpenAI Codex.</p>
<p>Github copilot was trained on a selection of the English language, public GitHub repositories, including 59 gigabytes of Python code sourced from 54 million public GitHub repositories.</p>
<p>There still is a lot of controversy about whether GitHub should be allowed to do so, as most open source licences obviously don’t contain anything against analyzing your code with AI and selling it. Also, as AI is analyzing the code base it is not classified as derivative work which seems to be legal. However, it seems quite unethical by Microsoft as Copilot is a paid service that relies on analyzing other people’s code.
Read more:
<a href="https://www.theverge.com/2021/7/7/22561180/github-copilot-legal-copyright-fair-use-public-code">https://www.theverge.com/2021/7/7/22561180/github-copilot-legal-copyright-fair-use-public-code</a></p>
<p>If copilot was free to use it would make a lot more sense as it utilizes FOSS(Free and open sourced software) in order to work. However with Microsoft’s decision to make copilot payed they are monetizing most off GitHub&rsquo;s code base which is an illegal grey zone.</p>
<p>Analyzing a huge amount of code without any security features has led to many problems like GitHub leaking phone numbers (I even encountered it while testing copilot out).</p>
<p><a href="https://github.com/community/community/discussions/9584?sort=top?sort=top">https://github.com/community/community/discussions/9584?sort=top?sort=top</a></p>
<p>Last but not least by using GitHub copilot you agree to the ToS which clearly states</p>
<pre tabindex="0"><code>GitHub Copilot gives you certain choices about how it uses the data it collects. User engagement data, including pseudonymous identifiers and general usage data, is required for the use of GitHub Copilot and will continue to be collected, processed, and shared with Microsoft and OpenAI as you use GitHub Copilot. You can choose whether your code snippets are collected and retained by GitHub and further processed and shared with Microsoft and OpenAI by adjusting your user settings.
</code></pre><h1 id="conclusion">Conclusion</h1>
<p>I personally don’t use or will ever use GitHub Copilot or recommend it to anyone for the following reasons:</p>
<ol>
<li>Doesn&rsquo;t help you learn. Instead does the opposite.</li>
<li>Recommends other peoples’ phone numbers, emails and even aws keys. No features have been implemented to stop this as far as I know.</li>
<li>Tracks your usage and collects a lot of data. Like Source code that you are editing, related files and other files open in the same IDE or editor, URLs of repositories and files paths.</li>
<li>Is paid and proprietary. (You pay to be tracked)</li>
<li>Monetizes Open Source Software in an unethical way.</li>
<li><a href="https://cyber.nyu.edu/2021/10/15/ccs-researchers-find-github-copilot-generates-vulnerable-code-40-of-the-time/">Github CoPilot generates vulnerable code 40% of the time</a></li>
</ol>
<p>PS if you don’t want GitHub to legally index your code, you could try one of these <a href="https://github.com/big-tech-sux/resistant-licenses">licenses</a> They might work</p>
<p>***If you enjoyed this article consider <a href="https://4rkal.com/donate">supporting me</a></p>
<div style="text-align: left; margin: 0 auto;">
    <form method="post" action="https://newsletter.4rkal.com/subscription/form" style="background: #2c2c2c; color: #f0f0f0; border-radius: 8px; padding: 15px; max-width: 500px; box-shadow: 0 3px 6px rgba(0, 0, 0, 0.2); font-family: Arial, sans-serif;">
        <div style="display: flex; flex-direction: column; gap: 10px;">
            <h3 style="margin: 0; color: #f0f0f0; font-size: 18px;">Subscribe</h3>
            <input type="hidden" name="nonce"/>
            <input type="email" name="email" required placeholder="E-mail" style="width: 100%; padding: 10px; border: 1px solid #666; border-radius: 4px; background: #333; color: #f0f0f0; box-sizing: border-box;"/>
            <div style="display: flex; flex-direction: column; gap: 8px;">
                <label style="margin: 0; color: #f0f0f0; display: none;">
                    <input id="78a75" type="checkbox" name="l" checked value="78a75b30-472d-4790-a5d5-7f2ed49662a4" style="accent-color: #fff;"/>
                    Weekly Roundup
                </label>
                <span style="color: #d0d0d0; display: none;">Where I share what I’ve been up to that week, including articles I’ve published, cool finds, tips and tricks, and more!</span>
                <label style="margin: 0; color: #f0f0f0; display: none;">
                    <input id="b3964" type="checkbox" name="l" checked value="b3964560-37b0-43d3-9df9-26589fd6bf8d" style="accent-color: #fff;"/>
                    New Posts
                </label>
                <span style="color: #d0d0d0; display: none;">Receive an email every time I post something new on my blog</span>
            </div>
            <input type="submit" value="Subscribe" style="width: 100%; padding: 10px; border: none; border-radius: 4px; background: #fff; color: #007bff; font-size: 14px; cursor: pointer; transition: background-color 0.3s ease, box-shadow 0.3s ease; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);"/>
        </div>
        <p style="text-align: center; margin-top: 10px; color: #d0d0d0; font-size: 10px; margin-bottom:0px;">
            No spam, no ads. Unsubscribe at any time.
        </p>
    </form>
</div>]]></content:encoded>
    </item>
    
    <item>
      <title>How to Set Up Your Own Git Server: A Simple Guide</title>
      <link>https://4rkal.com/posts/git/</link>
      <pubDate>Sun, 05 Mar 2023 17:11:40 +0300</pubDate>
      
      <guid>https://4rkal.com/posts/git/</guid>
      <description>Thinking about setting up your own Git server? There are plenty of perks to doing so instead of relying on platforms like GitHub. For starters, you&amp;rsquo;ll have complete control over your code, ensuring it can’t be used for profit or deleted by anyone but you.
What You’ll Need A Computer for Your Server: Ideally running Linux (Debian is a solid choice). Internet Connection: Pretty essential for accessing your server remotely. Another Computer with Git Installed: This is what you&amp;rsquo;ll use to interact with your server.</description>
      <content:encoded><![CDATA[<p>Thinking about setting up your own Git server? There are plenty of perks to doing so instead of relying on platforms like GitHub. For starters, you&rsquo;ll have complete control over your code, ensuring it can’t be used for profit or deleted by anyone but you.</p>
<h3 id="what-youll-need">What You’ll Need</h3>
<ol>
<li><strong>A Computer for Your Server</strong>: Ideally running Linux (Debian is a solid choice).</li>
<li><strong>Internet Connection</strong>: Pretty essential for accessing your server remotely.</li>
<li><strong>Another Computer with Git Installed</strong>: This is what you&rsquo;ll use to interact with your server.</li>
</ol>
<h3 id="step-by-step-setup-guide">Step-by-Step Setup Guide</h3>
<h4 id="1-install-git-on-your-server">1. Install Git on Your Server</h4>
<p>First, you need to install Git on your server. Depending on your Linux distribution, use one of these commands:</p>
<ul>
<li>For Debian-based systems (like Ubuntu):
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sudo apt install git
</span></span></code></pre></div></li>
<li>For Fedora-based systems:
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sudo dnf install git
</span></span></code></pre></div></li>
<li>For Arch-based systems:
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sudo pacman -S git
</span></span></code></pre></div></li>
</ul>
<h4 id="2-create-a-git-user">2. Create a Git User</h4>
<p>Next, create a dedicated user for Git operations:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sudo useradd git
</span></span></code></pre></div><p>You&rsquo;ll be prompted to enter some information. Feel free to leave everything blank except for the password.</p>
<h4 id="3-secure-your-server-with-ssh-keys">3. Secure Your Server with SSH Keys</h4>
<p>Log in as the new Git user:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>su git
</span></span></code></pre></div><p>Then, enhance security by setting up SSH keys:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>mkdir .ssh
</span></span><span style="display:flex;"><span>chmod <span style="color:#ae81ff">700</span> .ssh/
</span></span><span style="display:flex;"><span>touch .ssh/authorized_keys
</span></span><span style="display:flex;"><span>chmod <span style="color:#ae81ff">600</span> .ssh/authorized_keys
</span></span></code></pre></div><h4 id="4-generate-and-add-ssh-keys">4. Generate and Add SSH Keys</h4>
<p>On your main machine (the one you’ll be committing from), generate an SSH key:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>ssh-keygen
</span></span></code></pre></div><p>Copy the SSH public key to your server:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>ssh-copy-id git@your-server-ip
</span></span></code></pre></div><p>To find your server&rsquo;s IP, use:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>ifconfig
</span></span></code></pre></div><p>Now, you should be able to log in to your server without needing a password:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>ssh git@your-server-ip
</span></span></code></pre></div><h4 id="5-set-up-your-git-repository-directory">5. Set Up Your Git Repository Directory</h4>
<p>Create a directory to store your Git repositories. For example:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>mkdir ~/git
</span></span></code></pre></div><p>Give ownership of this directory to the Git user:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>chown git:git ~/git
</span></span></code></pre></div><h4 id="6-create-a-new-repository">6. Create a New Repository</h4>
<p>For each project, create a separate directory:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>mkdir ~/git/my_cool_project.git
</span></span></code></pre></div><p>Initialize the repository as a bare repository (suitable for sharing):</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>cd ~/git/my_cool_project.git
</span></span><span style="display:flex;"><span>git init --bare
</span></span></code></pre></div><h4 id="7-test-your-setup">7. Test Your Setup</h4>
<p>To test your new Git server, try cloning the repository from another machine:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>git clone git@your-server-ip:~/git/my_cool_project.git
</span></span></code></pre></div><p>You might see:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>warning: You appear to have cloned an empty repository.
</span></span></code></pre></div><p>That’s because you haven’t added any files yet. Go ahead and add a file:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>touch stuff.txt
</span></span></code></pre></div><p>Commit your changes:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>git add .
</span></span><span style="display:flex;"><span>git commit -m <span style="color:#e6db74">&#34;first commit&#34;</span>
</span></span></code></pre></div><p>Now, try cloning again, and everything should work smoothly.</p>
<h3 id="congratulations">Congratulations!</h3>
<p>You’ve successfully set up your own Git server! Now you have full control over your code and can collaborate without relying on third-party services.</p>
<p><em>Enjoyed this guide? Consider <a href="https://4rkal.com/donate">supporting me</a> to help me create more content like this!</em></p>
<div style="text-align: left; margin: 0 auto;">
    <form method="post" action="https://newsletter.4rkal.com/subscription/form" style="background: #2c2c2c; color: #f0f0f0; border-radius: 8px; padding: 15px; max-width: 500px; box-shadow: 0 3px 6px rgba(0, 0, 0, 0.2); font-family: Arial, sans-serif;">
        <div style="display: flex; flex-direction: column; gap: 10px;">
            <h3 style="margin: 0; color: #f0f0f0; font-size: 18px;">Subscribe</h3>
            <input type="hidden" name="nonce"/>
            <input type="email" name="email" required placeholder="E-mail" style="width: 100%; padding: 10px; border: 1px solid #666; border-radius: 4px; background: #333; color: #f0f0f0; box-sizing: border-box;"/>
            <div style="display: flex; flex-direction: column; gap: 8px;">
                <label style="margin: 0; color: #f0f0f0; display: none;">
                    <input id="78a75" type="checkbox" name="l" checked value="78a75b30-472d-4790-a5d5-7f2ed49662a4" style="accent-color: #fff;"/>
                    Weekly Roundup
                </label>
                <span style="color: #d0d0d0; display: none;">Where I share what I’ve been up to that week, including articles I’ve published, cool finds, tips and tricks, and more!</span>
                <label style="margin: 0; color: #f0f0f0; display: none;">
                    <input id="b3964" type="checkbox" name="l" checked value="b3964560-37b0-43d3-9df9-26589fd6bf8d" style="accent-color: #fff;"/>
                    New Posts
                </label>
                <span style="color: #d0d0d0; display: none;">Receive an email every time I post something new on my blog</span>
            </div>
            <input type="submit" value="Subscribe" style="width: 100%; padding: 10px; border: none; border-radius: 4px; background: #fff; color: #007bff; font-size: 14px; cursor: pointer; transition: background-color 0.3s ease, box-shadow 0.3s ease; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);"/>
        </div>
        <p style="text-align: center; margin-top: 10px; color: #d0d0d0; font-size: 10px; margin-bottom:0px;">
            No spam, no ads. Unsubscribe at any time.
        </p>
    </form>
</div>]]></content:encoded>
    </item>
    
    <item>
      <title>Host your own private search engine — searX</title>
      <link>https://4rkal.com/posts/searx/</link>
      <pubDate>Fri, 03 Mar 2023 23:21:53 +0300</pubDate>
      
      <guid>https://4rkal.com/posts/searx/</guid>
      <description>We rely on google more and more, but it’s interesting to know how much data Google is now handling. Alphabet aka Google describes its extensive data collection practices in its privacy policy. The company stores an astounding quantity of data. An estimated 15 exabytes of YOUR data are stored by Google. Google is tracking your every move.
What is searX? Searx is a free and open-source metasearch engine, available under the GNU Affero General Public License version 3, with the aim of protecting the privacy of its users.</description>
      <content:encoded><![CDATA[<p>We rely on google more and more, but it’s interesting to know how much data Google is now handling. Alphabet aka Google describes its extensive data collection practices in its privacy policy. The company stores an astounding quantity of data. An estimated 15 exabytes of YOUR data are stored by Google. Google is tracking your every move.</p>
<h2 id="what-is-searx">What is searX?</h2>
<p>Searx is a free and open-source metasearch engine, available under the GNU Affero General Public License version 3, with the aim of protecting the privacy of its users. In order to do this, Searx does not provide the search engines from which it receives results with users’ IP addresses or search histories. Tracking cookies served by the search engines are blocked, preventing user-profiling-based results modification.</p>
<p>Users can run private instances of Searx on their own computer, but there are also many public, user-run, Searx instances.</p>
<p>In this article i will show you how to run your own searX instance.</p>
<h2 id="what-is-a-metasearch-engine">What is a metasearch engine?</h2>
<p>A web search engine’s data is used by a metasearch engine, an online information retrieval tool, to create its own results. Metasearch engines automatically query search engines eg Google after receiving user input. The users are shown sufficient data that has been gathered, sorted, and presented.</p>
<h2 id="requirements">Requirements</h2>
<ol>
<li>An computer (preferably running linux). Check out my article on how to install linux here <a href="https://4rkal.medium.com/install-a-debian-server-54add9133eec">https://4rkal.medium.com/install-a-debian-server-54add9133eec</a></li>
<li>an internet connection</li>
</ol>
<h2 id="installing-on-windows">Installing on windows</h2>
<p>To install on windows you will have to install wsl and follow the setup guide for linux bellow</p>
<p>To see how to install wsl head to <a href="https://docs.microsoft.com/en-us/windows/wsl/install">https://docs.microsoft.com/en-us/windows/wsl/install</a></p>
<h2 id="installing-on-linux-debian">Installing on Linux (debian)</h2>
<p>First update your system
<code>sudo apt-get update &amp;&amp; sudo apt-get upgrade</code>
Now install required packages
<code>sudo apt install -y python3-dev python3-babel python3-venv uwsgi uwsgi-plugin-python3 git build-essential libxslt-dev zlib1g-dev libffi-dev libssl-dev </code>
Now you will have to create a new user called searx</p>
<pre tabindex="0"><code>sudo -H useradd --shell /bin/bash --system \
    --home-dir &#34;/usr/local/searx&#34; \
    --comment &#39;Privacy-respecting metasearch engine&#39; searx

sudo -H mkdir &#34;/usr/local/searx&#34;
sudo -H chown -R &#34;searx:searx&#34; &#34;/usr/local/searx&#34;
</code></pre><p>Now change user to searx</p>
<p><code>git clone &quot;https://github.com/searx/searx.git&quot; &quot;/usr/local/searx/searx-src&quot;t</code></p>
<p>Now create a virtual environment</p>
<p><code>echo &quot;. /usr/local/searx/searx-pyenv/bin/activate&quot; &gt;&gt;  &quot;/usr/local/searx/.profile&quot;</code></p>
<p>To install searx’s dependencies, exit the searx bash session you opened above and restart a new. Before install, first check if your virtualenv was sourced from the login (~/.profile):</p>
<p>Update dependencies</p>
<pre tabindex="0"><code>pip install -U pip
pip install -U setuptools
pip install -U wheel
pip install -U pyyaml
</code></pre><p>Jump to searx’s working tree and install searx into virtualenv</p>
<pre tabindex="0"><code>cd &#34;/usr/local/searx/searx-src&#34;
pip install -e .
</code></pre><p>Now go back to your default user</p>
<p><code>exit</code></p>
<p>And type
<code>sudo -H mkdir -p &quot;/etc/searx&quot;</code></p>
<p>Then</p>
<pre tabindex="0"><code>sudo -H cp &#34;/usr/local/searx/searx-src/utils/templates/etc/searx/use_default_settings.yml&#34; \
             &#34;/etc/searx/settings.yml&#34;
</code></pre><p>Now you can edit your settings file</p>
<p><code>sudo nano /etc/searx/settings.yml</code></p>
<p>You can change the secret_key</p>
<p>I will change the port and bind_address but you can change whatever you want.</p>
<p>Now log back in to your searx user</p>
<p><code>sudo -H -u searx -i</code></p>
<p>Change directory</p>
<p><code>cd /usr/local/searx/searx-src</code></p>
<p>Export the settings path</p>
<pre tabindex="0"><code>export 
SEARX_SETTINGS_PATH=&#34;/etc/searx/settings.yml&#34;
</code></pre><p>Finally run the web app
<code>python searx/webapp.py</code>
Now if you head to 127.0.0.1:8888 you should be able to see something like this
<img loading="lazy" src="/../assets/searx.webp" type="" alt="1"  />
<strong>GG</strong> you did it enjoy privacy (in search engines)</p>
<p>*<strong>If you enjoyed this article consider <a href="../../donate">supporting me</a></strong></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Become anonymous and somewhat untraceable with tails os</title>
      <link>https://4rkal.com/posts/tails/</link>
      <pubDate>Fri, 03 Mar 2023 23:03:40 +0300</pubDate>
      
      <guid>https://4rkal.com/posts/tails/</guid>
      <description>In this article we will talk about what tails is and how to install and more.
What is tails? Tails, or The Amnesic Incognito Live System, is a security-focused Debian-based Linux distribution aimed at preserving privacy and anonymity.It connects to the Internet exclusively through the anonymity network Tor. The system is designed to be booted as a live DVD or live USB, and leaves no digital footprint on the machine unless explicitly told to do so.</description>
      <content:encoded><![CDATA[<p>In this article we will talk about what tails is and how to install and more.</p>
<h1 id="what-is-tails">What is tails?</h1>
<p>Tails, or The Amnesic Incognito Live System, is a security-focused Debian-based Linux distribution aimed at preserving privacy and anonymity.It connects to the Internet exclusively through the anonymity network Tor. The system is designed to be booted as a live DVD or live USB, and leaves no digital footprint on the machine unless explicitly told to do so.</p>
<h1 id="what-is-the-tor-network">What is the tor network?</h1>
<p>Tor, short for The Onion Router, is free and open-source software for enabling anonymous communication. It directs Internet traffic through a free, worldwide, volunteer overlay network, consisting of more than six thousand relays,to conceal a user’s location and usage from anyone performing network surveillance or traffic analysis. Using Tor makes it more difficult to trace a user’s Internet activity.</p>
<h1 id="who-is-tails-intended-for">Who is tails intended for?</h1>
<p>As the tails website states (<a href="https://tails.net">https://tails.net</a>). Tails is intended for Activists who use Tails to hide their identities, avoid censorship, and communicate securely. Journalists and their sources use Tails to publish sensitive information and access the Internet from unsafe places. Domestic violence survivors use Tails to escape surveillance at home. You whenever you need extra privacy in this digital world.</p>
<h1 id="requirements">Requirements</h1>
<ol>
<li>A computer (minimum of 2GB ram , 64-bit x86–64 compatible processor)</li>
<li>A usb stick with 8GB+ of space</li>
</ol>
<p>Read more <a href="https://tails.boum.org/doc/about/requirements/index.en.html">https://tails.boum.org/doc/about/requirements/index.en.html</a></p>
<h1 id="installation">Installation</h1>
<p>Back up all your files USB files as they will get deleted!</p>
<p>The first thing you will have to do is to head to <a href="https://tails.boum.org/install/index.en.html">https://tails.boum.org/install/index.en.html</a>
Now select your operating system</p>
<p>Ill walk you through the installation for windows and linux.
This should probably bethe same with linux
After you have clicked on the windows logo you should be prompted with the requirements and a step by step guide.</p>
<p>The first thing you will have to do is to download the tails usb image.</p>
<p>After that i highly recommend that you verify your download</p>
<p>Just click on select and select it.</p>
<p>Now you will have to download balena etcher. Just click on download balena etcher and double click the installer.</p>
<p>At this moment plug in your usb (if you have any important files on the usb you have to back the up or they will be lost)</p>
<p>Now click the flash from file button and select the file you downloaded (it ends in .img)</p>
<p>Click the Select target button to select your USB stick.</p>
<p>And now select flash.</p>
<p>This could take a while so just sit back and relax.</p>
<h1 id="using-tails">Using tails</h1>
<p>After your installation is finished just reboot your computer and hit F12 or F2 depending on your computer.</p>
<p>Now you should see a screen thats says something like please select your boot device. You will have to select your usb and hit enter</p>
<p>Now you should see the grub loader</p>
<p>Select Tails and hit enter</p>
<p>Now you should be booted into tails</p>
<p>You will probably see a screen that looks something like this</p>
<p><img loading="lazy" src="/../assets/tails.webp" type="" alt=""  /></p>
<p>Here you will have to set your language and region. We can also press on the + icon to add a admin password mac address anonymization etc. I will just put the admin password and the unsafe browser. You can select anything you want. However remember that changing some of these settings will make you less anonymous.</p>
<p>Once you are ready select start tails</p>
<p>Now you will see</p>
<p><img loading="lazy" src="/../assets/tails2.webp" type="" alt=""  /></p>
<p>Here you can select anything you want. I will just select the first option.</p>
<p>Now you should see this:</p>
<p><img loading="lazy" src="/../assets/tails3.webp" type="" alt=""  /></p>
<p>GG you did it. One more step though</p>
<p>I like to have a persistent volume so that i don’t lose all my files when i reboot. To do that open the configure persistent volume app and follow the steps there.</p>
<p>That’s it for now</p>
<p>*<strong>If you enjoyed this article consider <a href="../../donate">supporting me</a></strong></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Get ad free web with Pi-hole</title>
      <link>https://4rkal.com/posts/pihole/</link>
      <pubDate>Sat, 25 Feb 2023 21:17:13 +0300</pubDate>
      
      <guid>https://4rkal.com/posts/pihole/</guid>
      <description>In this article, I will show you how to set up Pi-hole. Pi-hole will allow you to block in-app ads, improve your network&amp;rsquo;s performance, and monitor statistics. Pi-hole also allows you to create a VPN.
What is Pi-hole? Pi-hole is a Linux network-level advertisement and Internet tracker blocking application that acts as a DNS sinkhole and optionally a DHCP server, intended for use on a private network. It is designed for low-power embedded devices with network capability, such as the Raspberry Pi, but can be installed on any Linux machine.</description>
      <content:encoded><![CDATA[<p>In this article, I will show you how to set up Pi-hole. Pi-hole will allow you to block in-app ads, improve your network&rsquo;s performance, and monitor statistics. Pi-hole also allows you to create a VPN.</p>
<h1 id="what-is-pi-hole">What is Pi-hole?</h1>
<p>Pi-hole is a Linux network-level advertisement and Internet tracker blocking application that acts as a DNS sinkhole and optionally a DHCP server, intended for use on a private network. It is designed for low-power embedded devices with network capability, such as the Raspberry Pi, but can be installed on any Linux machine. Pi-hole has the ability to block traditional website advertisements as well as advertisements in unconventional places, such as smart TVs and mobile operating system advertisements.</p>
<h1 id="requirements">Requirements</h1>
<ol>
<li>A computer with Linux (preferably something Debian-based)</li>
<li>Preferably an Ethernet cable</li>
<li>Access to your router&rsquo;s admin portal</li>
<li>A static IP</li>
<li>An internet connection (it&rsquo;s pretty difficult without one, trust me)</li>
</ol>
<h1 id="installation">Installation</h1>
<p>The first thing we have to do is download the installer.</p>
<p>To do that, type:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>wget -O basic-install.sh https://install.pi-hole.net
</span></span></code></pre></div><p>Now, install it with:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sudo bash basic-install.sh
</span></span></code></pre></div><p>Now you should see something like this:</p>
<p><img loading="lazy" src="/../assets/pihole/1.webp" type="" alt="Installation Step 1"  /></p>
<p>Just press OK.</p>
<p><img loading="lazy" src="/../assets/pihole/2.webp" type="" alt="Installation Step 2"  /></p>
<p>Just press OK again.</p>
<p>As I said before, you have to have a static IP in order to set up the Pi-hole, so if you have one configured, just press Yes.</p>
<p><img loading="lazy" src="/../assets/pihole/3.webp" type="" alt="Static IP Setup"  /></p>
<p>Otherwise, you will have to set one up.</p>
<p>Now you will be prompted to select your upstream DNS provider. You can select any of the DNS providers on the list. I will just select Google.</p>
<p><img loading="lazy" src="/../assets/pihole/4.webp" type="" alt="DNS Provider Selection"  /></p>
<p>And press OK.</p>
<p>After that, you will have to select your list. I will just select the default one.</p>
<p><img loading="lazy" src="/../assets/pihole/5.webp" type="" alt="List Selection"  /></p>
<p>Now you will have to select whether you want a web admin interface. Select On and then OK.</p>
<p><img loading="lazy" src="/../assets/pihole/6.webp" type="" alt="Web Admin Interface"  /></p>
<p>Now just select On and press OK.</p>
<p><img loading="lazy" src="/../assets/pihole/7.webp" type="" alt="Web Admin Interface Confirmation"  /></p>
<p>After that, you can select if you want to log queries. You can select any option you want.</p>
<p><img loading="lazy" src="/../assets/pihole/8.webp" type="" alt="Log Queries"  /></p>
<p>Now, I recommend that you leave this as default, but you don’t have to.</p>
<p><img loading="lazy" src="/../assets/pihole/9.webp" type="" alt="Default Settings"  /></p>
<p>Now it should start installing everything.</p>
<p>After the installation is finished, you should see something like this:</p>
<p><img loading="lazy" src="/../assets/pihole/10.webp" type="" alt="Installation Complete"  /></p>
<p>You have now successfully installed Pi-hole. You can head to the admin portal by going to the specified IP.</p>
<p>To be able to use Pi-hole, you have two options:</p>
<ol>
<li>Make the IP the default DNS for your whole network</li>
<li>Manually add it on any device</li>
</ol>
<p>I&rsquo;ll go with the second option.</p>
<h3 id="on-windows">On Windows:</h3>
<p>DNS settings are specified in the TCP/IP Properties window for the selected network connection.</p>
<ol>
<li>Go to the Control Panel</li>
<li>Click Network and Internet &gt; Network and Sharing Center &gt; Change adapter settings</li>
<li>Select the connection for which you want to configure</li>
<li>Right-click Local Area Connection &gt; Properties</li>
<li>Select the Networking tab</li>
<li>Select Internet Protocol Version 4 (TCP/IPv4) or Internet Protocol Version 6 (TCP/IPv6)</li>
<li>Click Properties</li>
<li>Click Advanced</li>
<li>Select the DNS tab</li>
<li>Click OK</li>
<li>Select Use the following DNS server addresses</li>
<li>Replace those addresses with the IP addresses of your Pi</li>
<li>Restart the connection you selected in step 3</li>
<li>Repeat the procedure for additional network connections you want to change</li>
</ol>
<h3 id="on-linux">On Linux:</h3>
<p>In most modern Linux distributions, DNS settings are configured through Network Manager.</p>
<ol>
<li>Click System &gt; Preferences &gt; Network Connections</li>
<li>Select the connection for which you want to configure and press <strong>Edit</strong></li>
<li>Select the IPv4 Settings or IPv6 Settings tab</li>
<li>If the selected method is Automatic (DHCP), open the dropdown and select Automatic (DHCP) addresses only instead. If the method is set to something else, do not change it.</li>
<li>In the DNS servers field, enter your Pi’s IP addresses</li>
<li>Click Apply to save the changes</li>
</ol>
<blockquote>
<p><strong>Warning:</strong> If you are not using Network Manager, your DNS settings are specified in <code>/etc/resolv.conf</code>.</p>
</blockquote>
<p>Now, if we head over to any websites with ads, you should see that no ads appear.</p>
<p>Let&rsquo;s try speedtest.net.</p>
<p>If you have followed the steps correctly, you should see something like this:</p>
<p><img loading="lazy" src="/../assets/pihole/ads.webp" type="" alt="No Ads!"  /></p>
<p><strong>NO ADS</strong></p>
<p>Enjoy the ad-free web.</p>
<p><em><strong>If you enjoyed this article, consider <a href="../../donate">supporting me</a>.</strong></em></p>
<pre tabindex="0"><code></code></pre>]]></content:encoded>
    </item>
    
    <item>
      <title>Securing ssh with Key-Based authentication</title>
      <link>https://4rkal.com/posts/sssh/</link>
      <pubDate>Sat, 25 Feb 2023 21:08:47 +0300</pubDate>
      
      <guid>https://4rkal.com/posts/sssh/</guid>
      <description>SSH keys provide an extremely secure way of logging into your server.
SSH Password Based VS Key Based Authentication Clients can be authenticated by an SSH server in a variety of ways. The most basic is password authentication, which is simple to use but not particularly secure. The more advanced and secure way is via ssh keys.Brute-forcing a password-protected account is quite possible thanks to modern computing power and automated scripts.</description>
      <content:encoded><![CDATA[<p>SSH keys provide an extremely secure way of logging into your server.</p>
<h1 id="ssh-password-based-vs-key-based-authentication">SSH Password Based VS Key Based Authentication</h1>
<p>Clients can be authenticated by an SSH server in a variety of ways. The most basic is password authentication, which is simple to use but not particularly secure. The more advanced and secure way is via ssh keys.Brute-forcing a password-protected account is quite possible thanks to modern computing power and automated scripts. The solution to that is ssh key based authentication.</p>
<h1 id="how-does-key-based-authentication-work">How does Key Based Authentication work?</h1>
<p>SSH key pairs are two cryptographically secure keys that allow a client to connect to an SSH server. A public key and a private key make up each key pair.The client keeps the private key, which should be kept completely confidential.</p>
<p>If the attacker has access to the private key, they will be able to enter into servers using the corresponding public key without requiring further authentication. A passphrase can be used to encrypt the key on disc as an extra precaution.</p>
<p>The related public key can be freely shared without causing any harm. The public key can be used to encrypt communications that can only be decrypted with the private key. This attribute is used to verify the authenticity of the key pair. The public key is placed on a distant server that you wish to use SSH to access. The key is saved in a special file called /.ssh/authorized keys in the user account you’ll be login into.</p>
<p>When a client uses SSH keys to authenticate, the server can check if the client has the private key. A shell session is started or the requested command is executed if the client can verify ownership of the private key.</p>
<h1 id="setting-up">Setting up</h1>
<p>The first thing we will have to to do is generate an SSH key pair on your local computer.</p>
<p>To do that type</p>
<p><code>ssh-keygen</code></p>
<p>You should see something like this</p>
<pre tabindex="0"><code>Generating public/private rsa key pair.
Enter file in which to save the key (/home/4rkal/.ssh/id_rsa): 
Enter passphrase (empty for no passphrase):
</code></pre><p>If you want to you can enter a passphrase to encrypt the private key.</p>
<p>After that your key should be generated.</p>
<p>Now you will have to copy your public key to your server.</p>
<p>To do that type</p>
<p><code>ssh-copy-id username@host_ip</code></p>
<p>(find your servers ip by typing ifconfig in your server)</p>
<p>eg.</p>
<p>`ssh-copy-id <a href="mailto:server@192.168.1.13">server@192.168.1.13</a>'</p>
<p>Try to ssh into your server by typing</p>
<p><code>ssh username@host_ip</code></p>
<p>You should be able to login into your server without the password. However, brute force attacks continue to threaten your server. Now we have to disable password based authentication.</p>
<p>First login to your ssh server by typing
<code>ssh username@host_ip</code></p>
<p>Now we have edit the ssh config</p>
<p>sudo nano /etc/ssh/sshd_config</p>
<p>You should see a large file that starts with</p>
<pre tabindex="0"><code>#       $OpenBSD: sshd_config,v 1.103 2018/04/09 20:41:22 tj Exp $
</code></pre><p>At this point press cntrl w and search for <code>PasswordAuthentication</code></p>
<p>Uncomment the line that says</p>
<p><code>#PasswordAuthentication yes</code></p>
<p>And change it to</p>
<p><code>PasswordAuthentication no</code></p>
<p>Now press cntrl s to save and cntrl x to exit</p>
<p>After that restart the ssh service with</p>
<p><code>sudo service ssh restart</code></p>
<p>Now try to ssh into your server from another machine or a vm and you should see something like this</p>
<p><code>server@192.168.1.13: Permission denied (publickey)</code></p>
<p>GG you have now secured your server</p>
<p>*<strong>If you enjoyed this article consider <a href="../../donate">supporting me</a></strong></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Setup a tor website (hidden service)</title>
      <link>https://4rkal.com/posts/torhs/</link>
      <pubDate>Sat, 25 Feb 2023 20:56:02 +0300</pubDate>
      
      <guid>https://4rkal.com/posts/torhs/</guid>
      <description>In this article i will be showing you how to host your “dark web” aka Tor website for free.
What is Tor? Tor — short for the Onion Routing project — is an open-source privacy network that enables anonymous web browsing. The worldwide Tor computer network uses secure, encrypted protocols to ensure that users’ online privacy is protected. Tor users’ digital data and communications are shielded using a layered approach that resembles the nested layers of an onion.</description>
      <content:encoded><![CDATA[<p>In this article i will be showing you how to host your “dark web” aka Tor website for free.</p>
<h1 id="what-is-tor">What is Tor?</h1>
<p>Tor — short for the Onion Routing project — is an open-source privacy network that enables anonymous web browsing. The worldwide Tor computer network uses secure, encrypted protocols to ensure that users’ online privacy is protected. Tor users’ digital data and communications are shielded using a layered approach that resembles the nested layers of an onion.</p>
<h1 id="why-use-tor">Why use Tor?</h1>
<p>Tor is useful for anyone who wants to keep their internet activities out of the hands of advertisers, ISPs, and websites. That includes people getting around censorship restrictions in their country, people looking to hide their IP address, or anyone else who doesn’t want their browsing habits linked to them.</p>
<p>The Tor network may also host webpages that only other Tor users can view. In other words, you’ve entered the Dark Web, which consists of websites that aren’t indexed by the standard crawlers you use to look for products to purchase, and quiz answers etc . On the Dark Web, you can discover everything from free textbooks to drugs — and worse — as long as you know the secret URL that leads to these sites.</p>
<h1 id="tor-websites">Tor Websites</h1>
<p>Just like any other website, you will need to know the address of an onion service in order to connect to it. An onion address is a string of 56 mostly random letters and numbers, followed by “.onion”.</p>
<h1 id="requirements">Requirements</h1>
<ol>
<li>A linux machine (debian preferably)</li>
<li>An internet connection (pretty hard without one,trust me)</li>
</ol>
<h1 id="installation">Installation</h1>
<p>The first thing we will have to do is install Tor</p>
<p><code>apt install tor</code></p>
<p>Now we will have to enable tor hidden service(which is the website) for that type:</p>
<p><code>sudo nano /etc/tor/torrc</code></p>
<p>You should see a large configuration file, search for <code>HiddenService</code></p>
<p>You will have to uncoment:</p>
<pre tabindex="0"><code>#HiddenServiceDir /var/lib/tor/hidden_service/
#HiddenServicePort 80 127.0.0.1:80
</code></pre><p>Now press cntrl s and then cntrl x to exit</p>
<p>After that start the tor service by running</p>
<p><code>sudo service tor start</code></p>
<p>or</p>
<p><code>sudo systemctl start tor</code></p>
<p>Now we also have to install nginx to be able to run our website to do that type</p>
<p><code>sudo apt install nginx</code></p>
<p>Start the nginx service with the systemctl or service command</p>
<p>Now we also have to install nginx to be able to run our website to do that type</p>
<p><code>sudo cat /var/lib/tor/hidden_service/hostname</code></p>
<p>You should see a address that looks something like this</p>
<p><code>tiur7p652svsaemdewbsxnnkrj3b35ny2rx454od5wk5ivfqhijm2qd.onion</code></p>
<p>Now open your tor browser and paste your address and press enter.</p>
<p>You will most probably be greeted by the default nginx site.</p>
<p>This page is easily customized, you can check out my article:
<a href="https://4rkal.com/posts/shwebsite/">here</a></p>
<p>GG you did it you are now running a pretty anonymous website on the tor network.</p>
<p>*<strong>If you enjoyed this article consider <a href="../../donate">supporting me</a></strong></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>The importance of open source software</title>
      <link>https://4rkal.com/posts/opensource/</link>
      <pubDate>Sat, 25 Feb 2023 20:43:23 +0300</pubDate>
      
      <guid>https://4rkal.com/posts/opensource/</guid>
      <description>As the linuxfoundation states about 95% of cloud providers run kubernetes which is an open sourced solution, the Apache Web server powers millions of websites including netflix.com, spotify.com and more. Most of the Internets core functions are based on open source technology. But what is it and why is it so important?
What is open sourced software? Open-source software is computer software that is distributed under a license that allows users to use, study, modify and distribute the program and its source code to anyone and for any purpose.</description>
      <content:encoded><![CDATA[<p>As the linuxfoundation states about 95% of cloud providers run kubernetes which is an open sourced solution, the Apache Web server powers millions of websites including netflix.com, spotify.com and more. Most of the Internets core functions are based on open source technology. But what is it and why is it so important?</p>
<h2 id="what-is-open-sourced-software">What is open sourced software?</h2>
<p>Open-source software is computer software that is distributed under a license that allows users to use, study, modify and distribute the program and its source code to anyone and for any purpose. Open-source software may be created in a public, collaborative environment. Open-source software is a good example of open collaboration since it allows any skilled user to engage in development online.</p>
<p>&ldquo;Certainly there’s a phenomenon around open source. You know free software will be a vibrant area. There will be a lot of neat things that get done there.&rdquo;
-Bill Gates</p>
<h2 id="why-open-source">Why open source?</h2>
<p>There are several advantages to using open-source software.</p>
<ol>
<li>
<p><strong>Trust</strong>. One of the most important advantages is trust. As users can examine your code and make sure its not doing anything they don’t want it to. They are also able to change things they don’t like. Most cryptocurrency projects are open sourced to be able to develop trust with their community.</p>
</li>
<li>
<p><strong>Community</strong> A open source community allows more developers to build around the project . Bitcoin is the greatest example of such a community. As soon as bitcoin source code was published many utilities for bitcoin were made like wallets and more which would never have been made if bitcoin wasn’t open sourced.</p>
</li>
<li>
<p><strong>Transparency</strong> Anyone can read your source code and see if they want it to do what it is doing. That way your company gains a lot of trust.</p>
</li>
</ol>
<p>&ldquo;Talk is cheap show me the code&rdquo;
Linus Torvalds</p>
<ol start="4">
<li>
<p><strong>Continuous evolution</strong> Your project will continue to be developed even if you give up on it. Again the greatest example for this kind of project is bitcoin. Even though the founder of bitcoin has vanished for more than 10 years, cryptocurrency technology is &ldquo;changing&rdquo; the world.</p>
</li>
<li>
<p><strong>Lower Development costs</strong> (For companies) You can reduce your costs by using open source software. You can save money on licensing and maintenance. The only costs you’d have to deal with are those for documentation, media, support etc.</p>
</li>
<li>
<p><strong>Controll</strong> With open source YOU are ultimately in controll. If you dont like something you can modify the source code to your liking.</p>
</li>
</ol>
<p><em><strong>If you enjoyed this article consider <a href="../../donate">supporting me</a></strong></em></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Self host your own website</title>
      <link>https://4rkal.com/posts/shwebsite/</link>
      <pubDate>Sat, 25 Feb 2023 20:23:16 +0300</pubDate>
      
      <guid>https://4rkal.com/posts/shwebsite/</guid>
      <description>In this article i will show you how to self host your own website securely.
Requirements A computer or microcomputer to host the website The computer needs to run linux An internet connection (Its pretty hard without one, trust me) Lets get started!
Installation The first thing that we will have to do is setup our nginx site.
We first have to be root
sudo su
If you dont have sudo installed try:</description>
      <content:encoded><![CDATA[<p>In this article i will show you how to self host your own website securely.</p>
<h1 id="requirements">Requirements</h1>
<ol>
<li>A computer or microcomputer to host the website</li>
<li>The computer needs to run linux</li>
<li>An internet connection (Its pretty hard without one, trust me)</li>
</ol>
<p>Lets get started!</p>
<h1 id="installation">Installation</h1>
<p>The first thing that we will have to do is setup our nginx site.</p>
<p>We first have to be root</p>
<p><code>sudo su</code></p>
<p>If you dont have sudo installed try:</p>
<p><code>su -</code></p>
<p>Now we will have to install nginx</p>
<p><code>apt install nginx</code></p>
<p>If you are using any other package manager install it using the package name nginx</p>
<p>Now we will have to start the nginx service</p>
<p><code>systemctl start nginx</code></p>
<p>or</p>
<p><code>service nginx start</code></p>
<p>Lets find your ip with:</p>
<p><code>ip a</code></p>
<p>or</p>
<p><code>ifconfig</code></p>
<p>If you open a web browser and go to your ip you should see the default welcome to nginx site.</p>
<p>Since we want to make our website as secure as possible we can hide the nginx version</p>
<p>To do that type</p>
<p>`sudo nano /etc/nginx/nginx.conf</p>
<p>Now you should see the nginx configuration file.</p>
<p>under</p>
<pre tabindex="0"><code>http {
##
        # Basic Settings
        ##
sendfile on;
        tcp_nopush on;
        types_hash_max_size 2048;
        # server_tokens off;
</code></pre><p>uncomment <code>server_tokens off;</code></p>
<p>Now restart your nginx service</p>
<p><code>systemctl restart nginx</code></p>
<p>We can now enter our html files inside of <code>/var/www/html</code></p>
<p>To do that type:</p>
<p><code>cd /usr/share/nginx/html</code></p>
<p>and now we can create the index.html file</p>
<p><code>nano index.html</code></p>
<p>and paste/write your html code to index.html</p>
<p>Now restart the nginx service again</p>
<p><code>systemctl restart nginx</code></p>
<h1 id="certbot">Certbot</h1>
<p>Now we will install cerbot in order to get https</p>
<p>To install certbot simply type</p>
<p><code>apt install certbot python-certbot-nginx</code></p>
<p>Now we will have to run certbot</p>
<p><code>certbot --nginx</code></p>
<p>Enter all the inf oand agree to the terms</p>
<p>After that you will have to enter the name you would like to activate https for</p>
<p>Just select the names</p>
<p>After that select to redirect http to https</p>
<h1 id="port-forwarding">Port forwarding</h1>
<p>There are a few ways to port forward. In this article we will use noip.com.</p>
<p>Head over to noip.com to get started (Use my referal <a href="https://www.noip.com/?fpr=4rkal">https://www.noip.com/?fpr=4rkal</a>)</p>
<p>Create an account and register a hostname</p>
<p>After that we will have to build the noip client on our computer for that paste these commands to your terminal</p>
<pre tabindex="0"><code>cd /usr/local/src
wget http://www.no-ip.com/client/linux/noip-duc-linux.tar.gz
tar xzf noip-duc-linux.tar.gz
cd noip-2.1.9–1
make
make install
</code></pre><p>When you run make install you will be prompted to answer some questions like your login information and the update interval</p>
<p>In the update interval just set it to 30</p>
<p>Then if you don’t want to run something at a successful update type n if you do then type y.</p>
<p>You will now also have to edit the nginx default settings</p>
<p>to do that type</p>
<p>`sudo nano /etc/nginx/sites-available/default</p>
<p>Now you will have to change the server_name to the domain you registered at noip.com</p>
<p>You can check if your configuration was successful by running</p>
<p><code>nginx -t</code></p>
<p>You can now restart the nginx service</p>
<p><code>systemctl restart nginx</code></p>
<p>Now if you head to your domain it should be working and ssl should be installed</p>
<p>*<strong>If you enjoyed this article consider <a href="../../donate">supporting me</a></strong></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Raspberry pi security camera</title>
      <link>https://4rkal.com/posts/rpicamera/</link>
      <pubDate>Sat, 25 Feb 2023 20:03:25 +0300</pubDate>
      
      <guid>https://4rkal.com/posts/rpicamera/</guid>
      <description>In this article i will show you how to setup a raspberry pi security camera using motion. In the end of this article you will have a fully functioning security camera with a live feed and motion detection.
Requirements Raspberry pi or any other computer Web cam Any kind of debian based distro installed on the pi/computer Setup In this article we will be using the motion package (https://motion-project.github.io/)
To get started power on your raspberry pi and ssh into the machine or just connect it to a monitor and a keyboard.</description>
      <content:encoded><![CDATA[<p>In this article i will show you how to setup a raspberry pi security camera using motion. In the end of this article you will have a fully functioning security camera with a live feed and motion detection.</p>
<h1 id="requirements">Requirements</h1>
<ol>
<li>Raspberry pi or any other computer</li>
<li>Web cam</li>
<li>Any kind of debian based distro installed on the pi/computer</li>
</ol>
<h1 id="setup">Setup</h1>
<p>In this article we will be using the motion package (<a href="https://motion-project.github.io/">https://motion-project.github.io/</a>)</p>
<p>To get started power on your raspberry pi and ssh into the machine or just connect it to a monitor and a keyboard. Also connect your web cam to the raspberry pi usb port.</p>
<p>The first thing we will have to do is install motion, for that type the following command:<br>
<code>apt install motion</code><br>
Now start motion with:<br>
<code>systemctl start motion</code><br>
or<br>
<code>service motion start</code><br>
Now we are going to change some of the default settings . To do that type:<br>
<code>nano /etc/motion/motion.conf</code><br>
The first thing that we are going to change is<br>
<code>webcontrol_localhost off</code><br>
This will enable us to access the stream from other computers.</p>
<p>To view the stream run:</p>
<p><code>motion</code></p>
<p>If you get a permission denied error try running</p>
<p><code>sudo motion</code></p>
<p>If you got to http://YOUR_IP:8080 you should see a live feed of the web cam</p>
<p>You can change the port under webcontrol_port in the config file eg.
<code>webcontrol_port 1234</code></p>
<p>If you only want the live stream port you can go to http://your_ip:8081</p>
<p>Again you can change that under stream_port.</p>
<p>Now everything should be working fine. All motion detection files will be saved in /var/lib/motion</p>
<p>You can also change loads of other settings. Here are my settings:https://pastebin.com/WGn0NfcW</p>
<p>Read the documentation here: <a href="https://motion-project.github.io/motion_guide.html">https://motion-project.github.io/motion_guide.html</a></p>
<p>*<strong>If you enjoyed this article consider <a href="../../donate">supporting me</a></strong></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>How SSH works</title>
      <link>https://4rkal.com/posts/howsshworks/</link>
      <pubDate>Sat, 25 Feb 2023 19:36:25 +0300</pubDate>
      
      <guid>https://4rkal.com/posts/howsshworks/</guid>
      <description>If you work in the IT industry, you’ve undoubtedly heard of ssh. But how does it work?
SSH (secure shell) is a network protocol that allows two computers to connect securely over the internet. SSH uses encryption to prevent hackers from reading data sent between two connected devices.
SSH is divided into three layers:
The transport layer The connection layer The authentication layer During and after authentication, the transport layer establishes safe and secure communication between a client and a server.</description>
      <content:encoded><![CDATA[<p>If you work in the IT industry, you’ve undoubtedly heard of ssh. But how does it work?<br>
SSH (secure shell) is a network protocol that allows two computers to connect securely over the internet. SSH uses encryption to prevent hackers from reading data sent between two connected devices.<br>
SSH is divided into three layers:</p>
<ol>
<li>The transport layer</li>
<li>The connection layer</li>
<li>The authentication layer</li>
</ol>
<p>During and after authentication, the transport layer establishes safe and secure communication between a client and a server. It is in charge of data encryption, decryption, and integrity assurance. It also provides data compression and caching, which helps to speed up data communication.</p>
<p>The authentication layer informs the client about the available authentication methods. It’s also in charge of the whole user authentication procedure.</p>
<p>After the authentication is successful, the connection layer oversees the communication between the machines. It manages communication channel opening and closure, as well as multiple channels for multiple sessions.</p>
<h1 id="session-encryption">Session Encryption</h1>
<p>The server sends the client a list of supported encryption protocols after receiving a connection request. The public key is used by the server as an authentication technique.</p>
<p>The client compares the protocols to the ones it already knows. If there are two protocols that are compatible, the machines agree to use one of them to establish the connection.</p>
<p>On the first connection attempt, the client compares the server’s public key to the private key saved in its system. If the keys are identical, the client and server agree to communicate using symmetric encryption during the SSH session. They communicate utilizing an asymmetrically encrypted mechanism based on the Diffie-Hellman (DH) key exchange algorithm for this purpose.
There are different ciphers that can be used for SSH depending on the applications being used. Some of them include:</p>
<ul>
<li>CHACHA20</li>
<li>AES-GCM</li>
<li>Blowfish-CBC</li>
<li>AES128-CTR</li>
<li>AES192-CTR</li>
<li>AES256-CTR</li>
<li>Arcfour</li>
<li>Cast128-CBC</li>
</ul>
<h1 id="different-encryption-techniques">Different Encryption Techniques</h1>
<p>SSH uses a variety of data manipulation techniques at various points in the transaction to ensure the security of information transmission. These include symmetrical and asymmetrical encryption, as well as hashing.</p>
<h1 id="symmetrical-encryption">Symmetrical Encryption</h1>
<p>Symmetric encryption creates a single key that is exchanged between two machines. The key is then used by the machines for both encryption and decryption. This approach is rapid and resource-light, and it is used by SSH for each session. When the client and server are deciding which algorithm to employ for an SSH session, the first algorithm on the client’s list that the server supports is always used.</p>
<h1 id="asymmetrical-encryption">Asymmetrical Encryption</h1>
<p>Any party can have access to the public key. Although it is linked to its paired key, the private key cannot be deduced from the public key. The public key and private key have a mathematical relationship that allows the public key to encrypt messages that can only be decrypted by the private key. This is a one-way ability, which means that the public key cannot decode the communications it sends or decrypt anything the private key sends it.</p>
<p>The private key should be kept completely confidential and never shared with anybody else. This is a necessary condition for the public key paradigm to function.The only component that can decrypt communications encrypted with the accompanying public key is the private key. Any entity capable of decrypting these messages has demonstrated control over the private key as a result of this fact.</p>
<h1 id="hashing">Hashing</h1>
<p>r key defining characteristics are that they are never supposed to be reversed, that they are nearly hard to predictably alter, and that they are practically unique.</p>
<p>If you use the same hashing function and message, you should get the same hash; if you change any part of the data, you should get a completely different hash. A user should not be able to deduce the actual message from a hash, but they should be able to determine whether a message produced a hash.</p>
<h1 id="session-encryption-negotiation">Session Encryption Negotiation</h1>
<p>The server sends the client a list of supported encryption protocols after receiving a connection request. The public key is used by the server as an authentication technique.</p>
<p>The client evaluates the protocols in comparison to its own. The machines choose one to create the connection using if there are any compatible protocols.</p>
<p>On the initial connection attempt, the client checks the server&rsquo;s public key to the saved copy of its own private key. The client and server consent to using symmetric encryption to communicate during an SSH session if the keys match. They converse utilizing an asymmetric encryption method that makes use of the Diffie-Hellman (DH) key exchange algorithm.</p>
<p>Using a public network, machines can safely collaborate to build a cryptographic key thanks to the DH algorithm. The machines go through the following processes to create a key:</p>
<ul>
<li>The machines agree on two numbers: a modulus and a base number. To prevent brute force key decryption, the chosen modulus is a prime number of at least 600 digits.</li>
<li>In order to solve the equation involving the two public numbers, the machines independently select one number.</li>
<li>The calculated values are exchanged between the server and the client.</li>
<li>Now, utilizing the information obtained from the other machine, each machine computes something.</li>
</ul>
<p>By carrying out the above processes, both machines determine the identical value, which is their secret key. The server then makes an attempt to verify the user&rsquo;s identity who made the access request.</p>
<p>***If you enjoyed this article consider <a href="../../donate">supporting me</a></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Automating your web browser with selenium</title>
      <link>https://4rkal.com/posts/selenium/</link>
      <pubDate>Wed, 22 Feb 2023 21:23:38 +0300</pubDate>
      
      <guid>https://4rkal.com/posts/selenium/</guid>
      <description>Selenium is a very good skill to have as you can automate almost everything that you can do with a web browser.
In this tutorial, we’ll learn how to use Python and Selenium to automate a web browser. This is an updated version of my previous article which unfortunately doesn&amp;rsquo;t work anymore. If you’re a complete beginner, read my python article to understand the basics. (https://4rkal.com/posts/python/)
What is selenium? Selenium is an open source umbrella project for a range of tools and libraries aimed at supporting browser automation.</description>
      <content:encoded><![CDATA[<p><strong>Selenium is a very good skill to have as you can automate almost everything that you can do with a web browser.</strong></p>
<p>In this tutorial, we’ll learn how to use Python and Selenium to automate a web browser. This is an updated version of my previous article which unfortunately doesn&rsquo;t work anymore. If you’re a complete beginner, read my python article to understand the basics. (<a href="https://4rkal.com/posts/python/">https://4rkal.com/posts/python/</a>)</p>
<h2 id="what-is-selenium">What is selenium?</h2>
<p>Selenium is an open source umbrella project for a range of tools and libraries aimed at supporting browser automation. You can use selenium in multiple programming languages including JavaScript (Node.js), C#, Groovy, Java, Perl, PHP, Python, Ruby and Scala and with multiple web browsers including firefox, internet explorer, safary, opera, chrome and edge. Selenium can be very useful for web scraping, automating boring and manual tasks and so much more.</p>
<h2 id="setup">Setup</h2>
<p>To install selenium you first have to install a browser driver. Here is the list of supported web browsers :</p>
<ul>
<li>Firefox</li>
<li>Internet Explorer?</li>
<li>Safari</li>
<li>Opera</li>
<li>Chrome</li>
<li>Edge
In this article we will be using firefox geckodriver. But you can use any of the browser drivers above.</li>
</ul>
<h2 id="downloading-geckodriver">Downloading geckodriver</h2>
<p>To get started go to github.com/mozilla/geckodriver/releases
Scroll down and select the package for your computer.
I’ll use geckodriver-v0.31.0-linux64.tar.gz because I’m using a linux 64-bit computer.</p>
<h2 id="installing-geckodriver">Installing geckodriver</h2>
<p>The setup varies depending on your operating system.</p>
<p>If you are using Arch Linux:
You can install geckodriver from the aur. Using your favourite aur helper</p>
<p>On linux:</p>
<ol>
<li>Unzip the file</li>
<li>Make the file executable
<code>chmod +x geckodriver</code></li>
<li>Add the driver to your PATH so other tools can find it:
<code>export PATH=$PATH:/path-to-extracted-file/</code>
On windows:</li>
<li>Unzip the file</li>
<li>Paste the file in the directory that your script will run</li>
</ol>
<h2 id="installing-selenium">Installing selenium</h2>
<p>To install selenium you have to have python and pip installed.Check out my article on python for <a href="https://4rkal.com/posts/python">more</a>
To install selenium open your cmd or terminal and type:<br>
<code>pip install selenium</code>
That should install it.\</p>
<h2 id="basics-of-selenium">Basics of selenium</h2>
<p>The first thing we have to do is to create a new file with the .py ending eg. main.py<br>
After you have created it open it in your ide or editor of choice.\</p>
<p>The first thing that we have to do is to import the selenium webdriver :
<code> from selenium import webdriver</code><br>
After that we have to specify what webdriver we are using. In our case its firefox
<code> browser = webdriver.Firefox()</code><br>
Now we need to specify the url that we want it to go to eg python.org</p>
<pre tabindex="0"><code>browser.get(&#39;https://python.org&#39;)
The full code so far is:\
import selenium
from selenium import webdriver
browser = webdriver.Firefox()
browser.get(&#39;https://python.org&#39;)
</code></pre><p>Now we might want it to click on the Downloads button</p>
<p>There are a few ways to do this</p>
<h2 id="method-1-of-clicking-a-button">Method 1 of clicking a button</h2>
<p>The first is with XPATH<br>
To find the xpath of a button / object on a website you have to open your web browser go to the desired website and hit F12 to get the development tools. Now you should click on the select tool (See below)
<img loading="lazy" src="/../assets/inspect.png" type="" alt="Inspect element"  />
Click on it and after that hover above the downloads button with your mouse and click it. After that you should see a bit of code getting highlighted. Right click on the bit of code and select Copy then select Xpath
<img loading="lazy" src="/../assets/copy.png" type="" alt="1"  />
Now go back to the python file and type:<br>
<code>driver.find_element(By.XPATH, 'XPATH_HERE')</code><br>
This will throw an error, to fix that error simply add this at the top of the file<br>
<code> from selenium.webdriver.common.by import By</code><br>
Your code so far should look like this</p>
<pre tabindex="0"><code>import selenium
from selenium import webdriver
from selenium.webdriver.common.by import By
browser = webdriver.Firefox()
browser.get(&#39;https://python.org&#39;)
browser.find_element(By.XPATH, &#39;/html/body/div/header/div/nav/ul/li[2]/a&#39;).click()
</code></pre><h2 id="method-2">Method 2</h2>
<p>XPATH with text
The second method is a bit simpler but not as reliable as the first as there might be many objects with the same name.<br>
To use this method type:
<code>browser.find_element(By.XPATH, &quot;//*[contains(text(), 'Downloads')]&quot;).click()</code>
Your code should look something like this</p>
<pre tabindex="0"><code>import selenium
from selenium import webdriver
from selenium.webdriver.common.by import By
browser = webdriver.Firefox()
browser.get(&#39;https://python.org&#39;)
browser.find_element(By.XPATH, &#34;//*[contains(text(), &#39;Downloads&#39;)]&#34;).click()
</code></pre><p>. . . . .</p>
<p>There many methods on how to locate elements but the above i believe are the easiest.
The methods are the following</p>
<ul>
<li>By.ID</li>
<li>By.NAME</li>
<li>By.XPATH</li>
<li>By.LINK-TEXT</li>
<li>By.TAG_NAME</li>
<li>By.CLASS_NAME</li>
<li>By.CSS_SELECTOR\</li>
</ul>
<p>Read more here: <a href="https://selenium-python.readthedocs.io/locating-elements.html">https://selenium-python.readthedocs.io/locating-elements.html</a></p>
<h2 id="typing-text-into-input-fields">Typing text into input fields.</h2>
<p>Typing text into input fields is pretty straight forward.<br>
For that we will use any of the above methods. I&rsquo;m going to use xpath.<br>
Find the xpath of any input field, I&rsquo;m going to use the google.com search field<br>
Copy the xpath and type:<br>
<code>a = browser.find_element(By.XPATH, &quot;XPATH_HERE&quot;)</code>
Paste the xpath in XPATH_HERE</p>
<p>To send keys we need to import the selenium.webdriver.common.keys library for that paste this line of code at the top of your file<br>
<code>from selenium.webdriver.common.keys import Keys</code><br>
Now type:<br>
<code>a.send_keys(&quot;python&quot;)</code><br>
After that we want to press the enter key for that type:<br>
<code>a.send_keys(Keys.RETURN)</code><br>
The full code should look something like this:</p>
<pre tabindex="0"><code>import selenium
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
browser = webdriver.Firefox()
browser.get(&#39;https://google.com&#39;)
a = browser.find_element(By.XPATH, &#34;/html/body/div[1]/div[3]/form/div[1]/div[1]/div[1]/div/div[2]/input&#34;)
a.send_keys(&#34;python&#34;)
a.send_keys(Keys.RETURN)
</code></pre><p>GG you just automated your first google search!
You might first need to accept cookies for that just follow the steps on how to click a button from above.<br>
Read more about selenium here: <a href="https://selenium-python.readthedocs.io/">https://selenium-python.readthedocs.io/</a>\</p>
<p>*<strong>If you enjoyed this article consider <a href="../../donate">supporting me</a></strong></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Why computers can’t represent 0.3 accurately</title>
      <link>https://4rkal.com/posts/zeropointthree/</link>
      <pubDate>Tue, 21 Feb 2023 19:27:44 +0300</pubDate>
      
      <guid>https://4rkal.com/posts/zeropointthree/</guid>
      <description>Most people know that adding up 0.1 + 0.2 equals 0.3. However computers represent it as 0.30000000000000004 .
Here is a screenshot of it in python3 Your first thought might be that this is just some kind of error. Well its not
Why does this happen? Fractions can be represented precisely in the base 10 system (used by humans) if a prime factor of the base is used (10).
2 and 5 are the prime factors of 10.</description>
      <content:encoded><![CDATA[<p><strong>Most people know that adding up 0.1 + 0.2 equals 0.3. However computers represent it as 0.30000000000000004 .</strong></p>
<p>Here is a screenshot of it in python3
<img loading="lazy" src="/../assets/zeropointthree.png" type="" alt="0.1&#43;0.2 in python"  /></p>
<p>Your first thought might be that this is just some kind of error. Well its not</p>
<h1 id="why-does-this-happen">Why does this happen?</h1>
<p>Fractions can be represented precisely in the base 10 system (used by humans) if a prime factor of the base is used (10).</p>
<ul>
<li>2 and 5 are the prime factors of 10.</li>
<li>1/2, 1/4, 1/5 (0.2), 1/8, and 1/10 (0.1) can be expressed precisely as a result of denominators use prime factors of 10.</li>
<li>Whereas, 1/3, 1/6, and 1/7 are repeating decimals as a result of denominators use a prime factor of 3 or 7.
On the other hand, fractions can be represented precisely in the base 2 (binary) system (used by computers) if a prime factor of the base is used.</li>
<li>2 is the only prime factor of 2.</li>
<li>So 1/2, 1/4, 1/8 can all be expressed precisely because the denominators use prime factors of 2.</li>
<li>Whereas 1/5 (0.2) or 1/10 (0.1) are repeating decimals.
When you perform math on these repeating decimals, you end up with leftovers which carry over when you convert the computer’s base-2 (binary) number into a more human-readable base-10 representation.</li>
</ul>
<p>Read more:
0.300.com
Wikipedia:<br>
<a href="https://en.wikipedia.org/wiki/Floating-point_arithmetic">https://en.wikipedia.org/wiki/Floating-point_arithmetic</a></p>
<p><strong>If you enjoyed this article consider <a href="https://4rkal.com/donate">donating</a></strong></p>
]]></content:encoded>
    </item>
    
  </channel>
</rss>
