<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: 4rkal</title>
    <description>The latest articles on DEV Community by 4rkal (@4rkal).</description>
    <link>https://dev.to/4rkal</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1295551%2F86b8e5a9-413d-45ed-ac5d-493793e56568.png</url>
      <title>DEV Community: 4rkal</title>
      <link>https://dev.to/4rkal</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/4rkal"/>
    <language>en</language>
    <item>
      <title>Prevent newsletter signup spam</title>
      <dc:creator>4rkal</dc:creator>
      <pubDate>Thu, 17 Apr 2025 14:43:47 +0000</pubDate>
      <link>https://dev.to/4rkal/prevent-newsletter-signup-spam-fpi</link>
      <guid>https://dev.to/4rkal/prevent-newsletter-signup-spam-fpi</guid>
      <description>&lt;h2&gt;
  
  
  Backstory
&lt;/h2&gt;

&lt;p&gt;I woke up to 200 new subscribers on the newsletter of my site &lt;a href="//https;//videiro.com"&gt;videiro.com&lt;/a&gt;, had it finally happened? Did my site finally go viral?&lt;/p&gt;

&lt;p&gt;Sadly no. After checking the new subscribers I noticed that none had verified their email addresses, not even one, that’s definitely not a confidence.&lt;/p&gt;

&lt;p&gt;After some quick research I understood that I had indeed been spammed. But all the emails look legit. Here are some examples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kathyolynn@yahoo.com
lukeckins@gmail.com
dispatch@gonealinc.com
doug_fern@hotmail.com

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

&lt;/div&gt;



&lt;p&gt;After some initial research (entering the emails into &lt;a href="https://haveibeenpwned.com/" rel="noopener noreferrer"&gt;haveibeenpwned&lt;/a&gt;) it looks like most of these email addresses have been in some kind of hack or breach.&lt;/p&gt;

&lt;p&gt;So what was happening? How can I prevent it in the future?&lt;/p&gt;

&lt;p&gt;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?&lt;/p&gt;

&lt;h2&gt;
  
  
  What I learned
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;It turns out that this kind of spam attack is more common that you think (especially since my &lt;a href="https://newsletter.4rkal.com" rel="noopener noreferrer"&gt;blog’s newsletter&lt;/a&gt; also got spammed a couple weeks later). Bots crawl the web and look for forms, usually newsletter or contact forms and then start submitting “leaked” email addresses.&lt;/p&gt;

&lt;p&gt;But why? Here are some reasons I came up with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;To pollute your email list (if this is a personal attack, which I don’t think it is in this case)&lt;/li&gt;
&lt;li&gt;To test the validity of the emails??&lt;/li&gt;
&lt;li&gt;To annoy the leaked email addresses owners by having them subscribed to thousands of newsletters&lt;/li&gt;
&lt;li&gt;To annoy the website owner (me)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How I fixed it
&lt;/h2&gt;

&lt;p&gt;I have a couple solutions to this problem.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Enable Double Opt-in
&lt;/h3&gt;

&lt;p&gt;The fist and most important step is to make sure that all your newsletters are ‘double opt-in’ meaning that the user has to confirm their email address before getting subscribed&lt;/p&gt;

&lt;p&gt;On listmonk (the newsletter software I am using) make sure that the list that you are subscribing your users to is &lt;code&gt;double opt in&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This means that even if your form gets spammed you can just remove all the addresses that haven’t verified their email (after a couple of days/weeks).&lt;/p&gt;

&lt;p&gt;Want to learn how to set up your own self-hosted newsletter with Listmonk?&lt;br&gt;&lt;br&gt;
Check out my guide: &lt;a href="https://4rkal.com/posts/listmonk/" rel="noopener noreferrer"&gt;How to set up a self-hosted newsletter using Listmonk&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Add Captcha or Cloudflare JS challenge
&lt;/h3&gt;

&lt;p&gt;The second step I took was to enable some sort of catcha. Initially I setup an hcaptcha via listmonk. But I don’t think that is the best solution as it’s kind of annoying. I am however using it for the &lt;a href="https://videiro.com" rel="noopener noreferrer"&gt;videiro.com&lt;/a&gt; newsletter. If your interested in how to do it here’s how:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the listmonk web-ui&lt;/li&gt;
&lt;li&gt;Go to settings&lt;/li&gt;
&lt;li&gt;Under &lt;code&gt;Security&lt;/code&gt;, enable captcha and enter an hCaptcha.com API key (you will first have to signup at &lt;a href="https://hcaptcha.com" rel="noopener noreferrer"&gt;hcaptcha.com&lt;/a&gt;)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;However with this setup if you are using custom forms (like the email subscription form bellow) the submission process will be kind of broken.&lt;/p&gt;

&lt;p&gt;So instead what I came up with and I am currently using on &lt;a href="https://4rkal.com" rel="noopener noreferrer"&gt;4rkal.com&lt;/a&gt; newsletter is to use cloudflare JS Challenge on a specific subdomain.&lt;/p&gt;

&lt;p&gt;The way that I have setup my email newsletter is that I have listmonk running on &lt;code&gt;newsletter.4rkal.com&lt;/code&gt;, a seperate subdomain.&lt;/p&gt;

&lt;p&gt;This means that I can set that specific subdomain as “under attack” on cloudflare and prompt users to sometimes complete a catcha.&lt;/p&gt;

&lt;p&gt;To do this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Head to cloudflare.com&lt;/li&gt;
&lt;li&gt;Login and head to the dashboard of your specific domain&lt;/li&gt;
&lt;li&gt;Under &lt;code&gt;Security&lt;/code&gt; select &lt;code&gt;WAF&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Then click on &lt;code&gt;Create rule&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Give it any name&lt;/li&gt;
&lt;li&gt;Under &lt;code&gt;Field&lt;/code&gt; select &lt;code&gt;hostname&lt;/code&gt; and under &lt;code&gt;Operator&lt;/code&gt; select &lt;code&gt;wildcard&lt;/code&gt;, in &lt;code&gt;Value&lt;/code&gt; enter the subdomain, in my case that’s &lt;code&gt;newsletter.4rkal.com&lt;/code&gt;. The expression should look like this &lt;code&gt;(http.host wildcard "newsletter.4rkal.com")&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Under &lt;code&gt;Choose action&lt;/code&gt; select &lt;code&gt;JS Challenge&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Click on &lt;code&gt;Save&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And that’s about it&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

</description>
      <category>listmonk</category>
      <category>newsletter</category>
      <category>spam</category>
      <category>bots</category>
    </item>
    <item>
      <title>Deploying Go + Templ + HTMX + TailwindCSS to production</title>
      <dc:creator>4rkal</dc:creator>
      <pubDate>Thu, 06 Mar 2025 11:16:29 +0000</pubDate>
      <link>https://dev.to/4rkal/deploying-go-templ-htmx-tailwindcss-to-production-5hc4</link>
      <guid>https://dev.to/4rkal/deploying-go-templ-htmx-tailwindcss-to-production-5hc4</guid>
      <description>&lt;p&gt;I recently created my very own cryptocurrency exchange aggregator called &lt;a href="https://cyphergoat.com" rel="noopener noreferrer"&gt;cyphergoat&lt;/a&gt; it finds you the best rate to swap your crypto from different partnered exchanges.&lt;/p&gt;

&lt;p&gt;It has two parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;An API that interacts with exchanges. Written in go and uses gin&lt;/li&gt;
&lt;li&gt;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.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What is extremely cool with this stack and setup is that we are able to produce &lt;strong&gt;a single binary&lt;/strong&gt; 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.&lt;/p&gt;

&lt;p&gt;In this article I will be going through my setup to make it easier for you to make something like this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;In this guide I will show you how I set this up.&lt;/p&gt;

&lt;h2&gt;
  
  
  The setup
&lt;/h2&gt;

&lt;p&gt;I have a single folder on my dev machine called cyphergoat: It contains&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;api/
web/
builds/

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

&lt;/div&gt;



&lt;p&gt;The api folder houses the api source code. The web the website source code.&lt;/p&gt;

&lt;p&gt;And the builds houses all of the builds that are deployed to the server.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tailwind
&lt;/h3&gt;

&lt;p&gt;The first real challenge comes with setting up tailwindcss correctly.&lt;/p&gt;

&lt;p&gt;In my web project I have a static folder specifically for static files. Inside of it I have two files&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/web
    styles.css
    tailwind.css

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

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;styles.css&lt;/code&gt; simply contains:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@import "tailwindcss";

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

&lt;/div&gt;



&lt;p&gt;The tailwind.css file is where tailwind-cli will save it’s stuff.&lt;/p&gt;

&lt;p&gt;To build the tailwind stuff I simply run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx @tailwindcss/cli -i ./static/styles.css -o ./static/tailwind.css --watch

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

&lt;/div&gt;



&lt;p&gt;(assuming you have tailwind-cli installed)&lt;/p&gt;

&lt;p&gt;In my header.templ file (the header of all the pages) at the top I have&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;link href="https://4rkal.com/static/tailwind.css" rel="stylesheet"&amp;gt;

&amp;lt;link href="https://4rkal.com/static/styles.css" rel="stylesheet"&amp;gt;

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

&lt;/div&gt;



&lt;p&gt;And the files are being served using echo’s e.Static (in my main.go file )&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func main(){
e := echo.New()

e.Use(middleware.Logger())
e.Use(middleware.Recover())
e.Use(middleware.Secure())

e.Static("/static", "static") // Serves content from static folder.

// Rest of the handlers
}

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Server
&lt;/h2&gt;

&lt;p&gt;On my server side I have a debian 12 vm running on proxmox.&lt;/p&gt;

&lt;p&gt;In my users home directory I have a folder with the following contents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cyphergoat/
├── api
├── static/
└── web

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

&lt;/div&gt;



&lt;p&gt;The static folder contains all of the static files (including tailwind.css and styles.css) and the &lt;strong&gt;web&lt;/strong&gt; and &lt;strong&gt;api&lt;/strong&gt; are the binaries.&lt;/p&gt;

&lt;p&gt;I then have two systemd services for these exectuables:&lt;/p&gt;

&lt;p&gt;The&lt;code&gt;cg-api.service&lt;/code&gt;&lt;code&gt;/etc/systemd/system/cg-api.service&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Unit]
Description=CypherGoat API
After=network.target

[Service]
User=arkal
Group=www-data
WorkingDirectory=/home/arkal/cyphergoat
ExecStart=/home/arkal/cyphergoat/api
Restart=always
RestartSec=1

[Install]
WantedBy=multi-user.target

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

&lt;/div&gt;



