<?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>Forem: David MM👨🏻‍💻</title>
    <description>The latest articles on Forem by David MM👨🏻‍💻 (@davidmm1707).</description>
    <link>https://forem.com/davidmm1707</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%2F224623%2Fd4028227-ecab-47fe-909c-7be604c57e7c.jpg</url>
      <title>Forem: David MM👨🏻‍💻</title>
      <link>https://forem.com/davidmm1707</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/davidmm1707"/>
    <language>en</language>
    <item>
      <title>Security auditing your Linux OS with Lynis</title>
      <dc:creator>David MM👨🏻‍💻</dc:creator>
      <pubDate>Mon, 29 Jan 2024 12:15:53 +0000</pubDate>
      <link>https://forem.com/davidmm1707/security-auditing-your-linux-os-with-lynis-453f</link>
      <guid>https://forem.com/davidmm1707/security-auditing-your-linux-os-with-lynis-453f</guid>
      <description>&lt;p&gt;System hardening is a hard (hah!) thing to do: Every computer has loads of vulnerabilities that can compromise our security. From SSH brute-force attacks to weak passwords, misconfigurations, etc. Keeping track of each potential vulnerability is a difficult thing to do unless we use things like Lynis.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;&lt;span&gt;Table of contents&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Introduction: What is hardening?&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;What is Lynis?&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Downloading and running our first test&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Fixing our vulnerabilities&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Testing our system after fixing it&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Final thoughts&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Resources&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Introduction: What is hardening?
&lt;/h2&gt;

&lt;p&gt;Systems hardening is the process of securing a computer system or network by reducing its vulnerabilities and minimizing potential attack surfaces. The goal of systems hardening is to improve the overall security of a system, making it more resistant to various cyber threats and attacks. This involves configuring and managing the hardware, software, and network components in a way that minimizes security risks.&lt;/p&gt;

&lt;p&gt;And we can do it easily with Lynis.&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://github.com/CISOfy/lynis" rel="noopener noreferrer"&gt;Lynis&lt;/a&gt; is an open-source security auditing tool for &lt;a href="https://letslearnabout.net/hacking/linux-file-system/" rel="noopener noreferrer"&gt;Unix-based systems&lt;/a&gt;. First, it runs a series of tests and checks on your system and its configuration, then it gives you a score (from 0 to 100) based on your hardening level.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fl6bak4hgi0pigpzj5hm8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fl6bak4hgi0pigpzj5hm8.png" alt="Lynis initial test"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, it gives you a series of recommendations and tips to improve it even further.&lt;/p&gt;

&lt;p&gt;Let's give it a try! First, we will download Lynis, run a first test, follow their recommendations, and then run another test to see if it improved our hardening index.&lt;/p&gt;

&lt;h2&gt;
  
  
  Downloading and running our first test
&lt;/h2&gt;

&lt;p&gt;First, we will clone the GitHub repo:&lt;/p&gt;

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

git clone https://github.com/CISOfy/lynis.git


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

&lt;/div&gt;

&lt;p&gt;Then, we will move to the &lt;strong&gt;lynis&lt;/strong&gt; folder, then run our first test:&lt;/p&gt;

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

./lynis audit system --quick


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

&lt;/div&gt;

&lt;p&gt;We ran our test on a new Ubuntu Server 22.04.3 LTS computer. It is just a fresh install, where we only did &lt;strong&gt;sudo apt update &amp;amp;&amp;amp; sudo apt upgrade -y&lt;/strong&gt;, so no configurations nor hardening has been applied to it yet.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2For8p3dz5mc1stwvn8kru.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2For8p3dz5mc1stwvn8kru.png" alt="Initializing Lynis"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After a minute or two, we will have a hardening score and a few recommendations about how to improve our score.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fl6bak4hgi0pigpzj5hm8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fl6bak4hgi0pigpzj5hm8.png" alt="Lynis initial scan"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, our score is only XX/100. That's too low! We need to pump those numbers up. If we scroll up or read the newly created &lt;strong&gt;/var/log/lynis-report.dat&lt;/strong&gt; report file, we have a few suggestions and tips about how to fix them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fuyuaeqwbotuagtaxb166.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fuyuaeqwbotuagtaxb166.png" alt="Lynis warnings and suggestions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Fixing our vulnerabilities
&lt;/h2&gt;

&lt;p&gt;Then, let's fix them!&lt;/p&gt;

&lt;p&gt;Let's pick a few misconfigurations and fix them. For example, the &lt;a href="https://cisofy.com/lynis/controls/SSH-7408/" rel="noopener noreferrer"&gt;SSH-7408&lt;/a&gt;, tell us how to properly configure SSH to reduce known vulnerabilities:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fkcj7r9689imzruonrp0p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fkcj7r9689imzruonrp0p.png" alt="Lynis SSH suggestions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's edit &lt;strong&gt;/etc/ssh/sshd_config&lt;/strong&gt; with the following values:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fzle010y7r09k8hi8li6a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fzle010y7r09k8hi8li6a.png" alt="Fixing  /etc/ssh/sshd_config"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fwibyeyi874zlma79s5q8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fwibyeyi874zlma79s5q8.png" alt="Fixing  /etc/ssh/sshd_config"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nice. This would improve our hardening score for sure. But if we remember, we had other vulnerabilities:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Faf3td1sim0tzmt1a98gm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Faf3td1sim0tzmt1a98gm.png" alt="Lynis package suggestion"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is an easy one. &lt;strong&gt;apt-show-versions&lt;/strong&gt; is a Linux package that lists all available package versions with distribution. That's it. You just install this package, and then you improve your security.&lt;/p&gt;

&lt;p&gt;Let's go for another one:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fdv7cu1w88oi7hsp17hm1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fdv7cu1w88oi7hsp17hm1.png" alt="Lynis password's age suggestions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Seems like &lt;strong&gt;we don't have a minimum nor a maximum password age&lt;/strong&gt;: This lets the users use the same password for years without changing it. If the password gets compromised, as they don't change it, an attacker could use it indefinitely. Let's also make &lt;strong&gt;umask&lt;/strong&gt; (related to permissions) more strict.&lt;/p&gt;

&lt;p&gt;Let's fix this problem by setting a minimum and maximum password age, and also restricting umask in the &lt;strong&gt;/etc/login.defs&lt;/strong&gt; file:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F5yvy7fd5lqwrvf3mulcc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F5yvy7fd5lqwrvf3mulcc.png" alt="Fixing minimum and maximum password age errors in /etc/login.defs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That would do it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing our system after fixing it
&lt;/h2&gt;

&lt;p&gt;We have hardened our SSH, installed a package, improved the password's ageing controls and more.&lt;/p&gt;

&lt;p&gt;Could this have improved our starting 63/100 score?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fek0bi7dr4bnkwopb9pdj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fek0bi7dr4bnkwopb9pdj.png" alt="Lynis final test"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It did! The hardening index increased its score by 10 points with just 5 minutes of hard work!&lt;/p&gt;

&lt;p&gt;Yes, there is still work to do (or less work, if you use scripts to &lt;a href="https://github.com/konstruktoid/hardening" rel="noopener noreferrer"&gt;automate the hardening process&lt;/a&gt;), but now our computer is more secure and harder to crack!&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;Lynis and systems hardening are crucial elements in improving cybersecurity. Lynis, as a security auditing tool, identifies and addresses vulnerabilities, offering recommendations for system fortification. By regularly running Lynis audits we can keep our systems updated.&lt;/p&gt;

&lt;p&gt;Lynis minimizes a system's attack surface, creating a robust defence strategy by mitigating or even removing known vulnerabilities and common security weaknesses, improving the overall security of your operating system, and reducing the risk of security breaches.&lt;/p&gt;

&lt;p&gt;And, as you saw, it is pretty addicting, as you want to keep increasing your score more and more!&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://letslearnabout.net/hardening/security-auditing-lynis/" rel="noopener noreferrer"&gt;Original post&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/CISOfy/lynis" rel="noopener noreferrer"&gt;GitHub: Lynis&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/konstruktoid/hardening" rel="noopener noreferrer"&gt;GitHub: Hardening&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://letslearnabout.net/hacking/linux-file-system/" rel="noopener noreferrer"&gt;Linux File System&lt;/a&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>tutorial</category>
      <category>opensource</category>
      <category>linux</category>
    </item>
    <item>
      <title>Creating our own Docker images</title>
      <dc:creator>David MM👨🏻‍💻</dc:creator>
      <pubDate>Mon, 15 Jan 2024 08:31:10 +0000</pubDate>
      <link>https://forem.com/davidmm1707/creating-our-own-docker-images-188p</link>
      <guid>https://forem.com/davidmm1707/creating-our-own-docker-images-188p</guid>
      <description>&lt;p&gt;After learning the &lt;a href="https://letslearnabout.net/devops/docker-tutorial-beginners/"&gt;Docker basics&lt;/a&gt;, it is time to create our images. Creating our own custom Docker image allows us to have more control over application configurations, dependencies, security, and more. And it is easy and fun. Get ready for it!&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;&lt;span&gt;Table of contents&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Introduction&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Doing the process steps manually&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Creating our Docker image&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Making public our Docker image&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Final thoughts&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Resources&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Custom Docker images give us control over application configurations and dependencies, improving security, and performance. We can create a custom Docker image tailored to our own needs, with the dependencies we want, and the code we want.&lt;/p&gt;

&lt;p&gt;For example, we want everybody in our dev team to use Ubuntu 20.04 with Apache and the code in one GitHub repo. We could create a custom Docker image, upload it and tell everybody in the dev team to work using that image.&lt;/p&gt;

&lt;p&gt;No more dependencies problem, no more "I don't know how to install X" and, especially, no more "But it works on my computer".&lt;/p&gt;

&lt;p&gt;We just need to create one image packaged with all we need, that executes every step we want.&lt;/p&gt;

&lt;h2&gt;
  
  
  Doing the process steps manually
&lt;/h2&gt;

&lt;p&gt;One tip before creating our own custom Docker image is to do the process manually: We get a clean Linux system (A Virtual Machine created with &lt;a href="https://letslearnabout.net/devops/vagrant-tutorial-beginners/"&gt;Vagrant&lt;/a&gt; it is the easy way as you can use the image and discard it later) and we run the commands we want.&lt;/p&gt;

&lt;p&gt;Using a process of trial and error, we install and configure everything we want until it is done. We will repeat these steps on our Docker image.&lt;/p&gt;