&lt;p&gt;And &lt;code&gt;cg-web.service&lt;/code&gt;&lt;code&gt;/etc/systemd/system/cg-web.service&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Unit]
Description=CypherGoat Web
After=network.target

[Service]
User=arkal
Group=www-data
WorkingDirectory=/home/arkal/cyphergoat
ExecStart=/home/arkal/cyphergoat/web

[Install]
WantedBy=multi-user.target

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

&lt;/div&gt;



&lt;p&gt;Both are owned by the group &lt;code&gt;www-data&lt;/code&gt; (this is probably not necessary for the api), in order to make it easier to serve them via nginx.&lt;/p&gt;

&lt;h3&gt;
  
  
  Nginx
&lt;/h3&gt;

&lt;p&gt;The website is communicating with the api but I still need to make the web-ui accessible.&lt;/p&gt;

&lt;p&gt;I have setup an nginx site with the following configuration:&lt;code&gt;/etc/nginx/sites-available/cg&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;server {
    server_name cyphergoat.com;

    location / {
        proxy_pass http://127.0.0.1:4200;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    location /static/ {
        alias /var/www/static/;
        expires 30d;
    }

    # Optional robots.txt
    location = /robots.txt {
        root /var/www/static;
        access_log off;
        log_not_found off;
    }

    listen 80;
}

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

&lt;/div&gt;



&lt;p&gt;I have also setup certbot to have an ssl cert.&lt;/p&gt;

&lt;p&gt;You can setup certbot by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt install certbot python3-certbot-nginx -y

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

&lt;/div&gt;



&lt;p&gt;Generate the ssl cert:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo certbot --nginx -d cyphergoat.com

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

&lt;/div&gt;



&lt;p&gt;Read &lt;a href="https://4rkal.com/posts/shwebsite/" rel="noopener noreferrer"&gt;Self host your own website&lt;/a&gt; for a more in depth nginx setup.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cloudflare Tunnels
&lt;/h3&gt;

&lt;p&gt;I am currently making my website accessible using cloudflare pages. It is an extremely easy to use port forwarding solution&lt;/p&gt;

&lt;p&gt;To do this you will need a cloudflare account and a domain pointed to cloudflare.&lt;/p&gt;

&lt;p&gt;First head to the &lt;a href="https://one.dash.cloudflare.com/" rel="noopener noreferrer"&gt;Zero Trust Dashboard&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Under &lt;code&gt;Networks&lt;/code&gt; click on &lt;code&gt;Tunnels&lt;/code&gt; and then &lt;code&gt;Create a tunnel&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Once created you should &lt;code&gt;Install and run a connector&lt;/code&gt;, follow the instructions on the page for your specific setup.&lt;/p&gt;

&lt;p&gt;After the connector is running you should click on the &lt;code&gt;Public Hostname&lt;/code&gt; tab and &lt;code&gt;Add a public hostname&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now you should see something like this: &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F780if1qou03qlkwt5ihq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F780if1qou03qlkwt5ihq.png" alt="Cloudflare dashboard" width="800" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fill in the info as I have. The service type should be &lt;code&gt;HTTP&lt;/code&gt; and the url should be &lt;code&gt;127.0.0.1:80&lt;/code&gt; or &lt;code&gt;localhost:80&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Obviously there is no reason to make your api publicly accessible when deploying your website.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deployment
&lt;/h2&gt;

&lt;p&gt;In order to deploy my binaries I went ahead and created a quick bash script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd api
go build -o ../builds/ .

cd ../web

templ generate &amp;amp;&amp;amp; go build -o ../builds/web cmd/main.go

cd ..
rsync -urvP ./builds/ user@SERVER:/home/user/cyphergoat
rsync -urvP ./web/static user@SERVER:/home/user/cyphergoat/
rsync -urvP ./api/coins.json user@SERVER:/user/user/cyphergoat/

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

&lt;/div&gt;



&lt;p&gt;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)&lt;/p&gt;

&lt;p&gt;I then ssh into my server&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ssh user@ip&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;and then restart the services&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo systemctl restart cg-api cg-web&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And that’s it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Join my free newsletter!
&lt;/h2&gt;

&lt;p&gt;Join &lt;a href="https://newsletter.4rkal.com/subscription/form" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Related Articles
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://4rkal.com/posts/go-rate-limit" rel="noopener noreferrer"&gt;Simple Rate Limiting in Go (Gin)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://4rkal.com/posts/url-shortener-go/" rel="noopener noreferrer"&gt;How to build a URL shortener in Go&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://4rkal.com/posts/django-prod/" rel="noopener noreferrer"&gt;How to deploy django to production&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>htmx</category>
      <category>tailwindcss</category>
      <category>templ</category>
    </item>
    <item>
      <title>If Linux is so great why isn't everyone using it?</title>
      <dc:creator>4rkal</dc:creator>
      <pubDate>Sun, 13 Oct 2024 14:33:38 +0000</pubDate>
      <link>https://dev.to/4rkal/if-linux-is-so-great-why-isnt-everyone-using-it-5b98</link>
      <guid>https://dev.to/4rkal/if-linux-is-so-great-why-isnt-everyone-using-it-5b98</guid>
      <description>&lt;h2&gt;
  
  
  What even is Linux?
&lt;/h2&gt;

&lt;p&gt;Linux is a family of free and open source operating systems based on the &lt;a href="https://kernel.org/" rel="noopener noreferrer"&gt;Linux kernel&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Although being completely free (unlike alternatives) Linux currently only has &lt;a href="https://gs.statcounter.com/os-market-share/desktop/worldwide" rel="noopener noreferrer"&gt;4.5% of the global desktop operating system market&lt;/a&gt;, a very low percentage.&lt;/p&gt;

&lt;h2&gt;
  
  
  What makes Linux great?
&lt;/h2&gt;

&lt;p&gt;The core difference between Linux and other mainstream desktop operating systems (windows, macOS) is the fact that it is &lt;strong&gt;free and open source&lt;/strong&gt;. This allows it to be:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Highly performant&lt;/strong&gt; - Linux is often faster and more efficient than its counterparts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Free from spyware and ads&lt;/strong&gt; - Unlike Windows 11 which is &lt;a href="https://www.theverge.com/2024/4/24/24138949/microsoft-windows-11-start-menu-ads-recommendations-setting-disable" rel="noopener noreferrer"&gt;adding ads to the start menu&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Arguably more secure&lt;/strong&gt; - Being open source often makes it more secure&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://www.reddit.com/r/unixporn/" rel="noopener noreferrer"&gt;Endlessly customizable&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Completely free forever&lt;/strong&gt; - Because it is published under a free and open source GPL license.&lt;/li&gt;
&lt;li&gt;and much much more&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Read &lt;a href="https://4rkal.com/posts/opensource" rel="noopener noreferrer"&gt;The importance of open source software&lt;/a&gt; for more information about open source software and it’s superiority.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  If Linux is so great why isn’t everyone using it?
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;The fun part however is that most people are using Linux, they just don’t know it!&lt;/p&gt;

&lt;h3&gt;
  
  
  Android
&lt;/h3&gt;

&lt;p&gt;Android is the most widely used mobile operating system in the world. With a staggering &lt;a href="https://gs.statcounter.com/os-market-share/mobile/worldwide" rel="noopener noreferrer"&gt;71% of the global mobile operating system market&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A lesser known fact is that android is based on the Linux kernel.&lt;/p&gt;

&lt;p&gt;So basically 71% of smartphones are running Linux!&lt;/p&gt;

&lt;h3&gt;
  
  
  Servers
&lt;/h3&gt;

&lt;p&gt;Linux is the leading operating system on servers (over 96.4% of the top one million web servers’ operating systems are Linux) It also leads other systems such as mainframe computers, and is used on all of the world’s 500 fastest supercomputers.&lt;/p&gt;

&lt;p&gt;This website is being served from a Linux server.&lt;/p&gt;

&lt;p&gt;The majority if not all of the websites that you visit every single day are being served from a Linux server.&lt;/p&gt;

&lt;h3&gt;
  
  
  IoT and embedded systems
&lt;/h3&gt;

&lt;p&gt;Most IoT (Internet Of Things) devices run Linux because of it’s lightweight nature and robustness. &lt;a href="https://ubuntu.com/blog/eclipse-2018-survey-the-iot-landscape-what-it-empirically-looks-like" rel="noopener noreferrer"&gt;This article&lt;/a&gt; from 2018 suggests that 71% of IoT devices run Linux&lt;/p&gt;

&lt;p&gt;Most embedded systems (smart TV’s, routers etc) run Linux&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Linux is quietly running behind the scenes. It may only capture a small slice of the desktop operating system market but it’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.&lt;/p&gt;

&lt;p&gt;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’s a must)&lt;/p&gt;

&lt;p&gt;&lt;em&gt;PS: this article was written on a Framework 13 running Fedora 40 (Linux)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Join my free newsletter
&lt;/h2&gt;

&lt;p&gt;Here &lt;a href="https://newsletter.4rkal.com/subscription/form" rel="noopener noreferrer"&gt;https://newsletter.4rkal.com/subscription/form&lt;/a&gt;&lt;/p&gt;

</description>
      <category>linux</category>
    </item>
    <item>
      <title>How to build a URL shortener in Go</title>
      <dc:creator>4rkal</dc:creator>
      <pubDate>Sun, 22 Sep 2024 15:24:11 +0000</pubDate>
      <link>https://dev.to/4rkal/how-to-build-a-url-shortener-in-go-3p5p</link>
      <guid>https://dev.to/4rkal/how-to-build-a-url-shortener-in-go-3p5p</guid>
      <description>&lt;p&gt;In this article I will be going through how to make a url shortener in go. The final result will look something like this &lt;a href="https://app.4rkal.com" rel="noopener noreferrer"&gt;shortr&lt;/a&gt;, &lt;a href="https://github.com/4rkal/shortr" rel="noopener noreferrer"&gt;source code&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a great weekend project especially if you’re new to go.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a url shortener?
&lt;/h2&gt;

&lt;p&gt;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 &lt;code&gt;www.somelongwebsite.com/articles/this-is-a-super-long-link&lt;/code&gt; could become something like &lt;code&gt;bit.ly/abc123&lt;/code&gt;. It’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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Go installed on your system.&lt;/li&gt;
&lt;li&gt;A code editor, eg &lt;a href="https://code.visualstudio.com/" rel="noopener noreferrer"&gt;vs code&lt;/a&gt;, &lt;a href="https://neovim.io/" rel="noopener noreferrer"&gt;neovim&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In this project I will be using &lt;a href="https://echo.labstack.com/" rel="noopener noreferrer"&gt;echo&lt;/a&gt; as the http server and the standard html library.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project Setup
&lt;/h2&gt;

&lt;p&gt;Create a new directory to house our project&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir project-name
cd project-name

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

&lt;/div&gt;



&lt;p&gt;Assuming you have golang installed.&lt;/p&gt;

&lt;p&gt;Create a new go module (project):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;go mod init project-name

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

&lt;/div&gt;



&lt;p&gt;Before we start writing any code we first have to install echo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;go get github.com/labstack/echo/v4

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

&lt;/div&gt;



&lt;p&gt;Now create a new file called main.go&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;touch main.go

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

&lt;/div&gt;



&lt;p&gt;And open it in your favorite editor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating url handlers
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func main() {

    e := echo.New()

    e.Use(middleware.Logger())
    e.Use(middleware.Recover())
    e.Use(middleware.Secure())

    e.GET("/:id", RedirectHandler)
    e.GET("/", IndexHandler)
    e.POST("/submit", SubmitHandler)

    e.Logger.Fatal(e.Start(":8080"))

}

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

&lt;/div&gt;



&lt;p&gt;This will create three different routes/handlers.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;/:id&lt;/code&gt;, which will redirect the user to the required website&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;/&lt;/code&gt; which will display a url submission form for new urls to be added&lt;/p&gt;

&lt;p&gt;Finally the &lt;code&gt;/submit&lt;/code&gt; which will handle url submissions from the form in &lt;code&gt;/&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Redirect Handler
&lt;/h3&gt;

&lt;p&gt;The most important part of our application is the redirect handler, which will redirect the user to the url that was specified.&lt;/p&gt;

&lt;p&gt;Before we create any urls we first have to declare some variables and make a helper function&lt;/p&gt;

&lt;p&gt;In order to have a random ending to our url. eg &lt;code&gt;/M61YlA&lt;/code&gt;, we will create a new function called &lt;code&gt;GenerateRandomString&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"

func generateRandomString(length int) string {
    seededRand := rand.New(rand.NewSource(time.Now().UnixNano()))

    var result []byte

    for i := 0; i &amp;lt; length; i++ {
    index := seededRand.Intn(len(charset))
    result = append(result, charset[index])
    }

    return string(result)

}

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

&lt;/div&gt;



&lt;p&gt;This will select &lt;code&gt;length&lt;/code&gt; random characters from the charset. If you want your slugs (urls), to not contain any capital letters, you can remove them from the charset.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Create a new struct called &lt;code&gt;Link&lt;/code&gt; and a map called &lt;code&gt;LinkMap&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type Link struct {
    Id string
    Url string
}

var linkMap = map[string]*models.Link{}

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

&lt;/div&gt;



&lt;p&gt;You can also add some sample data to it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var linkMap = map[string]*Link{ "example": { Id: "example", Url: "https://example.com", }, }

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

&lt;/div&gt;



&lt;p&gt;Now we can (finally) create our &lt;code&gt;RedirectHandler&lt;/code&gt;, which will handle all of the redirects for our url shortener.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func RedirectHandler(c echo.Context) error {
    id := c.Param("id")
    link, found := linkMap[id]

    if !found {
    return c.String(http.StatusNotFound, "Link not found")
    }

    return c.Redirect(http.StatusMovedPermanently, link.Url)
}

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

&lt;/div&gt;



&lt;p&gt;This function will get the id of the link eg &lt;code&gt;/123&lt;/code&gt; and will look for it in the global &lt;code&gt;LinkMap&lt;/code&gt;, 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 &lt;code&gt;301 Permanently Moved&lt;/code&gt; http response code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recap #1
&lt;/h2&gt;

&lt;p&gt;The code so far should look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
"math/rand"
"time"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
)

type Link struct {
    Id string
    Url string
}

const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"

var linkMap = map[string]*Link{ "example": { Id: "example", Url: "https://example.com", }, }

func main() {
    e := echo.New()

    e.Use(middleware.Logger())
    e.Use(middleware.Recover())
    e.Use(middleware.Secure())

    e.GET("/:id", RedirectHandler)
    //e.GET("/", IndexHandler)
    //e.POST("/submit", SubmitHandler)

    e.Logger.Fatal(e.Start(":8080"))
}

func RedirectHandler(c echo.Context) error {
    id := c.Param("id")
    link, found := linkMap[id]

    if !found {
    return c.String(http.StatusNotFound, "Link not found")
    }

    return c.Redirect(http.StatusMovedPermanently, link.Url)
}

func generateRandomString(length int) string {
    seededRand := rand.New(rand.NewSource(time.Now().UnixNano()))

    var result []byte

    for i := 0; i &amp;lt; length; i++ {
    index := seededRand.Intn(len(charset))
    result = append(result, charset[index])
    }

    return string(result)

}

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

&lt;/div&gt;



&lt;p&gt;Run the server&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;go run .

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

&lt;/div&gt;



&lt;p&gt;You might also want to install any missing dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;go mod tidy

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

&lt;/div&gt;



&lt;p&gt;If you head to&lt;code&gt;localhost:8080/example&lt;/code&gt; you should be redirected to example.com&lt;/p&gt;

&lt;h3&gt;
  
  
  Submission Handlers
&lt;/h3&gt;

&lt;p&gt;We will now define two new routes inside of our main function&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;e.GET("/", IndexHandler)
e.POST("/submit", SubmitHandler)

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

&lt;/div&gt;



&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;For the &lt;code&gt;IndexHandler&lt;/code&gt; our code will look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func IndexHandler(c echo.Context) error {
    html := `
        &amp;lt;h1&amp;gt;Submit a new website&amp;lt;/h1&amp;gt;
        &amp;lt;form action="https://4rkal.com/submit" method="POST"&amp;gt;
        &amp;lt;label for="url"&amp;gt;Website URL:&amp;lt;/label&amp;gt;
        &amp;lt;input type="text" id="url" name="url"&amp;gt;
        &amp;lt;input type="submit" value="Submit"&amp;gt;
        &amp;lt;/form&amp;gt;
        &amp;lt;h2&amp;gt;Existing Links &amp;lt;/h2&amp;gt;
        &amp;lt;ul&amp;gt;`

    for _, link := range linkMap {
        html += `&amp;lt;li&amp;gt;&amp;lt;a href="https://4rkal.com/` + link.Id + `"&amp;gt;` + link.Id + `&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;`
    }
    html += `&amp;lt;/ul&amp;gt;`

    return c.HTML(http.StatusOK, html)
}

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

&lt;/div&gt;



&lt;p&gt;When we visit &lt;code&gt;/&lt;/code&gt; a submission for will be rendered, to submit a new website. Under the form we will see all registered links from our &lt;code&gt;Linkmap&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;PS it is not recommended that you use html like this. You should be separating the html file or using a library like &lt;a href="https://templ.guide" rel="noopener noreferrer"&gt;templ&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The submission handler &lt;code&gt;SubmitHandler&lt;/code&gt; should look something like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func SubmitHandler(c echo.Context) error {
    url := c.FormValue("url")
    if url == "" {
        return c.String(http.StatusBadRequest, "URL is required")
    }

    if !(len(url) &amp;gt;= 4 &amp;amp;&amp;amp; (url[:4] == "http" || url[:5] == "https")) {
        url = "https://" + url
    }

    id := generateRandomString(8)

    linkMap[id] = &amp;amp;Link{Id: id, Url: url}

    return c.Redirect(http.StatusSeeOther, "/")
}

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

&lt;/div&gt;



&lt;p&gt;This handler will take a url from the form that was submitted, do some (simple) input validation and then append it to the linkMap.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Recap
&lt;/h2&gt;

&lt;p&gt;The code for our url shortener is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "math/rand"
    "net/http"
    "time"
    "github.com/labstack/echo/v4"
    "github.com/labstack/echo/v4/middleware"
)



type Link struct {
    Id string
    Url string
}

const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"

var linkMap = map[string]*Link{"example": {Id: "example", Url: "https://example.com"}}


func main() {

    e := echo.New()

    e.Use(middleware.Logger())
    e.Use(middleware.Recover())
    e.Use(middleware.Secure())

    e.GET("/:id", RedirectHandler)
    e.GET("/", IndexHandler)
    e.POST("/submit", SubmitHandler)

    e.Logger.Fatal(e.Start(":8080"))
}


func generateRandomString(length int) string {
    seededRand := rand.New(rand.NewSource(time.Now().UnixNano()))

    var result []byte 

    for i := 0; i &amp;lt; length; i++ {
        index := seededRand.Intn(len(charset))
        result = append(result, charset[index])
    }

    return string(result)
}


func RedirectHandler(c echo.Context) error {
    id := c.Param("id")
    link, found := linkMap[id]

    if !found {
        return c.String(http.StatusNotFound, "Link not found")
    }

    return c.Redirect(http.StatusMovedPermanently, link.Url)
}


func IndexHandler(c echo.Context) error {
    html := `
        &amp;lt;h1&amp;gt;Submit a new website&amp;lt;/h1&amp;gt;
        &amp;lt;form action="https://4rkal.com/submit" method="POST"&amp;gt;
        &amp;lt;label for="url"&amp;gt;Website URL:&amp;lt;/label&amp;gt;
        &amp;lt;input type="text" id="url" name="url"&amp;gt;
        &amp;lt;input type="submit" value="Submit"&amp;gt;
        &amp;lt;/form&amp;gt;
        &amp;lt;h2&amp;gt;Existing Links &amp;lt;/h2&amp;gt;
        &amp;lt;ul&amp;gt;`

    for _, link := range linkMap {
        html += `&amp;lt;li&amp;gt;&amp;lt;a href="https://4rkal.com/` + link.Id + `"&amp;gt;` + link.Id + `&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;`
    }
    html += `&amp;lt;/ul&amp;gt;`

    return c.HTML(http.StatusOK, html)
}



func SubmitHandler(c echo.Context) error {
    url := c.FormValue("url")
    if url == "" {
        return c.String(http.StatusBadRequest, "URL is required")
    }

    if !(len(url) &amp;gt;= 4 &amp;amp;&amp;amp; (url[:4] == "http" || url[:5] == "https")) {
        url = "https://" + url
    }

    id := generateRandomString(8)

    linkMap[id] = &amp;amp;Link{Id: id, Url: url}

    return c.Redirect(http.StatusSeeOther, "/")
}

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

&lt;/div&gt;



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

&lt;p&gt;This is a great small project if you are new to/learning go.&lt;/p&gt;