&lt;p&gt;For this, of course, you need to have Docker installed (and, if not, here's how to &lt;a href="https://letslearnabout.net/devops/docker-tutorial-beginners/#installation"&gt;Install Docker with 3 easy steps&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Let's start then!&lt;/p&gt;

&lt;p&gt;We want to run a Flask web application inside an Ubuntu OS. The steps we want to do are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Install Ubuntu&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Update and upgrade Ubuntu&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Install Python and its installer&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Install Flask dependency&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Copy our Python code&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run the Flask web application&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, let's start!&lt;/p&gt;

&lt;p&gt;First, let's download a Docker image, then create a container using that image, and run the bash terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run -it ubuntu bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we are in the container's terminal as a root. Let's install all our dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apt update
apt upgrade -y
apt install -y python3
apt install python3-pip
pip install flask
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have everything we need to run our code. You can create a Flask app, search for one on GitHub that you want to use, or just use an &lt;a href="https://raw.githubusercontent.com/david1707/flask-app/main/app.py"&gt;application I have created for this tutorial&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Copy the code and paste it inside &lt;em&gt;/opt/app.py.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cat &amp;gt; /opt/app.py

import os
from flask import Flask

app = Flask(__name__)


@app.route("/")
def main():
    return "Welcome!"


@app.route("/How are you")
def how_are_you():
    return "I'm fine, how about you?"


@app.route("/about")
def about():
    return "I'm just a small Flask app :)"


@app.route("/info")
def info():
    return "I have been created just to pass Pau's subject."


if __name__ == "__main__":
    app.run()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Everything is set, time to 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;FLASK_APP=app.py flask run --host=0.0.0.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can visit the URL in our Browser:&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%2Fq0x877p0xxqdky22se75.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%2Fq0x877p0xxqdky22se75.png" alt="Starting our Flask service" width="688" height="393"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating our Docker image
&lt;/h2&gt;

&lt;p&gt;We have our server running perfectly. Now, we want to reproduce the same steps in a Docker image so we can distribute it.&lt;/p&gt;

&lt;p&gt;First, close everything and check the container isn't running:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Now, let's create a folder for us to work in. Inside, create a Dockerfile (A text document that contains all the commands we want to run) where we will create a script to do all the steps we did before:&lt;br&gt;
&lt;/p&gt;

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

sudo vim Dockerfile

FROM ubuntu
RUN apt update
RUN apt upgrade -y
RUN apt install -y python3 python3-pip
RUN pip install flask
COPY app.py /opt/app.py
ENTRYPOINT FLASK_APP=/opt/app.py flask run --host=0.0.0.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can run Docker build to run the script and create a Docker image. But before, as we see in the COPY line, we need to have our script in the same folder. Copy it or just download it with wget:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;wget https://raw.githubusercontent.com/david1707/flask-app/main/app.py

docker build . -t david1707/app-flask-caminas
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember to change the image's name, following the convention of &lt;code&gt;&amp;lt;YOUR_NAME&amp;gt;/&amp;lt;IMAGE_NAME&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;After a few minutes (it took me 6), you have your custom Docker image:&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%2F4vh6tgqmqqsvi3xofmfi.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%2F4vh6tgqmqqsvi3xofmfi.png" alt="sudo docker images" width="669" height="54"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Making public our Docker image
&lt;/h2&gt;

&lt;p&gt;Now we can distribute the Dockerfile and everybody will have the same image, with the same dependencies. But we can publish it in one Docker repo (for example, in &lt;a href="https://hub.docker.com/"&gt;Docker&lt;/a&gt; &lt;a href="https://hub.docker.com/"&gt;Hub&lt;/a&gt;). Very much like GitHub, everybody could download your image and use it on their computers.&lt;/p&gt;

&lt;p&gt;You have to register in Docker Hub first, and then push it to the repo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker push david1707/app-flask-caminas
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now anyone can use your image with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
docker run david1707/app-flask-caminas
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will download the image, if it isn't on our computer, and run it. Now, we can visit the browser using the URL given:&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%2Favia12gdkp7iuk8l8vfq.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%2Favia12gdkp7iuk8l8vfq.png" alt="downloading our docker image" width="678" height="633"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;Creating our own Docker images is pretty easy. We just need the basics of using the terminal, then we can replicate all the steps in a Dockerfile to create our images, even distributing them via Docker Hub.&lt;/p&gt;

&lt;p&gt;The benefits of using our own custom Docker files are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Customization:&lt;/strong&gt; Creating and using your own Docker images allows for tailored configurations, ensuring that the image contains specific dependencies, settings, and optimizations that align with the requirements of your applications.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Security Compliance:&lt;/strong&gt; By building and managing your own Docker images, we have direct control over the inclusion and configuration of security measures.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reduced Image Size:&lt;/strong&gt; Customizing Docker images allows for the elimination of unnecessary components, resulting in smaller image sizes. Smaller images lead to faster deployment times and more efficient resource utilization.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Flexibility and Specialized Tooling:&lt;/strong&gt; Building our own Docker images provides the flexibility to incorporate specialized tooling or unique requirements specific to your organization's workflows. This customization lets teams create and deploy applications with the exact environment they need for optimal performance and functionality.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://letslearnabout.net/devops/creating-docker-image/"&gt;Original post&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://letslearnabout.net/devops/docker-tutorial-beginners"&gt;Docker basics for beginners&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://letslearnabout.net/devops/docker-tutorial-beginners/#installation"&gt;Install Docker with 3 easy steps&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/david1707/flask-app/"&gt;GitHub: Flask App&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/david1707"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://hub.docker.com/"&gt;Docker hub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>docker</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Docker basics for beginners</title>
      <dc:creator>David MM👨🏻‍💻</dc:creator>
      <pubDate>Wed, 10 Jan 2024 22:06:30 +0000</pubDate>
      <link>https://forem.com/davidmm1707/docker-basics-for-beginners-49l9</link>
      <guid>https://forem.com/davidmm1707/docker-basics-for-beginners-49l9</guid>
      <description>&lt;p&gt;In my latest post, I talked about Vagrant and how it can help us to create Virtual Machines in minutes, but what if can do it even faster, better and more customizable? Let's learn how we can develop, deploy and run applications easily with Docker!&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;&lt;span&gt;Table of contents&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Introduction&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Docker vs Virtual Machines&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Installation&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Basic commands&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;An example: Jenkins container&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Data persistence&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Data persistence-with volumes&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Final thoughts&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Resources&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;If you Google &lt;em&gt;Docker&lt;/em&gt;, you will find that Docker is a software platform that uses an OS-level virtualization to create self-contained containers.&lt;/p&gt;

&lt;p&gt;Luckily here, I will explain to you what that means in simple English.&lt;/p&gt;

&lt;p&gt;You may have created multiple Virtual Machines with Oracle VM or &lt;a href="https://letslearnabout.net/devops/vagrant-tutorial-beginners/" rel="noopener noreferrer"&gt;Vagrant&lt;/a&gt; before. Docker is something like that (but better, but more about that later).&lt;/p&gt;

&lt;p&gt;With Docker, we select an image (think about Docker images as recipes) and download it. Then, we create an instance of that image or container, pretty similar to a Virtual Machine.&lt;/p&gt;

&lt;h4&gt;
  
  
  Image:
&lt;/h4&gt;

&lt;p&gt;A package or template used to create one or more containers&lt;/p&gt;

&lt;h4&gt;
  
  
  Container:
&lt;/h4&gt;

&lt;p&gt;Instances of an image, isolated from each other, with their own environment.&lt;/p&gt;

&lt;p&gt;But let's see it in action. This is a docker image code:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;FROM ubuntu:23.04&lt;br&gt;
 RUN apt-get update&lt;br&gt;
 RUN apt-get install -y curl nginx&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Remember what I said about a Docker image being a recipe? In this image or &lt;em&gt;recipe&lt;/em&gt;, Docker gets the Ubuntu 23.04 version, updates the SO, and then installs &lt;em&gt;curl&lt;/em&gt; and &lt;em&gt;nginx&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Granted, this is a short Docker image version, but it helped us to visualize what Docker is about.&lt;/p&gt;

&lt;p&gt;Now, with this image, we can create a container (imagine a Virtual Machine) and it will create a Linux Ubuntu VM-like already updated, with curl and nginx.&lt;/p&gt;

&lt;p&gt;And all the developers in our company can use the same image to have the same programs, packages, and versions installed. No more "Bu...but it works on my computer!"; now every computer has the same specifications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Docker vs Virtual Machines
&lt;/h2&gt;

&lt;p&gt;But...if Docker creates a container that is VM-like, why don't we use just Virtual Machines?&lt;/p&gt;

&lt;p&gt;I could explain how Docker containers are better than Virtual Machines on a low-level way, maybe even snatch some cool infographics from another site like this one and explain that Docker uses the same kernel for every container, making it light-weight and fast, only taking a few seconds to spin one container:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F9mlbr5g7cd1h655ftjlm.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F9mlbr5g7cd1h655ftjlm.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But there is one big benefit of using Docker and Docker containers:&lt;/p&gt;

&lt;p&gt;Imagine you want to develop a 21.1 NodeJS: You create your own Docker image, where you get an Ubuntu image, update it, install all the NodeJS-related stuff, and then distribute the image to the developing team.&lt;/p&gt;

&lt;p&gt;In a normal setting, you have to upload the NodeJS application, deploy it on your server and you have to make sure that the server has all the dependencies and its NodeJS is compatible with yours.&lt;/p&gt;

&lt;p&gt;And you don't want to bet on that.&lt;/p&gt;

&lt;p&gt;With Docker, we can create a Docker image, upload it to a Docker-compatible server and that's it.&lt;/p&gt;

&lt;p&gt;The Docker server doesn't care about what Linux you use, what packages installed, or what it is your app's language: It only needs to run the image. That's it.&lt;/p&gt;

&lt;p&gt;Let me emphasize this: We don't care what the server has installed. We upload and run the Docker image. That's all we have to do.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;You can install Docker Desktop, a GUI Docker app, but we, rugged and tough developers use proper terminal stuff, so you will install Docker Engine, the terminal version of Docker.&lt;/p&gt;

&lt;p&gt;Jokes aside, you can install whatever you want: &lt;a href="https://docs.docker.com/desktop/" rel="noopener noreferrer"&gt;Docker Desktop&lt;/a&gt; or &lt;a href="https://docs.docker.com/engine/install/" rel="noopener noreferrer"&gt;Docker Engine&lt;/a&gt;, just make sure you are following your OS's instructions. For example, for Debian-based distros such as Ubuntu:&lt;/p&gt;

&lt;p&gt;Uninstall previous Docker versions&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo apt-get purge docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker-ce-rootless-extras&lt;br&gt;
sudo rm -rf /var/lib/docker&lt;br&gt;
sudo rm -rf /var/lib/containerd&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Install Docker&lt;br&gt;
&lt;code&gt;curl -fsSL https://get.docker.com -o get-docker.sh&lt;br&gt;
sudo sh ./get-docker.sh&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Check that Docker is installed &lt;br&gt;
&lt;code&gt;sudo docker version&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Let's run a test. Run the following command in your terminal:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo docker run docker/whalesay cowsay boo&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fkubznaemm0o0mwfxgyur.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fkubznaemm0o0mwfxgyur.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; Every Docker command needs sudo permission. You can add a user to the &lt;em&gt;docker&lt;/em&gt; group, but despite that, it still keeps asking for sudo permission. I have found that by running the command &lt;code&gt;sudo chmod 666 /var/run/docker.sock&lt;/code&gt; , you don't get asked for sudo permissions any more (You can use a similar command, like &lt;em&gt;chmod +x&lt;/em&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Basic commands
&lt;/h2&gt;

&lt;p&gt;We have Docker up and running. Let's see a few basic commands. Your bread and butter if you want:&lt;/p&gt;

&lt;p&gt;List all images&lt;br&gt;
&lt;code&gt;docker images&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Download or execute a container from an image&lt;br&gt;
&lt;code&gt;docker run &amp;lt;IMAGE_NAME&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Download a specific version&lt;br&gt;
&lt;code&gt;docker run &amp;lt;IMAGE_NAME&amp;gt;:&amp;lt;VERSION&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Execute a container in the background&lt;br&gt;
&lt;code&gt;docker run -d &amp;lt;IMAGE_NAME&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Bring a container from the background to the foreground&lt;br&gt;
&lt;code&gt;docker run attach &amp;lt;ID&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Execute a command&lt;br&gt;
&lt;code&gt;docker run ubuntu cat /etc/*release*&lt;br&gt;
docker run ubuntu sleep 15&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Download an image to run it later&lt;br&gt;
&lt;code&gt;docker pull &amp;lt;IMAGE_NAME&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Execute a command inside the docker container&lt;br&gt;
&lt;code&gt;docker exec &amp;lt;COMMAND&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Connect to the container's bash&lt;br&gt;
&lt;code&gt;docker run -it &amp;lt;IMAGE_NAME&amp;gt; bash&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;List all running containers&lt;br&gt;
&lt;code&gt;docker ps&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;List ALL containers, running or not&lt;br&gt;
&lt;code&gt;docker ps -a&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Run a container with a link to other container:&lt;br&gt;
&lt;code&gt;docker run -p &amp;lt;PORT_LOCAL&amp;gt;:&amp;lt;PORT_DEFAULT&amp;gt; --link &amp;lt;IMAGE_NAME_TO_LINK&amp;gt;:&amp;lt;IMAGE_NAME_TO_LINK&amp;gt; &amp;lt;IMAGE_NAME&amp;gt;&lt;br&gt;
docker run -p 5000:80 --link redis:redis voting-app&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Get details from an image or container in JSON format&lt;br&gt;
&lt;code&gt;docker inspect &amp;lt;NAME_OR_ID&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Get logs from a container running in the background&lt;br&gt;
&lt;code&gt;docker logs &amp;lt;NAME_OR_ID&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Get all the layers from an image&lt;br&gt;
&lt;code&gt;docker history &amp;lt;IMAGE_NAME&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Stop a container&lt;br&gt;
&lt;code&gt;docker stop &amp;lt;IMAGE_NAME_OR_ID&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Remove permanently a container &lt;br&gt;
&lt;code&gt;docker rm &amp;lt;IMAGE_NAME_OR_ID&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Remove permanently an image that isn't being used&lt;br&gt;
&lt;code&gt;docker rmi &amp;lt;IMAGE_NAME&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Build an image from a Dockerfile&lt;br&gt;
&lt;code&gt;docker build . -t &amp;lt;NAME&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Environment variables&lt;br&gt;
&lt;code&gt;docker run -e &amp;lt;VARIABLE&amp;gt;=&amp;lt;VALUE&amp;gt; &amp;lt;IMAGE_NAME&amp;gt;&lt;br&gt;
docker run -e APP_COLOR=blue simple-webapp-color&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  An example: Jenkins container
&lt;/h2&gt;

&lt;p&gt;Let's use a real-life example: Using a Jenkins container.&lt;/p&gt;

&lt;p&gt;In future posts, I will talk more in-depth about Jenkins and what it does, but Jenkins is a great DevOps CI/CD tool. Let's download Jenkins and run it on our computer:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker run jenkins/jenkins       # This downloads and runs jenkins&lt;br&gt;
docker ps                        # Get the container ID and port&lt;br&gt;
docker inspect &amp;lt;CONTAINER_ID&amp;gt;    # Get the container IP&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Open a Browser in your VM using :&lt;br&gt;
&lt;code&gt;docker run -p 8080:8080 jenkins/jenkins   # Map the port&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Open a Browser in your Host machine using :&lt;/p&gt;

&lt;p&gt;Here, we are installing and downloading a Docker image in our Ubuntu Virtual Machine and running it. We can view Jenkins in our VM by opening a Browser and using the Docker container's IP and port, but by mapping the port we can open Jenkins in our Host computer.&lt;/p&gt;

&lt;p&gt;The structure is:&lt;/p&gt;

&lt;p&gt;Host with Windows -&amp;gt; Linux VM -&amp;gt; Docker container running in Linux&lt;/p&gt;

&lt;p&gt;Now, Linux is running a lightweight Docker container we can access from our Windows machine. Isn't that great?&lt;/p&gt;

&lt;h2&gt;
  
  
  Data persistence
&lt;/h2&gt;

&lt;p&gt;We stop the Jenkins container and the next day we resume it to keep working. But we have lost everything. What happened????&lt;/p&gt;

&lt;p&gt;Docker alone doesn't have data permanence.&lt;/p&gt;

&lt;p&gt;The container uses its own folders (&lt;em&gt;/var/jenkins_home&lt;/em&gt; on Jenkins, &lt;em&gt;/var/lib/mysql&lt;/em&gt; on MySQL, etc), but when you stop the container and run the image again, you are creating a container from scratch. What can we do about it?&lt;/p&gt;

&lt;p&gt;We can achieve &lt;em&gt;Data persistence&lt;/em&gt; by linking a folder in the OS running Docker, and the container's folder.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;mkdir my_jenkins_data&lt;br&gt;
docker run -p 8080:8080 -v /home/&amp;lt;USERNAME&amp;gt;/my_jenkins_data:/var/jenkins_home jenkins/jenkins&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Here, we created a folder called &lt;em&gt;my_jenkins_data&lt;/em&gt; and we linked it with the Jenkins folder &lt;em&gt;/var/jenkins_home&lt;/em&gt;, where Docker stores any change.&lt;/p&gt;

&lt;p&gt;So, if we run the command again, we will create a new container, linking the stored information, as if we were resuming our container.&lt;/p&gt;

&lt;h2&gt;
  
  
  Data permanence with volumes
&lt;/h2&gt;

&lt;p&gt;We can simplify this process. Instead of giving a long string for our folder, we can let Docker manage the volumes by creating them in &lt;em&gt;/var/lib/docker/volumes/*&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Create a volume&lt;br&gt;
&lt;code&gt;docker volume create test_volume&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This creates a volume in /var/lib/docker/volumes/test_volume&lt;br&gt;
&lt;code&gt;docker run -v test_volume:var/lib/mysql mysql&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We can also use the modern way, which is longer but more declarative and verbose:&lt;br&gt;
&lt;code&gt;docker run / --mount type=bind, source=/data/mysql, target=/var/lib/mysql mysql&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;As we just saw, Docker is great for several reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Isolation&lt;/strong&gt;: Docker allows applications to be isolated from the underlying system, ensuring consistency in different environments.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Efficiency&lt;/strong&gt;: It optimizes resource utilization by using containerization, allowing for more efficient use of system resources.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Portability&lt;/strong&gt;: Docker containers can run on any machine that has Docker installed, making it easy to deploy applications across different environments.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scalability&lt;/strong&gt;: With Docker, it's easy to scale applications by increasing or decreasing the number of containers as per the demand.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Consistency&lt;/strong&gt;: Docker ensures that the development, testing, and production environments are consistent, reducing the "it works on my machine" problem.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Ecosystem&lt;/strong&gt;: Docker has a rich ecosystem with a wide range of tools and services that complement containerization, making it a versatile platform for application deployment and management.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Deployment&lt;/strong&gt;: Docker makes it easier and safer to deploy. Instead of managing packages and their versions, we upload our Docker image to a server.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://letslearnabout.net/devops/docker-tutorial-beginners/" rel="noopener noreferrer"&gt;Original post&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://letslearnabout.net/devops/vagrant-tutorial-beginners/" rel="noopener noreferrer"&gt;Vagrant tutorial for beginners&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.docker.com/desktop/" rel="noopener noreferrer"&gt;Docker Desktop&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://kodekloud.com/blog/role-of-docker-in-devops/" rel="noopener noreferrer"&gt;The Role of Docker in DevOps&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://hub.docker.com/" rel="noopener noreferrer"&gt;Docker Hub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>docker</category>
      <category>devops</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Vagrant tutorial for beginners</title>
      <dc:creator>David MM👨🏻‍💻</dc:creator>
      <pubDate>Sun, 07 Jan 2024 09:43:50 +0000</pubDate>
      <link>https://forem.com/davidmm1707/vagrant-tutorial-for-beginners-1fb0</link>
      <guid>https://forem.com/davidmm1707/vagrant-tutorial-for-beginners-1fb0</guid>
      <description>&lt;p&gt;Vagrant is a tool used to simplify building and managing Virtual Machines in a very simple yet powerful way. If you, like me, are tired of installing Linux Virtual Machines as I do, you will welcome Vagrant into your life. Let's learn more about Vagrant!&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;&lt;span&gt;Table of contents&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Introduction&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Vagrant installation&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Vagrant basic commands&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Vagrantfile&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Final thoughts&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Resources&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;How many times have you created a Virtual Machine?&lt;/p&gt;

&lt;p&gt;You know the drill: You download a &lt;a href="https://letslearnabout.net/hacking/linux-file-system/"&gt;Linux&lt;/a&gt; image, create a Virtual Machine, select your options, add the .iso file, start the installation process then wait for something between 15 and 30 minutes. If you did this once or twice every year, it would be ok, but sometimes you need to create a lot for Virtual Machines, and time is lost by waiting.&lt;/p&gt;

&lt;p&gt;What if we could simplify and speed up the process?&lt;/p&gt;

&lt;h3&gt;
  
  
  Enter Vagrant
&lt;/h3&gt;

&lt;p&gt;Vagrant is an open-source tool for building and managing virtualized development environments. Vagrant uses configuration files to define the virtual machine settings and provisions them with the required software and tools. Or you can run a few commands and install a Virtual Machine in seconds. This approach ensures that all team members work in the same development environment, reducing compatibility issues and streamlining the development process.&lt;/p&gt;

&lt;p&gt;With Vagrant, instead of doing all the &lt;em&gt;Download a Linux image, create a Virtual Machine, etc&lt;/em&gt; processes, we will fetch an existing image from a Vagrant repository and add it to your Virtual Machine manager in 2 minutes. It is not an expression, it takes 2 minutes.&lt;/p&gt;

&lt;h3&gt;
  
  
  How does it work?
&lt;/h3&gt;

&lt;p&gt;Vagrant downloads a pre-existing Virtual Machine installation (Vagrant calls them &lt;strong&gt;boxes&lt;/strong&gt;), adds it to your Virtual Machine manager and sets the configuration automatically.&lt;/p&gt;

&lt;p&gt;How cool is that?&lt;/p&gt;

&lt;p&gt;You can run the command &lt;em&gt;vagrant init generic/ubuntu2204&lt;/em&gt; to download an Ubuntu 22.04 Jellyfish box, and &lt;em&gt;vagrant up&lt;/em&gt; to start the Virtual Machine. Now, you can open it in your VM or just connect to it with the command &lt;em&gt;vagrant ssh&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Vagrant installation
&lt;/h2&gt;

&lt;p&gt;As the installation depends on what Operating System you have, you just need to enter a few commands in your terminal. As this changes every few months/years, I'll link you to the &lt;a href="https://developer.hashicorp.com/vagrant/install"&gt;official Vagrant Installation&lt;/a&gt; site.&lt;/p&gt;

&lt;p&gt;For example, for Ubuntu/Debian, open your terminal and enter:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg&lt;br&gt;
echo "deb \[signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg\] https://apt.releases.hashicorp.com $(lsb\_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list&lt;br&gt;
sudo apt update &amp;amp;&amp;amp; sudo apt install vagrant&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You also need to have installed a virtualization program, such as &lt;a href="https://www.virtualbox.org/wiki/Downloads"&gt;VirtualBox&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Downloading your first Vagrant box
&lt;/h3&gt;

&lt;p&gt;Ok, you have Vagrant and VirtualBox installed, now what?&lt;/p&gt;

&lt;p&gt;Why don't we start with a download? Download a Centos VM with&lt;/p&gt;

&lt;p&gt;&lt;code&gt;vagrant init geerlingguy/centos7&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then start it with:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;vagrant up&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The VM is up and running. Now you can open it on VirtualBox or, if you don't need the GUI, you can connect to it via SSH with:&lt;/p&gt;

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

&lt;p&gt;As simple as that. As Vagrant manages all the processes, you don't need to enter the username or the IP to connect to it. Vagrant boxes come with a user already created (Username: vagrant, Password: vagrant) so you can log in to the machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Vagrant basic commands
&lt;/h2&gt;

&lt;p&gt;We just saw how we can download and create a new Virtual Machine, but what more we can do with Vagrant?&lt;/p&gt;

&lt;p&gt;Here's a list of basic commands:&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating a VM
&lt;/h3&gt;

&lt;p&gt;Install a box&lt;br&gt;
&lt;code&gt;vagrant init &amp;lt;BOX_NAME&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Managing a Vagrant VM state
&lt;/h3&gt;

&lt;p&gt;Start a Vagrant VM&lt;br&gt;
&lt;code&gt;vagrant up&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Stop a Vagrant VM&lt;br&gt;
&lt;code&gt;vagrant halt&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Resume a Vagrant VM&lt;br&gt;
&lt;code&gt;vagrant resume&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Reload a Vagrant VM&lt;br&gt;
&lt;code&gt;vagrant reload&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Suspend a Vagrant VM&lt;br&gt;
&lt;code&gt;vagrant suspend&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Delete a Vagrant VM&lt;br&gt;
&lt;code&gt;vagrant destroy&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Vagrant VM status
&lt;/h3&gt;

&lt;p&gt;Check a Vagrant VM state&lt;br&gt;
&lt;code&gt;vagrant status&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Check all Vagrant VM states&lt;br&gt;
&lt;code&gt;vagrant global-status&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Provisioning
&lt;/h3&gt;

&lt;p&gt;Force provisioning&lt;br&gt;
&lt;code&gt;vagrant provision&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Use the debug flag to add more verbosity&lt;br&gt;
&lt;code&gt;vagrant provision --debug&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Restart the virtual machine and force provisioning&lt;br&gt;
&lt;code&gt;vagrant reload --provision&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Connecting to a VM
&lt;/h3&gt;

&lt;p&gt;Connect to a Vagrant VM via SSH&lt;br&gt;
&lt;code&gt;vagrant ssh&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Connect to a specific Vagrant VM via SSH&lt;br&gt;
&lt;code&gt;vagrant ssh &amp;lt;BOX_NAME&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Managing boxes
&lt;/h3&gt;

&lt;p&gt;List all boxes installed&lt;br&gt;
&lt;code&gt;vagrant box list&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Check of updates&lt;br&gt;
&lt;code&gt;vagrant box outdated&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Download a box&lt;br&gt;
&lt;code&gt;vagrant box add &amp;lt;BOX_NAME&amp;gt; &amp;lt;URL&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Delete a box&lt;br&gt;
&lt;code&gt;vagrant box remove &amp;lt;BOX_NAME&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Vagrantfile
&lt;/h2&gt;

&lt;p&gt;We can also edit your Vagrant boxes with a Vagrantfile.&lt;/p&gt;

&lt;p&gt;A Vagrantfile is a configuration file used to define and configure the various aspects of Vagrant-managed virtual machines. It allows us to specify settings such as the virtual machine's networking, and provisioning, among other parameters.&lt;/p&gt;

&lt;p&gt;Then, we can use this Vagrantfile on multiple machines at the same time to create Virtual Machines with the same specs. How cool is that?&lt;/p&gt;

&lt;p&gt;If you want to edit a Vagrantfile, open it with your IDE (Atom, Notepad++, Sublime text, VIM, VS Code...) and uncomment any text you want to use.&lt;/p&gt;

&lt;h3&gt;
  
  
  Examples
&lt;/h3&gt;

&lt;p&gt;Add a bridged port&lt;br&gt;
&lt;code&gt;config.vm.network "public_network"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Add a bridged port with a static IP&lt;br&gt;
&lt;code&gt;config.vm.network "private_network", ip: "192.168.1.222"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Specify VM's memory and CPUs&lt;br&gt;
&lt;code&gt;  config.vm.provider "virtualbox" do |vb|&lt;br&gt;
    vb.memory = "2048"&lt;br&gt;
    vb.cpus = 2&lt;br&gt;
  end&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
Share a folder from your host PC to the Vagrant VM&lt;br&gt;
&lt;code&gt;config.vm.synced_folder "C:\\Users\\&amp;lt;YOUR_USERNAME&amp;gt;\\Desktop\\shared_files", "/home/vagrant/vagrant_data"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Provisioning the VM&lt;br&gt;
&lt;code&gt;  config.vm.provision "shell", inline: &amp;lt;&amp;lt;-SHELL&lt;br&gt;
    apt-get update&lt;br&gt;
    apt-get install -y apache2&lt;br&gt;
  SHELL&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Of course, there are more options. You can read more about them in the &lt;a href="https://developer.hashicorp.com/vagrant/docs/vagrantfile/machine_settings"&gt;official Documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can also download my &lt;a href="https://github.com/david1707/devops-cheatsheets/blob/main/Vagrant/Vagrant-Cheat-Sheet.md"&gt;Vagrant Cheat Sheets&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;As we already saw, Vagrant offers several benefits for developers and IT professionals, including:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Consistent Development Environments&lt;/strong&gt;: Vagrant ensures that every team member works in an identical environment, reducing "it works on my machine" issues.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Efficiency&lt;/strong&gt;: It streamlines the setup process for new team members, as well as the onboarding of existing projects.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Isolation&lt;/strong&gt;: Vagrant keeps project dependencies and configurations isolated from each other, preventing conflicts between projects.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cross-Platform Compatibility&lt;/strong&gt;: Vagrant provides a consistent environment across different operating systems, promoting seamless collaboration.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reproducibility&lt;/strong&gt;: With Vagrant, it's easy to reproduce environments for testing, debugging, and production, enhancing overall reliability.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Resource Optimization&lt;/strong&gt;: It allows for efficient resource usage by consolidating multiple development environments on a single machine.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Overall, Vagrant simplifies the development workflow, enhances collaboration, and improves the reliability of software projects.&lt;/p&gt;

&lt;p&gt;And you just saw how easy it is to use. At the bare minimum, you can work with just 2 or 3 commands to download, run and connect to it via SSH.&lt;/p&gt;

&lt;p&gt;Vagrant should become a tool in your belt, professionally or not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://letslearnabout.net/devops/vagrant-tutorial-beginners/"&gt;Original post&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.hashicorp.com/vagrant/install"&gt;Vagrant installation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.virtualbox.org/wiki/Downloads"&gt;VirtualBox installation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.hashicorp.com/vagrant/docs/vagrantfile/machine_settings"&gt;VagrantfileDocs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://letslearnabout.net/hacking/linux-file-system/"&gt;Linux File System&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/david1707/devops-cheatsheets/blob/main/Vagrant/Vagrant-Cheat-Sheet.md"&gt;Vagrant Cheat Sheet&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>The Linux File System: A simple guide for beginners</title>
      <dc:creator>David MM👨🏻‍💻</dc:creator>
      <pubDate>Fri, 03 Nov 2023 07:15:38 +0000</pubDate>
      <link>https://forem.com/davidmm1707/the-linux-file-system-a-simple-guide-for-beginners-3jao</link>
      <guid>https://forem.com/davidmm1707/the-linux-file-system-a-simple-guide-for-beginners-3jao</guid>
      <description>&lt;p&gt;If you want to master Linux, you need to know how the Linux File System works. Why not start now?&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;&lt;span&gt;Table of contents&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Introduction&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Linux directories&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Final thoughts&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Resources&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;When I started using Linux, coming from Windows, I was a bit lost with all the new directories in Linux. Sometimes their names are intuitive (/home, /boot...), but most of the time I didn't understand what they were used for.&lt;/p&gt;

&lt;p&gt;Fear not. Today you are going to learn what are each directory for in no time. Let's go!&lt;/p&gt;

&lt;h2&gt;
  
  
  Linux directories
&lt;/h2&gt;

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

&lt;p&gt;The root directory. This marks the start of the Linux File system and it is the highest level. All the files and directories are stored here.&lt;/p&gt;

&lt;h3&gt;
  
  
  /bin
&lt;/h3&gt;

&lt;p&gt;Bin contains binary executables (the Linux version of Windows .exe files). These include the commands you use in the terminal (cat, mkdir, ls, cat...). As you may have guessed, the name of this directory comes from BINaries.&lt;/p&gt;

&lt;h3&gt;
  
  
  /boot
&lt;/h3&gt;

&lt;p&gt;One of the main directories. Here are stored the files used to boot the system successfully. You shouldn't touch this directory.&lt;/p&gt;

&lt;h3&gt;
  
  
  /dev
&lt;/h3&gt;

&lt;p&gt;This contains files of devices connected to the system. For example, when you connect a USB, but also hard drives.&lt;/p&gt;

&lt;h3&gt;
  
  
  /etc
&lt;/h3&gt;

&lt;p&gt;As the name says, it is... etcetera. It stores configuration files required by the system. For example, /etc/shadow, /etc/passwd, etc. Again, you shouldn't touch this directory. And if you do, make a copy of the files you modify (I destroyed my Ubuntu virtual machine messing around with this. Luckily I had a snapshot saved...)&lt;/p&gt;

&lt;h3&gt;
  
  
  /home
&lt;/h3&gt;

&lt;p&gt;Here you will find the private directory of each user. It contains user directories such as /Downloads, /Documents, /Desktop, etc. The exception is root, which has its own directory.&lt;/p&gt;

&lt;h3&gt;
  
  
  /lib
&lt;/h3&gt;

&lt;p&gt;It contains libraries of different applications. The package manager controls and manages this directory automatically. These are essential files that you shouldn't mess around with.&lt;/p&gt;

&lt;h3&gt;
  
  
  /media
&lt;/h3&gt;

&lt;p&gt;Contains (temporal) directories of removable media (for example, when you connect a USB, you can find it at /media//.&lt;/p&gt;

&lt;h3&gt;
  
  
  /mnt
&lt;/h3&gt;

&lt;p&gt;This is the /media directory of the past. Here the CD ROM readers were mounted, but no longer is used.&lt;/p&gt;

&lt;h3&gt;
  
  
  /opt
&lt;/h3&gt;

&lt;p&gt;Here are stored the software packages provided by a third party, not installed with the package manager (generally, apt-get). Each application has its own directory inside /opt, containing the files needed to run.&lt;/p&gt;

&lt;h3&gt;
  
  
  /proc
&lt;/h3&gt;

&lt;p&gt;Contains information about running processes and your computer: CPU, RAM, kernel, etc. The files here are generated at your computer start-up and deleted when powered off.&lt;/p&gt;

&lt;h3&gt;
  
  
  /root
&lt;/h3&gt;

&lt;p&gt;The home directory of the &lt;em&gt;root&lt;/em&gt; account. Despite being a kind of "user directory", it has a different structure than the average user.&lt;/p&gt;

&lt;h3&gt;
  
  
  /run
&lt;/h3&gt;

&lt;p&gt;One of the newest directories. It contains temporal files that use the RAM memory. Once the computer is powered off, the files disappear.&lt;/p&gt;

&lt;h3&gt;
  
  
  /sbin
&lt;/h3&gt;

&lt;p&gt;Similar to the /bin directory, but for the &lt;em&gt;root&lt;/em&gt; user. It contains special binaries and command line tools used by &lt;em&gt;root&lt;/em&gt;. For example, the &lt;em&gt;reboot&lt;/em&gt; file that only the admin user can use it is stored here.&lt;/p&gt;

&lt;h3&gt;
  
  
  /sys
&lt;/h3&gt;

&lt;p&gt;Contains information about devices, drivers and kernels. This directory is managed automatically by Linux.&lt;/p&gt;

&lt;h3&gt;
  
  
  /srv
&lt;/h3&gt;

&lt;p&gt;Contains information about services, specific to your Linux distribution. This directory is managed automatically by Linux.&lt;/p&gt;

&lt;h3&gt;
  
  
  /tmp
&lt;/h3&gt;

&lt;p&gt;Contains temporal files, created by running applications, the system or users. Once your computer is powered off, these files are deleted.&lt;/p&gt;

&lt;h3&gt;
  
  
  /usr
&lt;/h3&gt;

&lt;p&gt;This directory contains libraries, binaries and documentation of the installed programs, that are shared between all the users.&lt;/p&gt;

&lt;h3&gt;
  
  
  /var
&lt;/h3&gt;

&lt;p&gt;Standing for &lt;em&gt;variable&lt;/em&gt;, /var directory contains files that are constantly changing, such as log files, events or spool files.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;Understanding and remembering all the directories in Linux it will take your time. Don't try to memorise it as if you were studying for it: Just by using Linux as you should (using the terminal!) you will get used to it. When you always start in /home/, you will learn that all the users have their own directory there. When you connect a USB to your computer, you will find it at /media, and you will remember that that's the purpose of that folder.&lt;/p&gt;

&lt;p&gt;Just keep using Linux and you'll get the hang of it in no time :)&lt;/p&gt;

&lt;p&gt;Or you can do one of the Linux courses I'm doing right now.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://letslearnabout.net/hacking/from-zero-to-hero/networking-and-linux-courses/"&gt;https://letslearnabout.net/hacking/from-zero-to-hero/networking-and-linux-courses/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://letslearnabout.net/hacking/from-zero-to-hero/networking-and-linux-courses/"&gt;Linux courses&lt;/a&gt;&lt;br&gt;
&lt;a href="https://letslearnabout.net/hacking/linux-file-system/"&gt;Original post: The Linux File System: A simple guide for beginners&lt;/a&gt;&lt;/p&gt;

</description>
      <category>linux</category>
      <category>tutorial</category>
      <category>learning</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Rkhunter tutorial – Protect your PC</title>
      <dc:creator>David MM👨🏻‍💻</dc:creator>
      <pubDate>Wed, 01 Nov 2023 22:57:16 +0000</pubDate>
      <link>https://forem.com/davidmm1707/rkhunter-tutorial-protect-your-pc-5ggm</link>
      <guid>https://forem.com/davidmm1707/rkhunter-tutorial-protect-your-pc-5ggm</guid>
      <description>&lt;p&gt;In an age where cybersecurity is a daily concern, you have to protect yourself. And that's what we are going to do with Rkhunter.&lt;/p&gt;

&lt;p&gt;Let's remove rootkits, backdoors and other exploits from your PC.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;&lt;span&gt;Table of contents&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Introduction&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Installation&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Running Rkhunter&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Resources&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Introduction: What is Rkhunter?
&lt;/h2&gt;

&lt;p&gt;But first of all, let's learn what Rkhunter is and what can it do for us.&lt;/p&gt;

&lt;p&gt;Rkhunter is a tool that scans your computer for rootkits, backdoors, &lt;a href="https://letslearnabout.net/hacking/from-zero-to-hero/day-051-vulnerabilities-101/"&gt;vulnerabilities&lt;/a&gt;, and local exploits. And, in case you don't know:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A &lt;strong&gt;rootkit&lt;/strong&gt; enables access to a computer. It stays at the root (hence the name, &lt;em&gt;root&lt;/em&gt; and &lt;em&gt;kit&lt;/em&gt;) and gives remote access and control to a malicious person. Nothing you want to do.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A &lt;strong&gt;backdoor&lt;/strong&gt; can let a hacker bypass any security system. Firewalls, antivirus, etc mean nothing once a backdoor has been established.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A &lt;strong&gt;vulnerability&lt;/strong&gt; is a flaw in a computer system that can be taken advantage of.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;And, finally, &lt;strong&gt;exploits&lt;/strong&gt; are pieces of software that can take advantage of existing bugs, errors or vulnerabilities in a system. From taking your bank data to stealing your passwords, and encrypting your data... anything is possible.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You don't want this. And, to solve it, we are going to use Rkhunter, a great and easy-to-use tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;To install Rkhunter, first update your Linux packages list, then install Rkhunter:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;sudo apt-get update&lt;br&gt;
sudo apt-get install rkhunter&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Shortly, you will be prompted with this screen:&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%2F8xovpgzgfsa6snrwhqy3.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%2F8xovpgzgfsa6snrwhqy3.png" alt="Image description" width="773" height="581"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I picked &lt;em&gt;Local only,&lt;/em&gt; but if you want to get emails from Rkhunter, select your preferred option and configure it.&lt;/p&gt;

&lt;p&gt;After everything is installed, check that Rkhunter is properly installed:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;rkhunter -V&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As I'm running this code on October 2023, I got the following message:&lt;/p&gt;

&lt;p&gt;Rootkit Hunter 1.4.6&lt;/p&gt;

&lt;p&gt;You may have a newer version. But now, let's configure it.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;vim /etc/rkhunter.conf&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And change the following lines:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;107  UPDATE\_MIRRORS=1&lt;br&gt;
122  MIRRORS\_MODE=0&lt;br&gt;
1190 WEB\_CMD=""&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We set up the mirror options to let Rkhunter update. Let's update it now:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;sudo rkhunter --update&lt;br&gt;
sudo rkhunter --propupd&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Everything should be set up now, as we have updated everything. Time for the fun stuff.&lt;/p&gt;

&lt;h3&gt;
  
  
  Running Rkhunter
&lt;/h3&gt;

&lt;p&gt;To run Rkhunter, simply run:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;sudo rkhunter --check&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;First, it will check general, shareable files in the /usr/ directory. After that, it will check for known rootkits (remember to update before running Rkhunter!), then, additional rootkit checks, malware checks, Linux-specific checks, your network and local host, etc.&lt;/p&gt;

&lt;p&gt;At the end, you'll be prompted with a summary:&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%2Fa5a1ox3rhl6vbyouwnkq.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%2Fa5a1ox3rhl6vbyouwnkq.png" alt="Image description" width="642" height="373"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Luckily, you won't have any warning, but I do. I'm going to run again the check with a special flag:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;sudo rkhunter --check --rwo&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This will run Rkhunter silently, only displaying any warning messages, in case it finds one or more of them.&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%2Fhm1nqsdp62hx977viu6n.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%2Fhm1nqsdp62hx977viu6n.png" alt="Image description" width="800" height="82"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Compared to the previous command, this one is way less verbose.&lt;/p&gt;

&lt;p&gt;The only warnings I have are the ones regarding &lt;em&gt;lwp-request&lt;/em&gt;, a false positive that gets flagged because it allows making HTTP requests, and an SSH misconfiguration. But nothing major.&lt;/p&gt;

&lt;p&gt;P.S. If you don't want to get a warning every time on safe files you run Rkhunter, you can add this to your &lt;em&gt;/etc/rkhunter.conf&lt;/em&gt; file:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;SCRIPTWHITELIST=/usr/bin/lwp-request&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Keep running Rkhunter from time to time to keep your computer safe and rootkit free :)&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.rockylinux.org/"&gt;Rkhunter docs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.veracode.com/security/rootkit"&gt;What is a rootkit?&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://letslearnabout.net/hacking/from-zero-to-hero/day-051-vulnerabilities-101/"&gt;Vulnerabilities&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://letslearnabout.net/hacking/rkhunter-tutorial/"&gt;Original post: Rkhunter tutorial&lt;/a&gt;&lt;/p&gt;

</description>
      <category>cybersecurity</category>
      <category>rootkits</category>
      <category>security</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Vue 3: Options API vs Composition API</title>
      <dc:creator>David MM👨🏻‍💻</dc:creator>
      <pubDate>Sun, 21 Nov 2021 16:16:55 +0000</pubDate>
      <link>https://forem.com/davidmm1707/vue-3-options-api-vs-composition-api-23c5</link>
      <guid>https://forem.com/davidmm1707/vue-3-options-api-vs-composition-api-23c5</guid>
      <description>&lt;p&gt;I used to use Vue to create my FrontEnds and, after one year and a half without using it, I'm re-learning it.&lt;/p&gt;

&lt;p&gt;The first thing that hit me, was that Vue 3 finally was a reality. I used the 2nd version, now I'm learning the 3rd.&lt;/p&gt;

&lt;p&gt;Right now I'm learning about the Composition API and I have a few questions that I would like to solve by Vue3 users:&lt;/p&gt;

&lt;p&gt;1) Do you use Composition API in your day to day?&lt;br&gt;
2) If yes, in which cases do you use Composition API? In which ones, the Options API?&lt;br&gt;
3) What are the drawbacks of the Composition API over Options? And benefits?&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>vue</category>
    </item>
    <item>
      <title>How to rebuild a ListView on Flutter using Provider async?</title>
      <dc:creator>David MM👨🏻‍💻</dc:creator>
      <pubDate>Tue, 29 Jun 2021 11:01:38 +0000</pubDate>
      <link>https://forem.com/davidmm1707/how-to-rebuild-a-listview-on-flutter-using-provider-async-3m25</link>
      <guid>https://forem.com/davidmm1707/how-to-rebuild-a-listview-on-flutter-using-provider-async-3m25</guid>
      <description>&lt;p&gt;&lt;em&gt;TL;DR: My Provider class doesn't trigger a rebuild, but I don't know what I'm doing wrong. Code provided below.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Hi,&lt;/p&gt;

&lt;p&gt;I have a ListView.builder nested inside a Consumer.&lt;/p&gt;

&lt;p&gt;While it creates as many MyProvider instances I have, if I delete or update an element, it does delete/update that element on the database, but it doesn't trigger a rebuild on the ListView builder, despite using notifyListeners().&lt;/p&gt;

&lt;p&gt;This is (a simplified version of) my code:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;genre_list.dart&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GenreListScreen&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;StatefulWidget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;routeName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'/genre-list'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;_GenreListScreenState&lt;/span&gt; &lt;span class="n"&gt;createState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_GenreListScreenState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;_GenreListScreenState&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;GenreListScreen&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;Widget&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BuildContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Scaffold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;appBar:&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nl"&gt;body:&lt;/span&gt; &lt;span class="n"&gt;Consumer&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;GenreProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;builder:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;genres&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getGenres&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ListView&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nl"&gt;itemCount:&lt;/span&gt; &lt;span class="n"&gt;genres&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nl"&gt;itemBuilder:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;genre&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;genres&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
              &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ListTile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nl"&gt;title:&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;genre&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'title'&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
                &lt;span class="nl"&gt;subtitle:&lt;/span&gt; &lt;span class="n"&gt;IconButton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                  &lt;span class="nl"&gt;icon:&lt;/span&gt; &lt;span class="n"&gt;Icon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Icons&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;edit&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="nl"&gt;onPressed:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                      &lt;span class="n"&gt;GenreProvider&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;updateGenre&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;genre&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="s"&gt;'Testing'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="kd"&gt;on&lt;/span&gt; &lt;span class="n"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                      &lt;span class="n"&gt;showSnackBar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="nl"&gt;text:&lt;/span&gt; &lt;span class="s"&gt;'Unknown error updating the genre.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="nl"&gt;color:&lt;/span&gt; &lt;span class="n"&gt;Colors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;red&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="nl"&gt;context:&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                      &lt;span class="p"&gt;);&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                  &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="p"&gt;),&lt;/span&gt;
              &lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;genre_provider.dart&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GenreProvider&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;ChangeNotifier&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;dynamic&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_genres&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

  &lt;span class="n"&gt;Future&lt;/span&gt; &lt;span class="n"&gt;fetchGenres&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;QuerySnapshot&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;dynamic&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;genres&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
          &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;FirebaseFirestore&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;instance&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'genres'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

      &lt;span class="n"&gt;_genres&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
      &lt;span class="n"&gt;genres&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;docs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;genre&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_genres&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s"&gt;'id'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;genre&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'title'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;genre&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'title'&lt;/span&gt;&lt;span class="p"&gt;]});&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="n"&gt;notifyListeners&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;Future&lt;/span&gt; &lt;span class="n"&gt;updateGenre&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;FirebaseFirestore&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;instance&lt;/span&gt;
          &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'genres'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s"&gt;'title'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;updatedGenre&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_genres&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;firstWhere&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;updatedGenre&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'title'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;notifyListeners&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;dynamic&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="n"&gt;getGenres&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;_genres&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;After a successful login, I call &lt;strong&gt;fetchGenres&lt;/strong&gt; to get the data. Then, I move to &lt;strong&gt;GenteListScreen&lt;/strong&gt; and I can see all the genres I have on my Database.&lt;/p&gt;

&lt;p&gt;Clicking on the 'Edit' button, I edit the Genre on the Database (normally a Dialog with a TextFormField, but for the example it is just a fixed string), but it doesn't trigger an UI rebuild on the ListView.&lt;/p&gt;

&lt;p&gt;Calling setState(() {}) after the function, triggers a rebuild, and everything is fine, but this call should be done automatically by the Provider package via Consumer.&lt;/p&gt;

&lt;p&gt;So the question is: What I am missing on the code to trigger the automatically rebuild?&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>help</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Looking for Remote Jobs During the Pandemic</title>
      <dc:creator>David MM👨🏻‍💻</dc:creator>
      <pubDate>Wed, 03 Feb 2021 19:15:02 +0000</pubDate>
      <link>https://forem.com/davidmm1707/looking-for-remote-jobs-during-the-pandemic-k6p</link>
      <guid>https://forem.com/davidmm1707/looking-for-remote-jobs-during-the-pandemic-k6p</guid>
      <description>&lt;p&gt;Looking for a job always has been not an easy task. Now, with the Covid Pandemic, is even harder. And seems that it won't be better anytime soon.&lt;/p&gt;

&lt;p&gt;Luckily, this has forced many business to open their mind to hiring remotely, making it easier to find a remote job, from anywhere in the world. Let's see how and where we can do it!&lt;/p&gt;




&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;Looking for a new job is always a stressful task: Lots of time spent in searching, comparing, sending CV and emails, waiting for an answer...&lt;/p&gt;

&lt;p&gt;Since 2020 this has been even harder: Business closed, people getting fired, and having a website has become less of a priority than before.&lt;/p&gt;

&lt;p&gt;But enough of negative things.&lt;/p&gt;

&lt;p&gt;This has forced (finally!) business to open to hiring people for remote positions. Now you can look for jobs, not only in the city you live in but anywhere in the world.&lt;/p&gt;

&lt;p&gt;But this is not the only benefit of working from home...&lt;/p&gt;

&lt;h3&gt;
  
  
  Why work from home?
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi2.wp.com%2Fest.zetaestaticos.com%2Fextremadura%2Fimg%2Fnoticias%2F0%2F918%2F918476_1.jpg%3Fw%3D810%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi2.wp.com%2Fest.zetaestaticos.com%2Fextremadura%2Fimg%2Fnoticias%2F0%2F918%2F918476_1.jpg%3Fw%3D810%26ssl%3D1" alt="Remote jobs - Work from home"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Working remotely doesn't (just) mean being able to pick any job, regardless of the location of the company. It also offers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;No commute&lt;/strong&gt;. Save time, money and stress.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Better eating habits.&lt;/strong&gt; Instead of packing sandwiches or going to the nearest McDonalds, you can eat better from home.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Fewer distractions&lt;/strong&gt;. Yes, kids may annoy you a bit, but once you set rules with your kids and/or partner, you'll have fewer distractions than working from home. And fewer questions from coworkers when you're about to crack that problem :-)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;More freedom.&lt;/strong&gt; Business normally enforces a set of (arbitrary) rules, from what to wear to even how to cut your hair (yeah, I know...) or if you can wear jewellery or display tattoos. Ignore that working from home.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Flexible schedule&lt;/strong&gt;. Some business lets you manage your schedule: As long as you work your hours and produce results, you can choose when to work, leaving time for you to play with your kids, relax or do chores, improving your work-life balance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;More productivity&lt;/strong&gt;. Contrary to how many bosses think, working from home increases your productivity. No one is there to stop your train of thought to show you another cat video (just leave it on Slack and I'll see it when I have free time!).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Easier phone calls&lt;/strong&gt;. If you share your office, you know that calling your clients is torture. People trying to talk to you, people talking between them, printers, doors, more people yelling... From your own home, you don't have all that distractions.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While this takes self-discipline and it is lonely, a lot of people prefer working remotely than driving one hour to work in an office.&lt;/p&gt;

&lt;p&gt;Let's see now where to find that dreamy job.&lt;/p&gt;

&lt;h3&gt;
  
  
  Search engines
&lt;/h3&gt;

&lt;p&gt;Without a further ado, here is a list of places where you can search for a remote job:&lt;/p&gt;

&lt;h4&gt;
  
  
  Jooble
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F420%2F1%2A6jRjspj7y7vFXEh1VIey-g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F420%2F1%2A6jRjspj7y7vFXEh1VIey-g.png" alt="Remote jobs - Jooble"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://jooble.org/" rel="noopener noreferrer"&gt;Jooble&lt;/a&gt; lets you search for jobs anywhere in the world.&lt;/p&gt;

&lt;p&gt;Select what are you looking for (Node.JS dev, Flutter programmer, Web design) and add a location (a country, a city...or 'remote'!), and you'll find a lot of job offers.&lt;/p&gt;

&lt;p&gt;As an example, here's what you will find if you are looking for a &lt;a href="https://jooble.org/SearchResult?rgns=remote&amp;amp;ukw=react" rel="noopener noreferrer"&gt;Remote React job&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fletslearnabout.net%2Fwp-content%2Fuploads%2F2021%2F02%2Fimage-1024x273.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fletslearnabout.net%2Fwp-content%2Fuploads%2F2021%2F02%2Fimage-1024x273.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;984 vacancies seems a good number, right?&lt;/p&gt;

&lt;p&gt;You can also add your email to get notified when a new job is open!&lt;/p&gt;

&lt;p&gt;Jooble has been online for more than 10 years, offering hundreds of jobs in different technologies.&lt;/p&gt;

&lt;h4&gt;
  
  
  Remotive
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fremotive.io%2Fremotive_website_job%2Fstatic%2Fsrc%2Fimg%2Fdoge_title.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fremotive.io%2Fremotive_website_job%2Fstatic%2Fsrc%2Fimg%2Fdoge_title.png" alt="Remote jobs - Remotive"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://remotive.io/remote-jobs" rel="noopener noreferrer"&gt;Remotive&lt;/a&gt; focuses in only remote jobs.&lt;/p&gt;

&lt;p&gt;A search box with a drop-down menu to filter by category (Sales, DevOps, QA, Software developer...) is all you need to find a job here.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/images%2Fimage-1-1024x356.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/images%2Fimage-1-1024x356.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clean UI and easy to apply by login with LinkedIn or Github.&lt;/p&gt;

&lt;h4&gt;
  
  
  We work remotely
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh3.googleusercontent.com%2Fproxy%2FLYOr3SXA16GwXgzimnVayM53sdGmYLXX-43c1JVWayXR0caRkoXN4cKBwW3RbnnmmC1Oh7NkGH3_utiFfeO-P62NJJi-kSvV7Wf24mPrWB8X58DovcTNDN8PCRUhAns" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh3.googleusercontent.com%2Fproxy%2FLYOr3SXA16GwXgzimnVayM53sdGmYLXX-43c1JVWayXR0caRkoXN4cKBwW3RbnnmmC1Oh7NkGH3_utiFfeO-P62NJJi-kSvV7Wf24mPrWB8X58DovcTNDN8PCRUhAns" alt="Remote jobs - WWR"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://weworkremotely.com" rel="noopener noreferrer"&gt;We Work Remotely&lt;/a&gt; is another search engine focused on remote jobs.&lt;/p&gt;

&lt;p&gt;It has a nice and simple (yet powerful) advance search system, that lets you filter jobs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/images%2Fimage-2-1024x766.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/images%2Fimage-2-1024x766.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Stack Overflow
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fozg8rw7u7w2ck50cwk5h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fozg8rw7u7w2ck50cwk5h.png" alt="Remote jobs - Stack Overflow"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you have been programming for more than one week, you already know Stack Overflow. What you might not know is that it has its own &lt;a href="https://stackoverflow.com/jobs/remote-developer-jobs" rel="noopener noreferrer"&gt;Remote Developer Jobs listing&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/images%2Fimage-3-1024x640.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/images%2Fimage-3-1024x640.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It offers one of the best advanced search filtering system, being focused in just programming jobs, with even a voting system.&lt;/p&gt;

&lt;h4&gt;
  
  
  Indeed
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.theguardian.pe.ca%2Fmedia%2Fphotologue%2Fphotos%2Fcache%2F348-3481806_indeed-logo-indeed-logo-png_large.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.theguardian.pe.ca%2Fmedia%2Fphotologue%2Fphotos%2Fcache%2F348-3481806_indeed-logo-indeed-logo-png_large.jpg" alt="Indeed"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While not focused on just remote (or programming) jobs, you'll find plenty at &lt;a href="https://www.indeed.com/jobs?q=Remote+Programmer&amp;amp;l=" rel="noopener noreferrer"&gt;Indeed&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fletslearnabout.net%2Fwp-content%2Fuploads%2F2021%2F02%2Fimage-4-1024x597.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fletslearnabout.net%2Fwp-content%2Fuploads%2F2021%2F02%2Fimage-4-1024x597.png" alt="Remote jobs - Indeed"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, at this time it is listing thousands of remote jobs. What are you waiting for?&lt;/p&gt;

&lt;h4&gt;
  
  
  Remote Hunt
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fremotehunt.com%2Fimages%2Fremotehub-logo.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fremotehunt.com%2Fimages%2Fremotehub-logo.svg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://remotehunt.com/remote-jobs" rel="noopener noreferrer"&gt;Remote Hunt&lt;/a&gt;, at its own name implies, is a remote job search engine with daily new jobs.&lt;/p&gt;

&lt;p&gt;While it is not big (yet!), it is updated with new jobs daily.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/images%2Fimage-5-1024x835.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/images%2Fimage-5-1024x835.png" alt="Remote jobs - Remote Hunt"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Their advanced search system is very powerful, as you can select what benefits are you looking for (Equity, Pair Coding, Crypto...).&lt;/p&gt;

&lt;h3&gt;
  
  
  Final thoughts
&lt;/h3&gt;

&lt;p&gt;Talking about working remotely, we are living in an interesting time.&lt;/p&gt;

&lt;p&gt;A lot of business are open to hiring remote workers and, as you saw, you have a lot of websites where you can search for jobs. And you are aware of the benefits of working from home.&lt;/p&gt;

&lt;p&gt;Don't &lt;a href="https://letslearnabout.net/blog/lets-learn-about-fighting-procrastination/" rel="noopener noreferrer"&gt;procrastinate&lt;/a&gt; and start searching for the job of your dreams!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>NodeJS Tutorial – 01 – Creating your first server</title>
      <dc:creator>David MM👨🏻‍💻</dc:creator>
      <pubDate>Wed, 22 Jul 2020 17:00:02 +0000</pubDate>
      <link>https://forem.com/davidmm1707/nodejs-tutorial-01-creating-your-first-server-4009</link>
      <guid>https://forem.com/davidmm1707/nodejs-tutorial-01-creating-your-first-server-4009</guid>
      <description>&lt;p&gt;Learning NodeJS is a great opportunity for every web developer: Tons of jobs, easy to learn and, as Javascript is a MUST on web developing for the FrontEnd, you already know the language!&lt;/p&gt;

&lt;p&gt;With this tutorial, you will create your first NodeJS server in less than 10 minutes.&lt;/p&gt;

&lt;p&gt;In this video you will learn:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to install NodeJS in your computer&lt;/li&gt;
&lt;li&gt;What NPM is&lt;/li&gt;
&lt;li&gt;How to create your NodeJS configuration file&lt;/li&gt;
&lt;li&gt;How to create your first server and the base file&lt;/li&gt;
&lt;li&gt;How to create routes to your server&lt;/li&gt;
&lt;li&gt;How to install Nodemon&lt;/li&gt;
&lt;/ul&gt;

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




&lt;p&gt;Related articles:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/redirect?q=https%3A%2F%2Fwww.freecodecamp.org%2Fnews%2Fwhat-exactly-is-node-js-ae36e97449f5%2F&amp;amp;event=video_description&amp;amp;redir_token=QUFFLUhqbmoxNDBDRFJFSkhNTlRxMGtsUEc1a08xN3FRd3xBQ3Jtc0tsWk5kLUFMSWRJb1VvSjN6VVdnSjMyeEZydXNSUFlxYWJnckV6dDJEWWVnZFZTY2pXelZHWVNrcS1qTFVfdnJnSDc5ei05dEppRjdCUERKUi1Hd0hNWlppV3lYcGNmRnIycVZFajc3UEhLcFE2alZFVQ%3D%3D&amp;amp;v=DkT_VRqA38o"&gt;What exactly is Node.js?&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/redirect?q=https%3A%2F%2Fwww.altexsoft.com%2Fblog%2Fengineering%2Fthe-good-and-the-bad-of-node-js-web-app-development%2F&amp;amp;event=video_description&amp;amp;redir_token=QUFFLUhqbjlXRHZVWkxEMXBwblpadkQwWnJkY0Q0elI0Z3xBQ3Jtc0tubks5U3d5b3A1TFlvdjlMM2JodVVDZHZPMFUzLXZnSUlUT3JyLXNMaTMwY1FudDkyU3VTTGo5aklCQWdOS1YyQkRXVUZwbjRnNUxET1BSOFFiclRpRl92RldFOEFmeXBqVnlEUDMwb0R4QXVoRWpmRQ%3D%3D&amp;amp;v=DkT_VRqA38o"&gt;Pros and Cons of Node.js&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;a href="https://www.youtube.com/channel/UC9OLm6YFRzr4yjlw4xNWYvg?sub_confirmation=1"&gt;My Youtube tutorial videos&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/david1707/node_crash_course"&gt;Final code on Github&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/DavidMM1707"&gt;Reach to me on Twitter&lt;/a&gt;&lt;/p&gt;

</description>
      <category>node</category>
      <category>javascript</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>6 + 1 Free Django tutorials for beginners</title>
      <dc:creator>David MM👨🏻‍💻</dc:creator>
      <pubDate>Mon, 06 Jul 2020 15:46:39 +0000</pubDate>
      <link>https://forem.com/davidmm1707/6-1-free-django-tutorials-for-beginners-png</link>
      <guid>https://forem.com/davidmm1707/6-1-free-django-tutorials-for-beginners-png</guid>
      <description>&lt;p&gt;You have just finished the &lt;a href="https://docs.djangoproject.com/en/3.0/intro/tutorial01/"&gt;Django poll tutorial&lt;/a&gt;, and you don't know what should be your next step? Or are you looking for inspiration to improve your recently acquired &lt;a href="https://letslearnabout.net/blog/16-tips-for-python-and-django-beginners/"&gt;Django skills&lt;/a&gt;?&lt;/p&gt;

&lt;p&gt;Don't you worry, as I've listed down the best Django tutorials I have found when I was still learning. Here they are:&lt;/p&gt;




&lt;h3&gt;
  
  
  A proper blog, by &lt;a href="https://www.youtube.com/channel/UCCezIgC97PvUuR4_gbFUs5g"&gt;Corey Schafer&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ubbgHsOw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i0.wp.com/letslearnabout.net/wp-content/uploads/2020/07/image-12.png%3Ffit%3D810%252C430%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ubbgHsOw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i0.wp.com/letslearnabout.net/wp-content/uploads/2020/07/image-12.png%3Ffit%3D810%252C430%26ssl%3D1" alt="Django tutorials for beginners - Corey Schafer" width="800" height="425"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Yes, we know there are a lot of Django tutorials focused on blogs. But this one does it professionally. Deploying, AWS, enabling SSL certifications, users management, etc.&lt;/p&gt;

&lt;p&gt;Start here:&lt;/p&gt;

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




&lt;h3&gt;
  
  
  Customer management app, by &lt;a href="https://www.youtube.com/channel/UCTZRcDjjkVajGL6wd76UnGg"&gt;Dennis Ivy&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lMdeEI6s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i2.wp.com/letslearnabout.net/wp-content/uploads/2020/07/image-13.png%3Ffit%3D810%252C411%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lMdeEI6s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i2.wp.com/letslearnabout.net/wp-content/uploads/2020/07/image-13.png%3Ffit%3D810%252C411%26ssl%3D1" alt="Django tutorials for beginners - Dennis Ivy" width="800" height="406"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Build a Customer management app from scratch. Manage customer information, orders, multi-parameter filtering, authentication, password reset, role permission, etc. Pretty neat.&lt;/p&gt;

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




&lt;h3&gt;
  
  
  Ecommerce Website with Django and Stripe, by &lt;a href="https://www.youtube.com/channel/UCRM1gWNTDx0SHIqUJygD-kQ"&gt;JustDjango&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NvgrcP9b--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i2.wp.com/letslearnabout.net/wp-content/uploads/2020/07/image-15.png%3Ffit%3D810%252C326%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NvgrcP9b--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i2.wp.com/letslearnabout.net/wp-content/uploads/2020/07/image-15.png%3Ffit%3D810%252C326%26ssl%3D1" alt="" width="800" height="322"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With Django we can do things that are cool, but also profitable. Check this tutorial to learn how to create an Ecommerce Website with Django, using Stripe as a payment platform.&lt;/p&gt;

&lt;p&gt;Refunds, discount codes, creating and deleting items. Everything!&lt;/p&gt;

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




&lt;h3&gt;
  
  
  Twitter-like app with Django and React, by &lt;a href="https://www.youtube.com/channel/UCWEHue8kksIaktO8KTTN_zg"&gt;CodingEntrepreneurs&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--52nH5SK9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i2.wp.com/letslearnabout.net/wp-content/uploads/2020/07/image-14.png%3Ffit%3D810%252C409%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--52nH5SK9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i2.wp.com/letslearnabout.net/wp-content/uploads/2020/07/image-14.png%3Ffit%3D810%252C409%26ssl%3D1" alt="" width="800" height="404"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If just using Django (and maybe even Bootstrap!) feels a bit short or clunky, you can take up a notch and merge Django with React to create a great Twitter-like App.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Ecommerce Website with Django and React, by &lt;a href="https://www.youtube.com/channel/UCRM1gWNTDx0SHIqUJygD-kQ"&gt;JustDjango&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--M4uDwgWp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i2.wp.com/letslearnabout.net/wp-content/uploads/2020/07/image-17.png%3Ffit%3D810%252C456%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--M4uDwgWp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i2.wp.com/letslearnabout.net/wp-content/uploads/2020/07/image-17.png%3Ffit%3D810%252C456%26ssl%3D1" alt="" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An improvement from the previous Ecommerce Website, now using React too.&lt;/p&gt;

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




&lt;h3&gt;
  
  
  Django Chat application, by &lt;a href="https://www.youtube.com/channel/UCRM1gWNTDx0SHIqUJygD-kQ"&gt;JustDjango&lt;/a&gt;
&lt;/h3&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%2Fi%2Fg61tv3a4qp7xngqg081r.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%2Fi%2Fg61tv3a4qp7xngqg081r.png" alt="" width="800" height="672"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This one is a bit more advanced. Here, we are using Django Channels to provide your Django project with WebSockets to update our website in real-time.&lt;/p&gt;

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




&lt;h3&gt;
  
  
  Django Full course, by &lt;a href="https://www.youtube.com/channel/UC8butISFwT-Wl7EV0hUK0BQ"&gt;FreeCodeCamp&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Did you get excited by seeing the projects but you don't know Django and want to start? For the very beginners, I have an (almost) 4 hours crash course, so you can start right now:&lt;/p&gt;

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




&lt;p&gt;&lt;a href="https://www.youtube.com/channel/UC9OLm6YFRzr4yjlw4xNWYvg?sub_confirmation=1"&gt;My Youtube tutorial videos&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/DavidMM1707"&gt;Reach to me on Twitter&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/david1707"&gt;My Github&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Contact me: &lt;a href="mailto:DavidMM1707@gmail.com"&gt;DavidMM1707@gmail.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>django</category>
      <category>python</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Creating a Python virtual environment</title>
      <dc:creator>David MM👨🏻‍💻</dc:creator>
      <pubDate>Sat, 04 Jul 2020 17:34:21 +0000</pubDate>
      <link>https://forem.com/davidmm1707/creating-a-python-virtual-environment-2dj3</link>
      <guid>https://forem.com/davidmm1707/creating-a-python-virtual-environment-2dj3</guid>
      <description>&lt;p&gt;Many people use Anaconda to write Python code. But it is so cumbersome for small scripts and hard to manage.&lt;/p&gt;

&lt;p&gt;Instead, we can create our own virtual environments (like our own world) where we only have the packages we want to install.&lt;/p&gt;

&lt;p&gt;In about 6 minutes we will be creating a Python virtual environment with Pipenv.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=mVzqOhdVJkc"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--95Imjqe2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://img.youtube.com/vi/mVzqOhdVJkc/0.jpg" alt="" width="480" height="360"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Table of contents&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What we will learn here&lt;/p&gt;

&lt;p&gt;1- Creating a virtual environment&lt;/p&gt;

&lt;p&gt;2- Installing packages on our Virtual Environment&lt;/p&gt;

&lt;p&gt;3- Creating a Scrapy spider on our new Virtual Environment&lt;/p&gt;

&lt;p&gt;Final Thoughts&lt;/p&gt;




&lt;h3&gt;
  
  
  What we will learn here
&lt;/h3&gt;

&lt;p&gt;In this video you will learn how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What Virtual Environments are&lt;/li&gt;
&lt;li&gt;Why we use them&lt;/li&gt;
&lt;li&gt;How to create our own Virtual Environment&lt;/li&gt;
&lt;li&gt;To install packages on our Virtual Environment&lt;/li&gt;
&lt;li&gt;How to create a small project from our Virtual Environment&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  1- Creating a virtual environment
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Da_C6sVO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/v1/images/venv.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Da_C6sVO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/v1/images/venv.jpg" alt="" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  What's a Virtual Environment?
&lt;/h4&gt;

&lt;p&gt;Many people use &lt;a href="https://en.wikipedia.org/wiki/Anaconda_(Python_distribution)"&gt;Anaconda&lt;/a&gt;, a Free Python distribution. While this helps when dealing with complex things by installing a series of packages (such as Machine Learning, Data Science, etc), sometimes is a bit cumbersome, especially when we want to control our environment by installing/removing packages, updating, etc.&lt;/p&gt;

&lt;p&gt;What can we do instead of using Anaconda?&lt;/p&gt;

&lt;p&gt;We can create a Virtual Environment and install the packages we need, manually.&lt;/p&gt;

&lt;p&gt;But first... What's a Virtual Environment?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://realpython.com/python-virtual-environments-a-primer/#what-is-a-virtual-environment"&gt;Real Python&lt;/a&gt; has a good definition here:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;At its core, the main purpose of Python virtual environments is to create an isolated environment for Python projects. This means that each project can have its own dependencies, regardless of what dependencies every other project has.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Imagine that you created a Django project in 2019, using Django 2.2. Now, on mid-2020. you want to update to Django 3. After doing it, your older Django project doesn't work because it was for Django 2.2!&lt;/p&gt;

&lt;p&gt;By using a Virtual Environment, each project has its own local packages list, with its own version.&lt;/p&gt;

&lt;p&gt;We can have an older project using Django 2.2, and a newer one using Django 3. Each time we work on one or other project, we just load their own Virtual Environment. This way we use their local packages.&lt;/p&gt;

&lt;p&gt;As everything, the best way to understand it is by practicing, so let's do it!&lt;/p&gt;

&lt;h4&gt;
  
  
  Creating our Virtual Environment
&lt;/h4&gt;

&lt;p&gt;If you have installed Python (and you should, because you're reading this post!), you have already the &lt;a href="https://pypi.org/project/virtualenv/"&gt;virtualenv&lt;/a&gt; package installed. But on this tutorial, we are going to use &lt;a href="https://pypi.org/project/pipenv/"&gt;pipenv&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We need to install pipenv on our computer, to have access anywere:&lt;/p&gt;

&lt;p&gt;pip install pipenv&lt;/p&gt;

&lt;p&gt;After that, move to the folder where you want to create your project, and create a Virtual Environment with 'pipenv shell':&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dFPzXdNv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i2.wp.com/letslearnabout.net/wp-content/uploads/2020/07/image.png%3Ffit%3D810%252C73%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dFPzXdNv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i2.wp.com/letslearnabout.net/wp-content/uploads/2020/07/image.png%3Ffit%3D810%252C73%26ssl%3D1" alt="" width="800" height="71"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After a few seconds, this will create a Python virtual environment:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--13PgoPLV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i2.wp.com/letslearnabout.net/wp-content/uploads/2020/07/image-1.png%3Ffit%3D810%252C297%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--13PgoPLV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i2.wp.com/letslearnabout.net/wp-content/uploads/2020/07/image-1.png%3Ffit%3D810%252C297%26ssl%3D1" alt="" width="800" height="294"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can use the commandos 'pip list' and 'pip freeze' to list the packages you have installed on the current Virtual Environment: 'Pip list' will list every package installed (even the ones installed by default such as setuptools, pip and wheel) while 'pip freeze' ONLY the ones you installed manually:&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%2Fi%2Fgd6vpnljql22e61la2rc.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%2Fi%2Fgd6vpnljql22e61la2rc.png" alt="Alt Text" width="800" height="222"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, we have no packages installed. Let's install them!&lt;/p&gt;




&lt;h3&gt;
  
  
  2- Installing packages on our Virtual Environment
&lt;/h3&gt;

&lt;p&gt;On this tutorial, we will create a basic &lt;a href="https://scrapy.org/"&gt;Scrapy&lt;/a&gt; project.&lt;/p&gt;

&lt;p&gt;You don't need to know how to use Scrapy, as this is just an example, but Scrapy is a framework that lets you extract data from websites. I have a few blogpost &lt;a href="https://letslearnabout.net/tutorial/scrapy-tutorial/python-scrapy-tutorial-for-beginners-01-creating-your-first-spider/"&gt;tutorials on Scrapy&lt;/a&gt; if you want to learn it, but as I said, you don't need to know it.&lt;/p&gt;

&lt;p&gt;Anyway, we need to install Scrapy. If we go to &lt;a href="https://scrapy.org/"&gt;their website&lt;/a&gt; we can see that installing it is quite easy:&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%2Fi%2Fjkxnntxqj37yv7f7bi7c.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%2Fi%2Fjkxnntxqj37yv7f7bi7c.png" alt="Alt Text" width="417" height="226"&gt;&lt;/a&gt;&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%2Fi%2Fpay8y6p451ou3wsd7jk8.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%2Fi%2Fpay8y6p451ou3wsd7jk8.png" alt="Alt Text" width="800" height="349"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After a little bit, you'll have everything you need installed. Let's see if everything is correct:&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%2Fi%2Frlg92n0urz2c0waipavv.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%2Fi%2Frlg92n0urz2c0waipavv.png" alt="Alt Text" width="800" height="755"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Scrapy, along a bunch of helper packages, has installed.&lt;/p&gt;

&lt;p&gt;Let's write a basic Scrapy spider to see if everything is in order.&lt;/p&gt;




&lt;h3&gt;
  
  
  3- Creating a Scrapy spider on our new Virtual Environment
&lt;/h3&gt;

&lt;p&gt;Let's create a Scrapy spider by following the &lt;a href="https://docs.scrapy.org/en/latest/intro/tutorial.html#creating-a-project"&gt;docs tutorial&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;On the folder you are, run:&lt;/p&gt;

&lt;p&gt;scrapy startproject tutorial&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fXQoR-Va--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i1.wp.com/letslearnabout.net/wp-content/uploads/2020/07/image-7.png%3Ffit%3D810%252C589%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fXQoR-Va--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i1.wp.com/letslearnabout.net/wp-content/uploads/2020/07/image-7.png%3Ffit%3D810%252C589%26ssl%3D1" alt="" width="800" height="582"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Under tutorial/spiders folder, create a spider file (for example, quotes_spider.py) and copy 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;import scrapy

class QuotesSpider(scrapy.Spider):
    name = "quotes"

    def start\_requests(self):
        urls = \[
            'http://quotes.toscrape.com/page/1/',
            'http://quotes.toscrape.com/page/2/',
        \]
        for url in urls:
            yield scrapy.Request(url=url, callback=self.parse)

    def parse(self, response):
        page = response.url.split("/")\[-2\]
        filename = 'quotes-%s.html' % page
        with open(filename, 'wb') as f:
            f.write(response.body)
        self.log('Saved file %s' % filename)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save the file, and run the code. Remember to move inside the project's folder:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_gYTMyDr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i0.wp.com/letslearnabout.net/wp-content/uploads/2020/07/image-8.png%3Ffit%3D810%252C53%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_gYTMyDr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i0.wp.com/letslearnabout.net/wp-content/uploads/2020/07/image-8.png%3Ffit%3D810%252C53%26ssl%3D1" alt="" width="800" height="52"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If everything is working correctly, you'll have 2 .HTML files on the root folder, proof that everything has worked without a problem:&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%2Fi%2F9s0b0ixxtv5ql4jqcz7o.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%2Fi%2F9s0b0ixxtv5ql4jqcz7o.png" alt="Alt Text" width="800" height="522"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Final Thoughts
&lt;/h3&gt;

&lt;p&gt;As you saw, creating a Virtual Environment, is not only easy, but useful.&lt;/p&gt;

&lt;p&gt;This way we each project with its own packages, and we can use the newest version on future projects without compromising the older ones.&lt;/p&gt;

&lt;p&gt;You just need to create a Virtual Environment, install the packages and you are set!&lt;/p&gt;

&lt;p&gt;Remember that if you want to learn easily how to use Scrapy to extract data from different websites, you can learn with my Scrapy tutorials: &lt;a href="https://letslearnabout.net/tutorial/scrapy-tutorial/python-scrapy-tutorial-for-beginners-01-creating-your-first-spider/"&gt;Creating your first spider with Scrapy&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://www.youtube.com/channel/UC9OLm6YFRzr4yjlw4xNWYvg?sub_confirmation=1"&gt;My Youtube tutorial videos&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/DavidMM1707"&gt;Reach to me on Twitter&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/david1707"&gt;My Github&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Contact me: &lt;a href="mailto:DavidMM1707@gmail.com"&gt;DavidMM1707@gmail.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