&lt;p&gt;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:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Enhance the input validation&lt;/li&gt;
&lt;li&gt;Track link clicks + Statistics Page&lt;/li&gt;
&lt;li&gt;Improve UI (html)&lt;/li&gt;
&lt;li&gt;Dockerizing the application&lt;/li&gt;
&lt;li&gt;++&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I did all of those and my url shortener (called shortr) can be accessed under the url &lt;a href="https://app.4rkal.com" rel="noopener noreferrer"&gt;app.4rkal.com&lt;/a&gt; and the source code is &lt;a href="https://github.com/4rkal/shortr" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Join my mailing list
&lt;/h3&gt;

&lt;p&gt;Subscribe here: &lt;a href="https://newsletter.4rkal.com/subscription/form" rel="noopener noreferrer"&gt;https://newsletter.4rkal.com/subscription/form&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Deploy django to production</title>
      <dc:creator>4rkal</dc:creator>
      <pubDate>Fri, 20 Sep 2024 08:54:29 +0000</pubDate>
      <link>https://dev.to/4rkal/deploy-django-to-production-4bn0</link>
      <guid>https://dev.to/4rkal/deploy-django-to-production-4bn0</guid>
      <description>&lt;p&gt;I recently deployed my very own django application to production. The website is called &lt;a href="https://videiro.com" rel="noopener noreferrer"&gt;videiro.com&lt;/a&gt; and was developed in django + HTML/CSS/JS + Tailwind.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;In this guide I will show you how I set this up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preparing the Django project
&lt;/h2&gt;

&lt;p&gt;The first thing you will have to do is open the settings.py and change the following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Debug = False
ALLOWED_HOSTS = ['yourdomain.tld']
CSRF_COOKIE_SECURE = True
CSRF_TRUSTED_ORIGINS = [
    'yourdomain.tld',
]

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

&lt;/div&gt;



&lt;p&gt;You should also change the &lt;code&gt;SECRET_KEY&lt;/code&gt; to a long random string, that you should never share with anyone.&lt;/p&gt;

&lt;p&gt;After that create a new file called &lt;code&gt;.gitignore&lt;/code&gt; and paste the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;db.sqlite3
*.pyc

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

&lt;/div&gt;



&lt;p&gt;This will make sure that the database is not uploaded to our server and that no pyc files are either.&lt;/p&gt;

&lt;p&gt;Now you can upload your project to a new github repository (or gitea repository). If you don’t want everyone to have access to your source code make sure to set the repository as private.&lt;/p&gt;

&lt;p&gt;If you want to make sure that your source code stays private I recommend you setup a selfhosted gitea instance, read &lt;a href="https://4rkal.com/posts/gitea/" rel="noopener noreferrer"&gt;Selfhost your own gitea instance - selfhosted, lightweight github alternative&lt;/a&gt;, to learn how to do that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git init
git branch -M main
git add .
git commit -m "initial commit"
git remote add origin https://...
git push -u origin main

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

&lt;/div&gt;



&lt;p&gt;Now that you we have done that you should login to your server&lt;/p&gt;

&lt;h2&gt;
  
  
  Server setup
&lt;/h2&gt;

&lt;p&gt;Before configuring anything make sure that you don’t allow any ssh logins with a password. Follow &lt;a href="https://4rkal.com/posts/sssh/" rel="noopener noreferrer"&gt;Securing ssh with Key-Based authentication&lt;/a&gt; to secure your server from those kinds of attacks.&lt;/p&gt;

&lt;p&gt;Login to your server&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssh user@server.ip

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

&lt;/div&gt;



&lt;p&gt;Make sure that your packages are up to data&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt update &amp;amp;&amp;amp; sudo apt upgrade

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

&lt;/div&gt;



&lt;p&gt;Now install python, pip, git and nginx&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt install python3 python3-pip git nginx

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

&lt;/div&gt;



&lt;p&gt;Now clone your project into your home directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone https://...
cd my-project

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

&lt;/div&gt;



&lt;p&gt;Once you’re in install the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install django django-crispy-forms whitenoise

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

&lt;/div&gt;



&lt;p&gt;Now try to run the project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3 manage.py runserver

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

&lt;/div&gt;



&lt;p&gt;if you get an error that a package is missing install it and re run.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring gunicorn
&lt;/h2&gt;

&lt;p&gt;Now we will setup gunicorn&lt;/p&gt;

&lt;p&gt;First install it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install gunicorn

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

&lt;/div&gt;



&lt;p&gt;Now create a new file called gunicorn.service with your favorite text editor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo vim /etc/systemd/system/gunicorn.service

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

&lt;/div&gt;



&lt;p&gt;And paste the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Unit]
Description=gunicorn daemon
After=network.target

[Service]
User=YOURUSER
Group=www-data
WorkingDirectory=/home/YOURUSER/PROJECT
ExecStart=/path/to/gunicorn --access-logfile - --workers 3 --bind 127.0.0.1:8000 PROJECTNAME.wsgi:application

[Install]
WantedBy=multi-user.target

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

&lt;/div&gt;



&lt;p&gt;Change &lt;code&gt;YOURUSER&lt;/code&gt; to your user.&lt;/p&gt;

&lt;p&gt;To find the path to &lt;code&gt;gunicorn&lt;/code&gt; run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;which gunicorn

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

&lt;/div&gt;



&lt;p&gt;And your project name is the name of the folder inside of your project that contains the &lt;code&gt;settings.py&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Now run the following commands to start and enable gunicorn (start on boot)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo systemctl daemon-reload
sudo systemctl start gunicorn.service
sudo systemctl enable gunicorn.service

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

&lt;/div&gt;



&lt;p&gt;Now if you head to 127.0.0.1:8000 you should see your project running.&lt;/p&gt;

&lt;p&gt;But were not finished yet&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up nginx
&lt;/h2&gt;

&lt;p&gt;Now we need to serve our static content via nginx.&lt;/p&gt;

&lt;p&gt;First create a new file nginx configuration file with your favorite text editor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo vim /etc/nginx/sites-available/PROJECT

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

&lt;/div&gt;



&lt;p&gt;Change PROJECT to whatever you want&lt;/p&gt;

&lt;p&gt;Now paste the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;server {
    listen 80;
    server_name YOURDOMAIN;

    location /static/ {
    alias /var/www/staticfiles/;
    }

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

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

&lt;/div&gt;



&lt;p&gt;Just change YOURDOMAIN to the domain that this will be hosted on.&lt;/p&gt;

&lt;p&gt;Create a symbolic link to enable your website:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo ln -s /etc/nginx/sites-available/PROJECT /etc/nginx/sites-enabled/

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

&lt;/div&gt;



&lt;p&gt;Start and enable nginx:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo systemctl start nginx
sudo systemctl enable nginx

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Setup static files
&lt;/h2&gt;

&lt;p&gt;The first thing you will have to do is cd into your (django) project&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd project

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

&lt;/div&gt;



&lt;p&gt;Now run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3 manage.py collectstatic

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

&lt;/div&gt;



&lt;p&gt;This will create a new folder called &lt;code&gt;staticfiles&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now to set up the static files we have two options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Change the user in &lt;code&gt;/etc/nginx/nginx.conf&lt;/code&gt; to your user (less secure)&lt;/li&gt;
&lt;li&gt;Copy over the staticfiles to &lt;code&gt;/var/www/&lt;/code&gt; (more secure)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I will be doing the 2nd option:&lt;/p&gt;

&lt;p&gt;First create a new file called staticfiles in /var/www&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo mkdir -p /var/www/staticfiles

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

&lt;/div&gt;



&lt;p&gt;Now copy over all of the staticfiles from your project there:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo cp staticfiles/* /var/www/staticfiles

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

&lt;/div&gt;



&lt;p&gt;Now cd into /var/www&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd /var/www

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

&lt;/div&gt;



&lt;p&gt;Change the ownership of all the files&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo chown www-data:www-data staticfiles
sudo chown www-data:www-data staticfiles/*

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

&lt;/div&gt;



&lt;p&gt;Restart the nginx service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo systemctl restart nginx

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

&lt;/div&gt;



&lt;p&gt;Now if you head to:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;127.0.0.1&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You should see your website running with all of the static files being served!&lt;/p&gt;

&lt;h2&gt;
  
  
  Exposing via cloudflare tunnels
&lt;/h2&gt;

&lt;p&gt;Now to make your website publicly accessible.&lt;/p&gt;

&lt;p&gt;To do this you will need a cloudflare account and a domain pointed to cloudflare.&lt;/p&gt;

&lt;p&gt;First head to the &lt;a href="https://one.dash.cloudflare.com/" rel="noopener noreferrer"&gt;Zero Trust Dashboard&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Under &lt;code&gt;Networks&lt;/code&gt; click on &lt;code&gt;Tunnels&lt;/code&gt; and then &lt;code&gt;Create a tunnel&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Once created you should &lt;code&gt;Install and run a connector&lt;/code&gt;, follow the instructions on the page for your specific setup.&lt;/p&gt;

&lt;p&gt;After the connector is running you should click on the &lt;code&gt;Public Hostname&lt;/code&gt; tab and &lt;code&gt;Add a public hostname&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now you should see something like this: &lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F780if1qou03qlkwt5ihq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F780if1qou03qlkwt5ihq.png" alt="Cloudflare dashboard" width="800" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fill in the info as I have. The service type should be &lt;code&gt;HTTP&lt;/code&gt; and the url should be &lt;code&gt;127.0.0.1:80&lt;/code&gt; or &lt;code&gt;localhost:80&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now if you head to the domain that you specified you should see your app up and running.&lt;/p&gt;

&lt;p&gt;Congratulations!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you enjoyed this post and want to support my (mostly unpaid) work , you can &lt;a href="https://4rkal.com/donate" rel="noopener noreferrer"&gt;donate here&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Join my free newsletter!
&lt;/h2&gt;

&lt;p&gt;Join &lt;a href="https://newsletter.4rkal.com/subscription/form" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

</description>
      <category>django</category>
      <category>python</category>
      <category>linux</category>
    </item>
    <item>
      <title>Selfhost your own gitea instance - selfhosted, lightweight github alternative</title>
      <dc:creator>4rkal</dc:creator>
      <pubDate>Mon, 19 Aug 2024 16:21:15 +0000</pubDate>
      <link>https://dev.to/4rkal/selfhost-your-own-gitea-instance-selfhosted-lightweight-github-alternative-4gf2</link>
      <guid>https://dev.to/4rkal/selfhost-your-own-gitea-instance-selfhosted-lightweight-github-alternative-4gf2</guid>
      <description>&lt;p&gt;In this article I’ll walk you through how you can run your own gitea instance. But first&lt;/p&gt;

&lt;h2&gt;
  
  
  What is gitea?
&lt;/h2&gt;

&lt;p&gt;Gitea is a painless selfhosted Git service. It is written in Go and is extremely lightweight. I run a gitea instance on my &lt;a href="https://libre.computer/products/aml-s905x-cc/" rel="noopener noreferrer"&gt;Le Potato&lt;/a&gt; and it barely uses any resources.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why use gitea (vs GitHub, GitLab etc)
&lt;/h2&gt;

&lt;p&gt;I started running my own Gitea instance because I wanted a private place to host my &lt;a href="https://obsidian.md" rel="noopener noreferrer"&gt;Obsidian&lt;/a&gt; notes. I did not want to have them in a private GitHub repository since it’s not on my own hardware. GitLab is harder to spin up and has a lot of features that I do not need.&lt;/p&gt;

&lt;p&gt;If you want an easy to spin up, private git service gitea is your way to go.&lt;/p&gt;

&lt;h1&gt;
  
  
  Setup
&lt;/h1&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing and setting up docker
&lt;/h2&gt;

&lt;p&gt;The first thing you will need is docker installed on your system.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.docker.com/engine/install/debian/" rel="noopener noreferrer"&gt;Install docker on debian&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also make sure to add your user to the docker group. This will allow you to run docker commands without sudo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;usermod -aG docker $USER

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

&lt;/div&gt;



&lt;p&gt;Now reboot&lt;/p&gt;

&lt;h2&gt;
  
  
  Docker-compose.yml
&lt;/h2&gt;

&lt;p&gt;Once docker is installed. We have to get gitea up and running&lt;/p&gt;

&lt;p&gt;First create a new directory. This will host our docker-compose file.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;mkdir gitea&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then create/edit docker-compose.yml in your favourite text editor.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;vim docker-compose.yml&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then paste the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;version: "3"

networks:
  gitea:
    external: false

services:
  server:
    image: gitea/gitea:latest
    container_name: gitea
    environment:
      - USER_UID=1000
      - USER_GID=1000
    restart: always
    networks:
      - gitea
    volumes:
      - ./gitea:/data
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    ports:
      - "3000:3000"
      - "222:22"

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

&lt;/div&gt;



&lt;p&gt;You can change any of the default ports eg switching 3000 to 8000 can be done like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ports:
- "8080:3000"

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

&lt;/div&gt;



&lt;p&gt;You can setup gitea using a &lt;a href="https://docs.gitea.com/installation/install-with-docker#postgresql-database" rel="noopener noreferrer"&gt;PostgreSQL&lt;/a&gt; or &lt;a href="https://docs.gitea.com/installation/install-with-docker#mysql-database" rel="noopener noreferrer"&gt;MySQL&lt;/a&gt; database. But at least for my needs a simple SQLite3 database is more than enough.&lt;/p&gt;

&lt;p&gt;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:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;version: "3"

networks:
  gitea:
    external: false

volumes:
  gitea:
    driver: local

services:
  server:
    image: gitea/gitea:latest
    container_name: gitea
    restart: always
    networks:
      - gitea
    volumes:
      - gitea:/data
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    ports:
      - "3000:3000"
      - "222:22"

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Starting the container and additional configuration
&lt;/h2&gt;

&lt;p&gt;Now you can start the container by typing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker compose up -d

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

&lt;/div&gt;



&lt;p&gt;The -d flag will run it in detach mode. If you want to see the logs live you can remove it.&lt;/p&gt;

&lt;p&gt;After docker is done pulling, gitea should be up and running.&lt;/p&gt;

&lt;p&gt;Now open up:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;localhost:3000&lt;/code&gt; or &lt;code&gt;yourserverip:3000&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And you should see something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqstieqgq6k7i2xs1d317.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqstieqgq6k7i2xs1d317.png" alt="Gitea Setup Dashboard" width="800" height="1314"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fill in all of the required information. Since I will be using my subdomain &lt;code&gt;git.4rkal.com&lt;/code&gt; I set the server domain and gitea base url to that.&lt;/p&gt;

&lt;p&gt;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 &lt;a href="https://cock.li" rel="noopener noreferrer"&gt;cock.li&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After you have entered all the required info click on &lt;code&gt;Install Gitea&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;After the installation is complete you should be up and running&lt;/p&gt;

&lt;h1&gt;
  
  
  Make publicly accessible with cloudflare tunnels (optional)
&lt;/h1&gt;

&lt;p&gt;I will be making my instance publicly accessible using cloudflare tunnels.&lt;/p&gt;

&lt;p&gt;To do this you will need a cloudflare account and a domain pointed to cloudflare.&lt;/p&gt;

&lt;p&gt;First head to the &lt;a href="https://one.dash.cloudflare.com/" rel="noopener noreferrer"&gt;Zero Trust Dashboard&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Under &lt;code&gt;Networks&lt;/code&gt; click on &lt;code&gt;Tunnels&lt;/code&gt; and then &lt;code&gt;Create a tunnel&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Once created you should &lt;code&gt;Install and run a connector&lt;/code&gt;, follow the instructions on the page for your specific setup.&lt;/p&gt;

&lt;p&gt;After the connector is running you should click on the &lt;code&gt;Public Hostname&lt;/code&gt; tab and &lt;code&gt;Add a public hostname&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now you should see something like this: &lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F780if1qou03qlkwt5ihq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F780if1qou03qlkwt5ihq.png" alt="Zero Trust Dashboard" width="800" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fill in the info as I have.&lt;/p&gt;

&lt;p&gt;You can create a new subdomain eg git or gitea&lt;/p&gt;

&lt;p&gt;The service type should be &lt;code&gt;HTTP&lt;/code&gt; and the url should be &lt;code&gt;yourserverurl:3000&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now if you head to the domain that you specified you should see gitea up and running.&lt;/p&gt;

&lt;p&gt;In my case you can access my public gitea instance at &lt;a href="https://git.4rkal.com" rel="noopener noreferrer"&gt;git.4rkal.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Congratulations, you now have your very own gitea instance!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you enjoyed this article, consider &lt;a href="https://4rkal.eu.org/donate" rel="noopener noreferrer"&gt;supporting me&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Improving Golang API request performance</title>
      <dc:creator>4rkal</dc:creator>
      <pubDate>Sat, 17 Aug 2024 09:25:15 +0000</pubDate>
      <link>https://dev.to/4rkal/improving-golang-api-request-performance-1ae4</link>
      <guid>https://dev.to/4rkal/improving-golang-api-request-performance-1ae4</guid>
      <description>&lt;h1&gt;
  
  
  The project
&lt;/h1&gt;

&lt;p&gt;I recently started working on a &lt;em&gt;cryptocurrency exchange aggregator&lt;/em&gt;. 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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h1&gt;
  
  
  Improvements
&lt;/h1&gt;

&lt;p&gt;These improvements come in order of biggest improvement of runtime.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Using goroutines
&lt;/h3&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Goroutines are amazing and extremely easy to use. You should include them wherever possible. But always be careful of &lt;a href="https://go.dev/doc/articles/race_detector" rel="noopener noreferrer"&gt;Data Races&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Upgrading the JSON Library
&lt;/h3&gt;

&lt;p&gt;I swapped out &lt;code&gt;encoding/json&lt;/code&gt; for &lt;code&gt;github.com/json-iterator/go&lt;/code&gt;.&lt;code&gt;jsoniter&lt;/code&gt; 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.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Benchmark Results&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To measure the performance improvements, I ran some benchmarks comparing &lt;code&gt;encoding/json&lt;/code&gt; and &lt;code&gt;jsoniter&lt;/code&gt;. Here’s a summary of the results:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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

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

&lt;/div&gt;



&lt;p&gt;So, &lt;code&gt;jsoniter&lt;/code&gt; is about 6 times faster than the standard library.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Reusing HTTP Handlers
&lt;/h3&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Benchmark Results&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here are the results of the benchmarks comparing reused handlers versus creating new handlers for each request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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

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

&lt;/div&gt;



&lt;p&gt;Reusing HTTP handlers gave a slight performance boost compared to making a new handler for each request.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;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!&lt;/p&gt;

&lt;p&gt;If you are interested the code for my benchmarks, it is available &lt;a href="https://git.4rkal.com/4rkal/goapiperf" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you enjoyed this post and want to support my work, you can &lt;a href="https://4rkal.com/donate" rel="noopener noreferrer"&gt;donate here&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>api</category>
    </item>
    <item>
      <title>My Obsidian + Hugo blogging setup</title>
      <dc:creator>4rkal</dc:creator>
      <pubDate>Tue, 13 Aug 2024 14:15:57 +0000</pubDate>
      <link>https://dev.to/4rkal/my-obsidian-hugo-blogging-setup-auto-publishing-with-hotkeys-365d</link>
      <guid>https://dev.to/4rkal/my-obsidian-hugo-blogging-setup-auto-publishing-with-hotkeys-365d</guid>
      <description>&lt;p&gt;If you clicked on this article you probably know what these two technologies are but if you don’t here’s a quick explanation:&lt;/p&gt;

&lt;h3&gt;
  
  
  Obsidian
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://obsidian.md" rel="noopener noreferrer"&gt;Obsidian&lt;/a&gt; is a feature packed markdown editor. But it’s not just a markdown editor. It’s a way to manage knowledge. It’s great for organizing your thoughts in a flexible, non-linear way.&lt;/p&gt;

&lt;p&gt;Obsidian works on all platforms. So you can write articles from basically any platform.&lt;/p&gt;

&lt;p&gt;I have been taking all of my notes in it for a couple of months now and it’s amazing!&lt;/p&gt;

&lt;h3&gt;
  
  
  Hugo
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://gohugo.io" rel="noopener noreferrer"&gt;Hugo&lt;/a&gt; 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 &lt;a href="https://4rkal.eu.org/posts/newlook?utm_source=internal&amp;amp;utm_campaign=obsidianhugo" rel="noopener noreferrer"&gt;New Look, new start&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Setup
&lt;/h1&gt;

&lt;p&gt;In this article I will not be showing how to setup these two technologies but merely how to get them to work together.&lt;/p&gt;

&lt;p&gt;If you wan’t to learn how I setup this whole blog using hugo, cloudflare and render.com read:&lt;a href="https://4rkal.eu.org/posts/thisblog?utm_source=internal&amp;amp;utm_campaign=obsidianhugo" rel="noopener noreferrer"&gt;How I setup this blog for free (domain, hosting, ssl) Complete Guide&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you wan’t a good guide on how to use obsidian read:&lt;a href="https://help.obsidian.md/Getting+started/Download+and+install+Obsidian" rel="noopener noreferrer"&gt;Getting started - obsidian.md&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Goals
&lt;/h1&gt;

&lt;p&gt;My goals for the setup are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Using a single &lt;a href="https://help.obsidian.md/Getting+started/Create+a+vault" rel="noopener noreferrer"&gt;obsidian vault&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Have an easy to use &lt;a href="https://help.obsidian.md/Plugins/Templates" rel="noopener noreferrer"&gt;obsidian template&lt;/a&gt; that I can use for my blog posts.&lt;/li&gt;
&lt;li&gt;Keep my personal vault folders private.&lt;/li&gt;
&lt;li&gt;Auto publish using obsidian hotkeys.&lt;/li&gt;
&lt;li&gt;Have all markdown files in a &lt;a href="https://github.com/4rkal/blog/" rel="noopener noreferrer"&gt;public github repository&lt;/a&gt;, so that people can propose changes&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Existing setup
&lt;/h1&gt;

&lt;p&gt;The way that my current work flow works is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Edit articles from the content folder.&lt;/li&gt;
&lt;li&gt;Run hugo command.&lt;/li&gt;
&lt;li&gt;Push to github.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://render.com" rel="noopener noreferrer"&gt;Render.com&lt;/a&gt; automatically picks up the changes and serves them.&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Journey
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;If you want to skip the journey part you can go straight to The Sauce&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I will be going through a couple of mistakes that I made while setting this up.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mistake #1
&lt;/h3&gt;

&lt;p&gt;The first idea that I had was to create a simple symlink (I use linux btw) that would link the two folders together.&lt;/p&gt;

&lt;p&gt;Basically I have two folders:&lt;br&gt;
&lt;/p&gt;

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

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

&lt;/div&gt;



&lt;p&gt;The blog folder contains all the blog folders and the vault is my personal vault.&lt;/p&gt;

&lt;p&gt;The symlink would link these folders&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;blog/content
vault/Blog

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

&lt;/div&gt;



&lt;p&gt;However &lt;strong&gt;the problem&lt;/strong&gt; 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&lt;/p&gt;

&lt;h3&gt;
  
  
  Mistake #2
&lt;/h3&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Sauce
&lt;/h1&gt;

&lt;p&gt;Basically the way that I have set this up is I have two folders:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;blog
vault

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

&lt;/div&gt;



&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;I created a new folder inside of my vault called Blog&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;blog/content
vault/Blog

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

&lt;/div&gt;



&lt;p&gt;After that I copied over all of my files from the content directory to the Blog.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I then started writing this very article&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Obsidian templates
&lt;/h2&gt;

&lt;p&gt;I needed some way to setup a simple template to contain all of the required hugo front matter.&lt;/p&gt;

&lt;p&gt;That is quite easy.&lt;/p&gt;

&lt;p&gt;Read about how to setup templates &lt;a href="https://help.obsidian.md/Plugins/Templates" rel="noopener noreferrer"&gt;Templates - obsidian.md&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I created a file called &lt;code&gt;Blog Post&lt;/code&gt; in my templates folder&lt;/p&gt;

&lt;p&gt;My &lt;code&gt;Blog Post&lt;/code&gt; template contains the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
title: "{{Title}}"
description: 
date: "{{date:YYYY-MM-DD}}T{{time:HH:mm:ss}}+00:00"
draft: true
---

**If you enjoyed this article consider [supporting me](https://4rkal.eu.org/donate)**

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

&lt;/div&gt;



&lt;p&gt;I have all the required front matter including a title, description and a date in the format that hugo asks.&lt;/p&gt;

&lt;p&gt;I also added a small donation text that I include at the bottom of every article.&lt;/p&gt;

&lt;p&gt;This means that I can automatically insert this template into any file and start writing!&lt;/p&gt;

&lt;h2&gt;
  
  
  Folder Syncing
&lt;/h2&gt;

&lt;p&gt;Now I want all of my files in my vault/Blog directory to be copied over to the blog/content&lt;/p&gt;

&lt;p&gt;Thank’s to a helpful discord user I found the &lt;a href="https://github.com/Taitava/obsidian-shellcommands" rel="noopener noreferrer"&gt;obsidian-shellcommands&lt;/a&gt; plugin.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; 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.&lt;/p&gt;

&lt;p&gt;It allows you to run shell commands in the background with a hotkey.&lt;/p&gt;

&lt;p&gt;The steps to set this up are the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://obsidian.md/plugins?search=shell%20commands" rel="noopener noreferrer"&gt;Install the plugin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Enable the plugin&lt;/li&gt;
&lt;li&gt;Go to the plugin options&lt;/li&gt;
&lt;li&gt;Click on &lt;code&gt;New shell command&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Now you will need to enter a shell command to copy the files from the one folder to the other.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;On Linux/MacOS that is:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cp -a ~/folder1/. ~/folder2/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;in my case that is &lt;code&gt;cp -a ~/Documents/vault/Blog/. ~/Documents/blog2/content/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;On windows it most probably is:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;robocopy "%USERPROFILE%\folder1" "%USERPROFILE%\folder2" /E /COPYALL&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After that we need to set a hotkey that will run the command&lt;/p&gt;

&lt;p&gt;Click on the (+) icon to go to the hotkey settings and assign a hotkey&lt;/p&gt;

&lt;p&gt;My hotkey is &lt;code&gt;CTR + 0&lt;/code&gt;, simply because that was available.&lt;/p&gt;

&lt;p&gt;Now every time that I run the hotkey it copies over all of my files to the hugo folder ready to be published&lt;/p&gt;

&lt;h2&gt;
  
  
  Auto publishing scripts
&lt;/h2&gt;

&lt;p&gt;I also want to be able to automatically publish my articles. But I want it to happening by hitting a hotkey.&lt;/p&gt;

&lt;p&gt;I wrote a small script that does exactly that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/bash
cd ~/Documents/blog

hugo

git add .
git commit -m "new"
git push -u origin main

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

&lt;/div&gt;



&lt;p&gt;This script will build my website, commit and push to my github repo, where it is picked up and published. Read &lt;a href="https://4rkal.eu.org/posts/thisblog?utm_source=internal&amp;amp;utm_campaign=obsidianhugo" rel="noopener noreferrer"&gt;How I setup this blog for free (domain, hosting, ssl) Complete Guide&lt;/a&gt; to learn how to setup your own blog for free.&lt;/p&gt;

&lt;p&gt;Don’t forget to make the script executable by running&lt;/p&gt;

&lt;p&gt;&lt;code&gt;chmod +x ./YOURSCRIPT.sh&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then create a new shell command for the shellcommand plugin (as we did before) and enter the path to your script.&lt;/p&gt;

&lt;p&gt;In my case that is:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;~/Documents/blog2/push.sh&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then enter a hotkey and you’re done!&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I can now simply open my obsidian vault, create a new file, insert my template and have all the info automatically entered.&lt;/p&gt;

&lt;p&gt;I then write my article inside of obsidian&lt;/p&gt;

&lt;p&gt;Run my hotkey and copy all the files into the hugo directory&lt;/p&gt;

&lt;p&gt;Hit another key and my blog is published!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you enjoyed this article consider &lt;a href="https://4rkal.eu.org/donate" rel="noopener noreferrer"&gt;supporting me&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>obsidian</category>
      <category>hugo</category>
      <category>go</category>
    </item>
    <item>
      <title>Ultimate Monero ColdStorage Guide (Feather X Anonero)</title>
      <dc:creator>4rkal</dc:creator>
      <pubDate>Thu, 14 Dec 2023 18:00:30 +0000</pubDate>
      <link>https://dev.to/4rkal/ultimate-monero-coldstorage-guide-feather-x-anonero-3gi2</link>
      <guid>https://dev.to/4rkal/ultimate-monero-coldstorage-guide-feather-x-anonero-3gi2</guid>
      <description>&lt;p&gt;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!&lt;/p&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;An old laptop/computer with a webcam (to be kept offline). Called &lt;strong&gt;offline&lt;/strong&gt; or &lt;strong&gt;cold&lt;/strong&gt; computer.&lt;/li&gt;
&lt;li&gt;An android smartphone.&lt;/li&gt;
&lt;li&gt;Your main computer&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Required reads
&lt;/h2&gt;

&lt;p&gt;Before starting this article you &lt;strong&gt;must&lt;/strong&gt; read:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://malvarma.org/before_we_start/what_things_mean.html" rel="noopener noreferrer"&gt;Key concepts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://monero.stackexchange.com/questions/2426/offline-transaction-signing-what-are-the-details" rel="noopener noreferrer"&gt;Monero offline transaction signing details&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Cold computer setup
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;I will not be guiding you on how to install [[linux]]. But here are some resourses to help you get started:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://peppermintos.com/guide/downloading/" rel="noopener noreferrer"&gt;Installing PeperMintOS&lt;/a&gt; &amp;lt;– somewhat 32 bit support, lightweight&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://linuxmint-installation-guide.readthedocs.io/en/latest/install.html" rel="noopener noreferrer"&gt;Installing LinuxMint&lt;/a&gt; &amp;lt;– better for newer computers&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.makeuseof.com/how-to-install-mx-linux/" rel="noopener noreferrer"&gt;Installing MX Linux&lt;/a&gt; &amp;lt;– 32 bit support, pretty lightweight&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Downloading &amp;amp; Installing necessary software
&lt;/h3&gt;

&lt;p&gt;The first thing that we will need to do is download the required software.&lt;/p&gt;

&lt;p&gt;We will need &lt;a href="https://featherwallet.org" rel="noopener noreferrer"&gt;featherwallet&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and that’s about it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Taking the device offline
&lt;/h3&gt;

&lt;p&gt;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’re going full on &lt;a href="https://i.imgur.com/p5h6STu.jpeg" rel="noopener noreferrer"&gt;tinfoilhat&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here’s a guide on how to physically disable them from &lt;a href="https://malvarma.org/cold_wallet/prepare_the_hardware.html" rel="noopener noreferrer"&gt;malvarma.org&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A guide on how to disable it via BIOS can be found by searching your specific hardware on your &lt;a href="https://searx.org/" rel="noopener noreferrer"&gt;favorite search engine&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Computer cold wallet setup
&lt;/h3&gt;

&lt;p&gt;Now we will have to setup our wallet. Ensure that your device is completely &lt;strong&gt;offline&lt;/strong&gt; and then open featherwallet.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click on &lt;code&gt;Create a new wallet&lt;/code&gt;. Then click on &lt;code&gt;Next&lt;/code&gt;. You will be presented with your seedphrase. &lt;strong&gt;Write it down!! on physical paper&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Select a name for your wallet and click &lt;code&gt;Next&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Select a wallet password and click &lt;code&gt;Next&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;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 &lt;code&gt;Disable all network connections (offline)&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Phone
&lt;/h2&gt;

&lt;p&gt;We will now be installing the anonero software. We will be using NERO from the ANON/NERO suite.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Download and install fdroid. Apk can be downloaded from the &lt;a href="https://fdroid.org" rel="noopener noreferrer"&gt;F-Droid website&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Download and install orbot. Can be installed from google play store &lt;a href="https://play.google.com/store/apps/details?id=org.torproject.android" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Open orbot. Select &lt;code&gt;VPN Mode&lt;/code&gt;, click on the onion logo that says &lt;code&gt;start&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Open fdroid and in the settings scroll down and enable &lt;code&gt;Use Tor&lt;/code&gt; option&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Again in the settings that click on the repositories section and add the following:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click on latest and then search for NERO&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click on install That’s it ; )&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Updating NERO
&lt;/h3&gt;

&lt;p&gt;If you want to update NERO you will have to turn orbot on, open fdroid and refresh the updates tab&lt;/p&gt;

&lt;h3&gt;
  
  
  NERO setup
&lt;/h3&gt;

&lt;p&gt;To set up NERO, follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Once NERO is successfully installed, open the application.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click on &lt;code&gt;RESTORE WALLET&lt;/code&gt; option and select &lt;code&gt;RESTORE FROM KEYS&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Proceed to establish a node connection. You can find a lot of Monero nodes &lt;a href="https://monero.fail" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Copy the node address into the node field. By default you shouldn’t need a username or password&lt;/p&gt;

&lt;p&gt;By default tor connectivity is enabled in NERO. You can disable it by going into the proxy settings and deleting everything.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click on &lt;code&gt;Connect&lt;/code&gt;. It will try connecting. If it fails check your internet connection or try another node&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Importing view-only wallet
&lt;/h3&gt;

&lt;p&gt;Now you will have to import your wallets &lt;code&gt;Primary address&lt;/code&gt; , &lt;code&gt;Secret-View key&lt;/code&gt; and &lt;code&gt;Restore height&lt;/code&gt; into NERO. To import that info to nero:&lt;/p&gt;

&lt;p&gt;On your offline computer open featherwallet and navigate to &lt;code&gt;Wallet&lt;/code&gt; then &lt;code&gt;View-Only&lt;/code&gt;. Enter your password and click on the &lt;code&gt;Show QR&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;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 &lt;code&gt;Next&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Set a pin. After that your wallet should be imported into NERO.&lt;/p&gt;

&lt;h2&gt;
  
  
  Receiving monero
&lt;/h2&gt;

&lt;p&gt;To receive monero you can follow these steps&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open NERO and enter your pin&lt;/li&gt;
&lt;li&gt;Click on the receive tab (the one with the qr code icon)&lt;/li&gt;
&lt;li&gt;Long hold on the address&lt;/li&gt;
&lt;li&gt;Select one of the SubAddreses and click on the copy icon.&lt;/li&gt;
&lt;li&gt;Transfer any amount of monero to that address.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After 10 confirmations it should be spendable. Proceed to the next step.&lt;/p&gt;

&lt;h2&gt;
  
  
  Signing transactions
&lt;/h2&gt;

&lt;p&gt;Signing/Broadcasting transactions is easy with the NERO/Feather duo. No usbs are needed it is all done via animated QR codes.&lt;/p&gt;

&lt;p&gt;To sign/broadcast a transaction follow these steps On your phone:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open NERO and enter your pin&lt;/li&gt;
&lt;li&gt;In the send tab enter the desired address and amount&lt;/li&gt;
&lt;li&gt;Click on continue, you should now see an animated QR code.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;On your cold computer&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open feather and enter your password&lt;/li&gt;
&lt;li&gt;Click on &lt;code&gt;Tools&lt;/code&gt; &amp;gt; &lt;code&gt;Offline transaction signing&lt;/code&gt;. You should now see your camera&lt;/li&gt;
&lt;li&gt;Show your phone to the computers camera so that it can read the QR code.&lt;/li&gt;
&lt;li&gt;After it has been picked up by your computer you should see a QR code displayed on your computers screen&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In NERO.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click on &lt;code&gt;SCAN KEY IMAGES&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Scan the QR code from the computer’s screen&lt;/li&gt;
&lt;li&gt;Once it has been picked up you can see the &lt;code&gt;Address&lt;/code&gt;, &lt;code&gt;Amount&lt;/code&gt;, &lt;code&gt;Fee&lt;/code&gt; and &lt;code&gt;Total&lt;/code&gt;. Click on &lt;code&gt;confirm&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;You should now see the unsigned TX screen.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In feather click on &lt;code&gt;Next&lt;/code&gt;. Then scan the QR code displayed by NERO to your computer. Once the bar is at 100%, you should again see the &lt;code&gt;Address&lt;/code&gt;, &lt;code&gt;Amount&lt;/code&gt;, &lt;code&gt;Fee&lt;/code&gt; and &lt;code&gt;Total&lt;/code&gt;. If your ok with that click on SIGN.&lt;/p&gt;

&lt;p&gt;In NERO&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click on &lt;code&gt;SCAN SIGNED TX&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Scan the QR displayed by feather wallet.&lt;/li&gt;
&lt;li&gt;Click on &lt;code&gt;Yes&lt;/code&gt;, once asked whether or not to broadcast transaction&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You have now sent the transaction.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;if this article helped you out consider &lt;a href="//../../donate/"&gt;supporting me&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>SSH Remote Access NO Port-Forwarding NO Cloudflare</title>
      <dc:creator>4rkal</dc:creator>
      <pubDate>Wed, 04 Oct 2023 16:17:04 +0000</pubDate>
      <link>https://dev.to/4rkal/ssh-remote-access-no-port-forwarding-no-cloudflare-586f</link>
      <guid>https://dev.to/4rkal/ssh-remote-access-no-port-forwarding-no-cloudflare-586f</guid>
      <description>&lt;p&gt;In this article I will show you how I securely connect to my remote machines without having to configure port forwarding.&lt;/p&gt;

&lt;h2&gt;
  
  
  Requirements:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;A computer “server” (running linux)&lt;/li&gt;
&lt;li&gt;A internet connection&lt;/li&gt;
&lt;li&gt;Another computer to connect to your server (running linux)&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Why?
&lt;/h2&gt;

&lt;p&gt;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!&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;You will have to install the following packages (ssh, tor)&lt;/p&gt;

&lt;p&gt;On debian&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo apt install openssh-client&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;On arch&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo pacman -S openssh&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After that enable the ssh service&lt;/p&gt;

&lt;p&gt;Debian:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo systemctl enable ssh&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Arch:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo systemctl enable sshd&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If you want to check if this worked just use another computer and run&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ssh USER@IP&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;for example I run&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ssh arkal@192.168.1.69&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After this you can enable KeyBased authentication for more security&lt;/p&gt;

&lt;p&gt;Here is my article how to enable that :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/4rkal/securing-ssh-with-key-based-authentication-56kl-temp-slug-1327575"&gt;Enable keybased authentication&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we need to install tor:&lt;/p&gt;

&lt;p&gt;On debian&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo apt install tor&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;On arch&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo pacman -S tor&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then start and enable the tor service with&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo systemctl start tor &amp;amp;&amp;amp; sudo systemctl enable tor&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After you have done that you want to edit your torrc file. Using your favorite text editor&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo vim /etc/tor/torrc&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now you will want to navigate to the part that says HiddenService. And paste the following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HiddenServiceDir /var/lib/tor/ssh/
HiddenServicePort 22 127.0.0.1:22

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

&lt;/div&gt;



&lt;p&gt;Save your file and exit the editor (for nano cntrl s, cntrl x)&lt;/p&gt;

&lt;p&gt;Now you want will have to restart the tor service&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo systemctl restart tor&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After that run the following:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo cat /var/lib/tor/ssh/hostname&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You should see a string of letters and characters ending in .onion &lt;/p&gt;

&lt;p&gt;Now on your other machine:&lt;/p&gt;

&lt;h2&gt;
  
  
  Connecting to the server
&lt;/h2&gt;

&lt;p&gt;On your main machine you will have to do the following:&lt;/p&gt;

&lt;p&gt;Have ssh, tor, and socat installed&lt;/p&gt;

&lt;p&gt;After you have installed them you will have to edit the ssh config&lt;/p&gt;

&lt;p&gt;&lt;code&gt;vim .ssh/config&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And paste the following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Host NAME
 Hostname URL.onion
 User USER
 Port 22
 Proxycommand socat - SOCKS4A:127.0.0.1:%h:%p,socksport=9050

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

&lt;/div&gt;



&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Now save the file and exit.&lt;/p&gt;

&lt;p&gt;Now edit the torrc file. Using your favorite text editor:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;vim /etc/tor/torrc&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Find the line that says SOCKSPort and uncomment it&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SOCKSPort 9050&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Restart the tor service&lt;/p&gt;

&lt;p&gt;&lt;code&gt;systemctl restart tor&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;To connect to the server run the following command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ssh NAME&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;With NAME being the name that you gave to the server in the config file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If this article helped you out consider &lt;a href="https://4rkal.eu.org/donate" rel="noopener noreferrer"&gt;supporting me&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Python for Complete Beginners</title>
      <dc:creator>4rkal</dc:creator>
      <pubDate>Mon, 06 Mar 2023 17:52:42 +0000</pubDate>
      <link>https://dev.to/4rkal/python-for-complete-beginners-h47</link>
      <guid>https://dev.to/4rkal/python-for-complete-beginners-h47</guid>
      <description>&lt;p&gt;Why you should use Python. Going over the basics of Python.&lt;/p&gt;

&lt;p&gt;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’s start by explaining what coding is.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is coding?
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Python?
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Python?
&lt;/h2&gt;

&lt;p&gt;Python is one of the most popular computer languages and it’s very concise — that is, you don’t need to type much in order to create programs that do a lot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advantages of python
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Simple to read, learn, and write&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Python is a high-level programming language with a syntax that is similar to English. This makes the code easier to read and comprehend.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Improved Productivity&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Python is an extremely useful programming language. Python’s simplicity allows developers to concentrate on solving the problem.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Free and Open-Source&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Portability&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Downloading Python
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;On Linux&lt;/strong&gt; You probably already know how to install it but I’m gonna show it anyways.&lt;/p&gt;

&lt;p&gt;Open your terminal and type python or python3; if it does not work then run: (depending on your distro)&lt;code&gt;sudo apt install python3&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Windows 10&lt;/strong&gt; 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’t already have it installed go to &lt;a href="https://python.org" rel="noopener noreferrer"&gt;https://python.org&lt;/a&gt;, download the correct version for your computer and then install it.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Python comes in different versions. This course uses version 3 and upwards. I recommend always installing the latest version.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What is an IDE?
&lt;/h2&gt;

&lt;p&gt;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).&lt;/p&gt;

&lt;p&gt;The IDE that we will be using in this series is called VS Code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Downloading VS Code
&lt;/h2&gt;

&lt;p&gt;Go to &lt;a href="https://code.visualstudio.com/" rel="noopener noreferrer"&gt;https://code.visualstudio.com/&lt;/a&gt; and download the version that you want. Vs Code is available for Windows, Mac, and Linux. Follow the instructions on the website for installation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Starting in Python
&lt;/h2&gt;

&lt;p&gt;It’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.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open Vs Code and click on File &amp;gt; New File and name your file helloworld.py. The .py tells the computer that this is a Python program.&lt;/li&gt;
&lt;li&gt;In your project, in VS Code type :&lt;code&gt;print("Hello World!")&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Save your project and click on the run button at the top of your screen&lt;/li&gt;
&lt;li&gt;If you have done everything correctly you should see a Hello World message in your terminal.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If it didn’t work you should get a red error message something like this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SyntaxError: invalid syntax&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If that happens make sure that you have copied it exactly like above.&lt;/p&gt;

&lt;h2&gt;
  
  
  Playing With numbers in Python
&lt;/h2&gt;

&lt;p&gt;Python makes it easy to do maths. You just type in a question and get the answer&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Adding Up&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Open an empty project and type:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;print(2+2)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You should see the answer:&lt;code&gt;4&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Subtracting(and more)&lt;/strong&gt;If you want to subtract, use the ‘-’ symbol like this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;print(2 - 2)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;To multiply use the ‘*’ symbol:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;print(2 * 2)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;To divide, use the ‘/’ symbol&lt;/p&gt;

&lt;p&gt;&lt;code&gt;print(2 / 2)&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Variables
&lt;/h2&gt;

&lt;p&gt;A variable is like a labelled box that stores information. You can change this information but the label stays the same.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a variable:
&lt;/h2&gt;

&lt;p&gt;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’s an example using fish.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open a new VS Code project and type:&lt;code&gt;fish = 5&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Imagine a cat gets hungry and eats two fish. To create another variable for the amount eaten, write the following:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;fishEaten = 2&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Press enter and then type:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;print(fish - fishEaten)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Save and run your code and you should get the answer:&lt;code&gt;3&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Input in Python
&lt;/h2&gt;

&lt;p&gt;You can use the input() function to ask for information from the user.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open a new VS Code project and type:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;name = input("What is your name? ")&lt;/code&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Run the program and you should get the following message:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;What is your name?&lt;/code&gt;3. Now let’s try printing your name.&lt;/p&gt;

&lt;p&gt;Add the following to your program:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;print(name)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You have successfully created an input field!&lt;/p&gt;

&lt;p&gt;This can be very useful in creating decision games.&lt;/p&gt;

&lt;h2&gt;
  
  
  Making Decisions
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are Conditions?
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open a new Vs Code project and type:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;age = 10
if age == 12:
 print("True")
else:
 print("False")

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

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Save and run and you should get False&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That is because ‘age’ is set to 10 and not 12&lt;/p&gt;

&lt;h2&gt;
  
  
  What are conditionals
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  IF
&lt;/h2&gt;

&lt;p&gt;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’s an if statement and get confused.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing the if condition
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Create a new VS Code project and type the following:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;user_reply = ("Do you like python? (Type yes or no) ")&lt;/code&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Then we will implement the if condition by typing the following:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if user_reply == "yes"
   print("Python likes you to ! ")

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  ELIF
&lt;/h2&gt;

&lt;p&gt;elif is short for else if. If the conditions of the if code isn’t met it “sweeps up” whatever is left.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Now type the following:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;elif user_reply == "maybe":
  print("Make up your mind!")

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  ELSE
&lt;/h2&gt;

&lt;p&gt;When conditions for the if and elif code arent met, else goes into action and “sweeps up” whatever is left.&lt;/p&gt;

&lt;p&gt;Let’s implement that: 4. Now type the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;else:
  print("Well python doesn't like you either")

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

&lt;/div&gt;



&lt;p&gt;The complete code should look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;user_reply = ("Do you like python? (Type yes or no) ")
if user_reply == "yes"
   print("Python likes you to ! ")
elif user_reply == "maybe":
  print("Make up your mind!")
else:
  print("Well python doesn't like you either")

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Don’t forget to press the tab after if statements.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Randomness in python
&lt;/h2&gt;

&lt;p&gt;In python we can use the random function in order to generate random numbers. This can be extremely useful in a variety of things.&lt;/p&gt;

&lt;p&gt;The first thing we will have to do is import the random function&lt;/p&gt;

&lt;p&gt;&lt;code&gt;import random&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After that we can print out a random number with the following&lt;/p&gt;

&lt;p&gt;&lt;code&gt;print(random.randint(1,10))&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This will output a random number from 1–10&lt;/p&gt;

&lt;p&gt;randint stands for random integer.&lt;/p&gt;

&lt;p&gt;Here is the full code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import random
print(random.randint(1,10))

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Loops in python
&lt;/h2&gt;

&lt;p&gt;There are two types of loops in python&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;While loop&lt;/li&gt;
&lt;li&gt;For loop&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;While loops only stop when something changes. If it doesn’t change they could go on forever.&lt;/p&gt;

&lt;p&gt;With for loops on the other hand you can define exactly when you want them to stop&lt;/p&gt;

&lt;p&gt;The most popular example of a while loop is&lt;/p&gt;

&lt;p&gt;&lt;code&gt;while True:&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Which will run forever eg&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;while True:
    print("hi")

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

&lt;/div&gt;



&lt;p&gt;This will run forever.&lt;/p&gt;

&lt;p&gt;With while loops on the other hand you can define exactly how many times you want the loop to run.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;for x in range(0,10):
   print("Hi")

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

&lt;/div&gt;



&lt;p&gt;This will print Hi exactly 10 times&lt;/p&gt;

&lt;h2&gt;
  
  
  Guessing game
&lt;/h2&gt;

&lt;p&gt;Now lets combine what learned from above and from our previous articles to create a game&lt;/p&gt;

&lt;p&gt;The computer will select a random number from 1–10 and you will have to guess it.&lt;/p&gt;

&lt;p&gt;The first thing we will have to do is&lt;/p&gt;

&lt;p&gt;&lt;code&gt;import random&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After that we will create a variable called number&lt;/p&gt;

&lt;p&gt;&lt;code&gt;number = random.randint(1,10)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After that we will create another variable called your_guess&lt;/p&gt;

&lt;p&gt;&lt;code&gt;your_guess = int(input("Im thinking of a number from 1 to 10, can you guess which one?"))&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We are using int as you will have to enter a number&lt;/p&gt;

&lt;p&gt;Now we will create a while loop that will keep the game running until you guess the number&lt;/p&gt;

&lt;p&gt;&lt;code&gt;while your_guess != number:&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The code so far is&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import random
number = random.randint(1,10)
your_guess = int(input("Im thinking of a number from 1 to 10, can you guess which one?"))
while your_guess != number:
    if your_guess &amp;lt; number:
        print("Your number was too low")
    else:
        print("You number was to high")

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

&lt;/div&gt;



&lt;p&gt;And the following&lt;/p&gt;

&lt;p&gt;&lt;code&gt;print("GG you found it")&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You code should now look like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import random
number = random.randint(1,10)
your_guess = int(input("Im thinking of a number from 1 to 10, can you guess which one?"))
while your_guess != number:
    if your_guess &amp;lt; number:
        print("Your number was too low")
    else:
        print("You number was to high")
    your_guess = int(input("Please try again... "))
print("GG you found it")

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Thats it for now&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Stay tuned for more&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;If you enjoyed this article consider &lt;a href="//../../donate"&gt;supporting me&lt;/a&gt;&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>PocketBase self-hosted Firebase alternative</title>
      <dc:creator>4rkal</dc:creator>
      <pubDate>Mon, 06 Mar 2023 17:44:46 +0000</pubDate>
      <link>https://dev.to/4rkal/pocketbase-self-hosted-firebase-alternative-871</link>
      <guid>https://dev.to/4rkal/pocketbase-self-hosted-firebase-alternative-871</guid>
      <description>&lt;h1&gt;
  
  
  What is PocketBase
&lt;/h1&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h1&gt;
  
  
  Install PocketBase
&lt;/h1&gt;

&lt;p&gt;The first thing that you will have to do is head to &lt;a href="https://pocketbase.io" rel="noopener noreferrer"&gt;https://pocketbase.io&lt;/a&gt; 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.&lt;/p&gt;

&lt;p&gt;Unzip the file and open up a terminal to the path that you extracted the file to and type:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;./pocketbase serve&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If you want to serve some static content you can create a new directory called pb_public&lt;/p&gt;

&lt;p&gt;&lt;code&gt;mkdir pb_public&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then paste any content into that directory&lt;/p&gt;

&lt;p&gt;eg.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang="en"&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;meta charset="UTF-8"&amp;gt;
    &amp;lt;meta http-equiv="X-UA-Compatible" content="IE=edge"&amp;gt;
    &amp;lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&amp;gt;
    &amp;lt;title&amp;gt;Epic Website&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    &amp;lt;h1&amp;gt;My epic website&amp;lt;/h1&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;

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

&lt;/div&gt;



&lt;p&gt;And save that as index.html inside of the pb_public folder&lt;/p&gt;

&lt;p&gt;Now if you head to &lt;a href="http://127.0.0.1:8090/" rel="noopener noreferrer"&gt;http://127.0.0.1:8090/&lt;/a&gt; you should see the website that we entered above.&lt;/p&gt;

&lt;p&gt;If you go to &lt;a href="http://127.0.0.1:8090/%5C_/" rel="noopener noreferrer"&gt;http://127.0.0.1:8090/\_/&lt;/a&gt; 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.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gZjI4e9F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://4rkal.eu.org/assets/pocketbase.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gZjI4e9F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://4rkal.eu.org/assets/pocketbase.webp" alt="1" width="720" height="367"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here you can add and create users&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_zpZUkx5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://4rkal.eu.org/assets/pocketbase2.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_zpZUkx5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://4rkal.eu.org/assets/pocketbase2.webp" alt="2" width="720" height="367"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And also create custom collections eg&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wBrNqrZe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://4rkal.eu.org/assets/pocketbase3.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wBrNqrZe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://4rkal.eu.org/assets/pocketbase3.webp" alt="2" width="720" height="367"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;That’s it for now if you want to learn more check out &lt;a href="https://pocketbase.io/docs/" rel="noopener noreferrer"&gt;https://pocketbase.io/docs/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;If you enjoyed this article consider &lt;a href="//../../donate"&gt;supporting me&lt;/a&gt;&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
