<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Skriptmonkey</title>
    <description>The latest articles on DEV Community by Skriptmonkey (@skriptmonkey).</description>
    <link>https://dev.to/skriptmonkey</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%2F518525%2Feb4749f5-fc99-4a29-8973-b4ceea204300.jpg</url>
      <title>DEV Community: Skriptmonkey</title>
      <link>https://dev.to/skriptmonkey</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/skriptmonkey"/>
    <language>en</language>
    <item>
      <title>QR Code Gen - Creating the model</title>
      <dc:creator>Skriptmonkey</dc:creator>
      <pubDate>Tue, 06 Jan 2026 16:00:00 +0000</pubDate>
      <link>https://dev.to/skriptmonkey/creating-the-model-18c8</link>
      <guid>https://dev.to/skriptmonkey/creating-the-model-18c8</guid>
      <description>&lt;p&gt;Okay, now that the holidays are over. Let's get back to it, shall we? My hope is to get these out on a more regular schedule. However, like during the holiday season, sometimes other obligations (family, work) take priority.&lt;/p&gt;

&lt;p&gt;I'm just going to jump right in to creating the QR app and designing/testing our basic "starter" model.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create the app
&lt;/h3&gt;

&lt;p&gt;Creating the app is simple enough.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;django-admin startapp qr
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then open the config/settings.py file and add &lt;code&gt;'qr',&lt;/code&gt; to the end of the "INSTALLED_APPS" variable.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fodj6qc20fo8hyx6org0x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fodj6qc20fo8hyx6org0x.png" alt="settings.py" width="636" height="268"&gt;&lt;/a&gt;&lt;br&gt;
Now that we have the "application" created, we can start thinking about content.&lt;/p&gt;
&lt;h3&gt;
  
  
  Location location location
&lt;/h3&gt;

&lt;p&gt;We need to figure out where we're going to store the QR code images when they're generated. In a larger project we might consider storing the images on a CDN (content delivery network) for better distribution over geographically different locations. But this isn't a big project. This is a small project where I don't expect anyone to really use so I'm not going to worry about load times, yet.&lt;br&gt;
What I will do, is create a 'media' folder at the base of the project and set the &lt;code&gt;'MEDIA_ROOT'&lt;/code&gt; variable to the new folder in the &lt;code&gt;settings.py&lt;/code&gt; file.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkz0flgn3ar645ke60ez1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkz0flgn3ar645ke60ez1.png" alt="MEDIA_ROOT" width="800" height="403"&gt;&lt;/a&gt;&lt;br&gt;
Note: I also had to add &lt;code&gt;import os&lt;/code&gt; to the top of my settings file.&lt;/p&gt;

&lt;p&gt;Also, quick tip: keep a separate terminal open with &lt;code&gt;python manage.py runserver&lt;/code&gt; running. Whenever you save a change to a file it'll refresh the local web server and report any errors (like using the os module without importing it).&lt;/p&gt;
&lt;h3&gt;
  
  
  Create the model
&lt;/h3&gt;

&lt;p&gt;This will be a simple model to start. All we want is a single line text input which we'll use to generate the QR code. We can add more QR code customization later.&lt;br&gt;
So what fields do I need?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;a field to store the input text.&lt;/li&gt;
&lt;li&gt;a field to store the location of the generated image&lt;/li&gt;
&lt;li&gt;and a field for the creation date.
I'm also adding in a couple of functions (stolen from the Django tutorial) to help later on.
Here is what my &lt;code&gt;qr/models.py&lt;/code&gt; file looks like so far.
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django.db&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django.utils&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;timezone&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;QRCode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;input_text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;qr_code_img&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ImageField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;upload_to&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;qr_codes/&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;pub_date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DateTimeField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;date published&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__str__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&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;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;input_text&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;was_published_recently&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;timezone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&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;now&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;timedelta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pub_date&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;I also needed to install the pillow module using &lt;code&gt;pip install pillow&lt;/code&gt; to use the ImageField field.&lt;/p&gt;
&lt;h3&gt;
  
  
  The Segno Package
&lt;/h3&gt;

&lt;p&gt;Now that we have a model, I'd like to do something with it. As in, create some QR codes. To do that, I've decided to go with the Segno package. And... I'll be honest, I did about 10 seconds of searching and just picked something. Segno seems easy enough to use and looks like it has the features that I'd want in a QR code generating web app.&lt;br&gt;
Installing Segno was straight forward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;(&lt;/span&gt;.venv&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;segno
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Creating a QR code using Segno is also very easy.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;segno&lt;/span&gt;
&lt;span class="n"&gt;qrcode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;segno&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;test&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;qrcode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;test.png&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a "test" QR code and saves it as "test.png". Easy right?&lt;/p&gt;

&lt;p&gt;You can find more info on the Segno package from the &lt;a href="https://pypi.org/project/segno/" rel="noopener noreferrer"&gt;PyPi website&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing the model
&lt;/h3&gt;

&lt;p&gt;Now let's test out the model using the Segno package. I'm taking another chapter out of the Django tutorial and using the Django shell to do our testing. But first, let's migrate our changes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;(&lt;/span&gt;.venv&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;./manage.py makemigrations
Migrations &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="s1"&gt;'qr'&lt;/span&gt;:
  qr/migrations/0001_initial.py
    + Create model QRCode
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;(&lt;/span&gt;.venv&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;./manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, qr, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying auth.0012_alter_user_first_name_max_length... OK
  Applying qr.0001_initial... OK
  Applying sessions.0001_initial... OK
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's enter into the shell to play around with our new model.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;(&lt;/span&gt;.venv&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;./manage.py shell
7 objects imported automatically &lt;span class="o"&gt;(&lt;/span&gt;use &lt;span class="nt"&gt;-v&lt;/span&gt; 2 &lt;span class="k"&gt;for &lt;/span&gt;details&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;

Python 3.14.2 &lt;span class="o"&gt;(&lt;/span&gt;main, Dec  5 2025, 00:00:00&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;GCC 15.2.1 20251111 &lt;span class="o"&gt;(&lt;/span&gt;Red Hat 15.2.1-4&lt;span class="o"&gt;)]&lt;/span&gt; on linux
Type &lt;span class="s2"&gt;"help"&lt;/span&gt;, &lt;span class="s2"&gt;"copyright"&lt;/span&gt;, &lt;span class="s2"&gt;"credits"&lt;/span&gt; or &lt;span class="s2"&gt;"license"&lt;/span&gt; &lt;span class="k"&gt;for &lt;/span&gt;more information.
&lt;span class="o"&gt;(&lt;/span&gt;InteractiveConsole&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; import segno &lt;span class="c"&gt;# import segno&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; import os
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; from django.utils import timezone &lt;span class="c"&gt;# import django timezone&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; QRCode.objects.all&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="c"&gt;# show that nothing has been done, yet.&lt;/span&gt;
&amp;lt;QuerySet &lt;span class="o"&gt;[]&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Everything is setup, let's create a new QRCode object with some test input text. Then we'll use the new object's input_text to create the QR code and use the object's ID for the naming.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; qrcode &lt;span class="o"&gt;=&lt;/span&gt; QRCode&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;input_text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"This is a test"&lt;/span&gt;, &lt;span class="nv"&gt;pub_date&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;timezone.now&lt;span class="o"&gt;())&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; qrcode.save&lt;span class="o"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; qrcode.id
1
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; qrcode.qr_code_img &lt;span class="o"&gt;=&lt;/span&gt; f&lt;span class="s2"&gt;"{qrcode.id}.png"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; qrcode.save&lt;span class="o"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; from config.settings import MEDIA_ROOT
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; qr_code_path &lt;span class="o"&gt;=&lt;/span&gt; os.path.join&lt;span class="o"&gt;(&lt;/span&gt;MEDIA_ROOT, &lt;span class="s1"&gt;'qr_codes'&lt;/span&gt;, f&lt;span class="s2"&gt;"{qrcode.id}.png"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; qr &lt;span class="o"&gt;=&lt;/span&gt; segno.make_qr&lt;span class="o"&gt;(&lt;/span&gt;qrcode.input_text&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; qr.save&lt;span class="o"&gt;(&lt;/span&gt;qr_code_path, &lt;span class="nv"&gt;scale&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;4&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now we should have a PNG file saved at media/qr_codes/1.png.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2r0p8zaxqn3p2juyq2r9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2r0p8zaxqn3p2juyq2r9.png" alt="PNG Image created" width="507" height="406"&gt;&lt;/a&gt;&lt;br&gt;
To be honest, this last part took a lot longer than expected. I kept running into a FileNotFoundError when attempting to create the QR code image. This was resolved by creating the qr_code_path variable with the full path to the "1.png" file location, which involved needing to import the MEDIA_ROOT variable from config.settings.&lt;/p&gt;

&lt;p&gt;Next up, I'll work on creating the templates for the input form and the QR code results page, then I'll work on creating the views later.&lt;/p&gt;

&lt;p&gt;To some of you more experienced Django developers, some tips and tricks are always appreciated in the comments. Especially if it makes something that I've done in the post easier to accomplish.&lt;/p&gt;

</description>
      <category>django</category>
      <category>beginners</category>
      <category>tutorial</category>
      <category>saas</category>
    </item>
    <item>
      <title>Getting Started with Django - Project Setup</title>
      <dc:creator>Skriptmonkey</dc:creator>
      <pubDate>Fri, 19 Dec 2025 12:00:00 +0000</pubDate>
      <link>https://dev.to/skriptmonkey/getting-started-with-django-project-setup-5eoj</link>
      <guid>https://dev.to/skriptmonkey/getting-started-with-django-project-setup-5eoj</guid>
      <description>&lt;h4&gt;
  
  
  Introduction
&lt;/h4&gt;

&lt;p&gt;In this series of posts, I'll be building my way from fresh graduate of the Django tutorial (months ago) to SaaS application builder extraordinaire. The goal is to take a simple, over-done, unimaginative idea (QR code generator) and build a SaaS application out of it. For educational fun, of course. Complete with user authentication, and monetization strategies without the.... monetization?? I'm going to add "paid" tiers, but no actual payment methods, for now. Unless? Just kidding..... heh.&lt;/p&gt;

&lt;p&gt;The purpose of this project is to practice building web applications in Django and write about it along the way. A real "learning in public" kind of project.&lt;/p&gt;

&lt;p&gt;So, let's just go ahead and jump into the process. We'll start with a simple project setup. Here is my standard setup process.&lt;/p&gt;

&lt;p&gt;I am on a Linux workstation so all of the commands will be in bash.&lt;/p&gt;

&lt;h4&gt;
  
  
  Creating the project
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Create the folder&lt;br&gt;
I have a Code/Py folder in my home folder. This is where I like to start my Django projects.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~/Code/Py/
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;QRCodeGen
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;QRCodeGen/
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Install Python VirtualEnv, and activate&lt;br&gt;
At the root of this folder, I setup the python virtualenv.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;python3 &lt;span class="nt"&gt;-m&lt;/span&gt; venv .venv
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;source&lt;/span&gt; .venv/bin/activate
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Upgrade Setuptools and Pip&lt;br&gt;
As a habit, before I install any packages through pip, I make sure to upgrade both setuptools and pip.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--upgrade&lt;/span&gt; setuptools pip
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Install DJango&lt;br&gt;
Now we can install the Django package.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;django
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create Django Project&lt;br&gt;
This is where people might start to question my process. &lt;br&gt;
The folder that we're in is the project folder, so I don't want to create a nested project folder inside of the project folder. I prefer to use the current folder. I also name the project "config" because that will create the folder that will hold what I consider the config files for the project.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# notice the lone period at the end.&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;django-admin startproject config &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;I'll be honest, I'm not experienced enough to know if this preference will bite me in the long run. I've only created simple, single page apps so far. So go ahead, tell me why I'm wrong here.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Lastly for this post, run the dev server.&lt;br&gt;
This is just a quick test to make sure everything has been setup properly so far.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;./manage.py runserver
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Then open your web browser to &lt;a href="http://127.0.0.1:8000" rel="noopener noreferrer"&gt;http://127.0.0.1:8000&lt;/a&gt; or &lt;a href="http://localhost:8000" rel="noopener noreferrer"&gt;http://localhost:8000&lt;/a&gt;. There will be a link in the terminal that you can click, if your terminal supports it. This is what you should see.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxetnpxtg89sn70z6gvpx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxetnpxtg89sn70z6gvpx.png" alt="Django Congratulations Page" width="800" height="651"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a very simple setup, and honestly, the end of my comfort zone with Django. I've built some basic apps before but that was YEARS ago. So now I'm jumping back in. There are a few things that I like to do that I purposely skipped over to keep this a very short and simple guide. I'll go over these in future posts as I work my way through this project.&lt;/p&gt;

&lt;p&gt;Next, I'll go over creating a simple model for our QR code generator.&lt;/p&gt;

</description>
      <category>django</category>
      <category>beginners</category>
      <category>tutorial</category>
      <category>saas</category>
    </item>
    <item>
      <title>Learning to Code like Crafting in an MMORPG</title>
      <dc:creator>Skriptmonkey</dc:creator>
      <pubDate>Sat, 25 Oct 2025 20:25:31 +0000</pubDate>
      <link>https://dev.to/skriptmonkey/learning-to-code-like-crafting-in-an-mmorpg-1ckl</link>
      <guid>https://dev.to/skriptmonkey/learning-to-code-like-crafting-in-an-mmorpg-1ckl</guid>
      <description>&lt;p&gt;I’ve been on a bit of a productivity kick lately; thinking a lot about note-taking (bullet Journal + Obsidian), time management, and how systems thinking ties it all together. Systems thinking, in particular, has been a big part of my current studies. It’s made me look closely at how I approach learning itself, how I study, take notes, and write, to reinforce what I’ve learned.&lt;/p&gt;

&lt;p&gt;Then a thought occurred: one of the best examples of learning through systems already exists in something I love, crafting in MMORPGs.&lt;/p&gt;

&lt;p&gt;I’ve always been a bit of an MMORPG addict. I played World of Warcraft for way longer than I’d like to admit, spent thousands of hours buried in the spreadsheets of EVE Online, and still log into Guild Wars 2 when new content drops. These days I'm giving New World a go, and some friends have pulled me into the new Pax Dei game that recently released version 1.0.&lt;/p&gt;

&lt;p&gt;While I enjoy the combat, storylines, and endgame content (and maybe a little PvP), it’s the crafting that keeps me coming back. I love gathering materials, refining them, and building things from scratch to sell on the market. There’s something deeply satisfying about turning raw resources into something valuable and leveling up my crafting skill in the process.&lt;/p&gt;

&lt;p&gt;And honestly, learning to code (and other skills) feels exactly the same.&lt;/p&gt;

&lt;p&gt;In games like World of Warcraft or Guild Wars 2, you don’t start by crafting legendary weapons. You begin by chopping wood, mining copper, and making a lot of basic, unimpressive items. Nobody’s impressed by your mountain of copper daggers, but each one pushes your crafting experience a little higher.&lt;/p&gt;

&lt;p&gt;Coding follows the same pattern. You don’t jump straight from “Hello, world!” to deploying a full SaaS app with authentication, payments, and analytics. You get there by building small things, over and over, until the process becomes second nature, until you can forge something great without even realizing how far you’ve come.&lt;/p&gt;

&lt;p&gt;One of the content creators that I watch occasionally, &lt;a href="https://www.twitch.tv/theprimeagen" rel="noopener noreferrer"&gt;ThePrimeagen&lt;/a&gt;, has a saying that it takes "time in the saddle". This, to me, means "just start creating". Start small, build up, and learn along the way.&lt;/p&gt;

&lt;h4&gt;
  
  
  Gathering Resources (Fundamentals)
&lt;/h4&gt;

&lt;p&gt;Let’s start with the basics, what does it mean to “gather resources” in coding?&lt;/p&gt;

&lt;p&gt;In games, you begin by collecting the most common, easy-to-find materials: copper ore, herbs, cloth. This stuff is so abundant it practically litters the starting zones. You swing a pickaxe a few times, fill your bags, and head back to town.&lt;/p&gt;

&lt;p&gt;In coding, it’s the same. You start by learning the fundamentals: variables, loops, functions, and classes. Resources for these basics are everywhere: tutorials, videos, interactive sites, documentation. A quick search for “how to learn programming” will bury you in guides eager to hand you your first virtual pickaxe.&lt;/p&gt;

&lt;p&gt;It’s not glamorous work. Writing a function that adds two numbers is the coding equivalent of mining copper. But without that raw material, you can’t craft anything worth showing off later.&lt;/p&gt;

&lt;p&gt;Just like the resources in the game getting better as you level up, the resources you gather when learning also get more advanced. Data structures and algorithms, design patterns, new technologies, and frameworks. The learning doesn't stop, you grow and learn more to continue growing.&lt;/p&gt;

&lt;h4&gt;
  
  
  Crafting Low-Level Items (Small Projects)
&lt;/h4&gt;

&lt;p&gt;Once you’ve gathered enough materials, it’s time to start crafting - and crafting a lot.&lt;/p&gt;

&lt;p&gt;In games, that usually means cranking out 20 basic daggers or 50 bandages, most of which will never see use. You’ll probably sell them to a vendor just to clear bag space.&lt;/p&gt;

&lt;p&gt;In coding, it looks a little different but feels the same. You build a simple calculator, a to-do list app, a tiny blog, or maybe a quick script that automates something trivial. These are small projects that probably only you will ever use, but they serve as your training ground.&lt;/p&gt;

&lt;p&gt;Will these projects make you famous? Not likely. But every one of them builds muscle memory. You’re learning how to structure a project, solve problems, and debug when things inevitably break. Just like crafting those “useless” daggers, the real reward isn’t the item—it’s the experience points you gain along the way.&lt;/p&gt;

&lt;h4&gt;
  
  
  Unlocking New Recipes (Concept Mastery)
&lt;/h4&gt;

&lt;p&gt;Grinding out enough low-level items eventually unlocks the good stuff.&lt;/p&gt;

&lt;p&gt;In games, the items you craft start to get interesting. They have stats, special bonuses, or unique effects—and as your skill increases, you learn new recipes. You move from crafting basic starter gear to creating useful items that other players actually want.&lt;/p&gt;

&lt;p&gt;In coding, the same thing happens. As you build more small projects, your understanding deepens. You start to see how different pieces fit together, how data flows, how logic connects, and how systems interact. Suddenly, things that once felt mysterious begin to make sense. Each concept you master unlocks the next, like learning a new recipe you didn’t even know existed.&lt;/p&gt;

&lt;h4&gt;
  
  
  Crafting Epic and Legendary Items (Big Projects)
&lt;/h4&gt;

&lt;p&gt;The real payoff comes when you take on big projects.&lt;/p&gt;

&lt;p&gt;In games, crafting a legendary weapon is a long-term goal. You need rare materials, patience, and persistence. Some ingredients might only drop from dungeon bosses or raid encounters, which means teaming up with others to get what you need. Even then, it’s still a deeply personal pursuit—the grind, the refinement, the long path to something extraordinary.&lt;/p&gt;

&lt;p&gt;In coding, the same idea applies. Building and deploying a large application—something complex and feature-rich—is the equivalent of crafting your own legendary item. It draws on every skill you’ve learned so far: designing systems, structuring data, creating interfaces, and learning how to ship your work into the real world. Sometimes you’ll need help from others, and learning to collaborate is another craft in itself.&lt;/p&gt;

&lt;p&gt;But the only way to reach this point without burning out is by grinding through those smaller builds first. Every simple project you’ve ever finished has been quietly preparing you for this moment.&lt;/p&gt;

&lt;h4&gt;
  
  
  The Grind is the Path
&lt;/h4&gt;

&lt;p&gt;It’s easy to get discouraged when your projects feel small. But here’s the secret: those small projects are not wasted time. They’re your grind. They’re your XP.&lt;/p&gt;

&lt;p&gt;Every tiny script, every toy project, every bug you squash, those are your daggers, your copper rings, your stacks of bandages. Without them, you'd never unlock the recipes for the bigger stuff.&lt;/p&gt;

&lt;p&gt;The trick is to keep moving forward. Don’t stay stuck crafting the same copper sword forever. Try new patterns. Experiment with different materials. Build something slightly outside your comfort zone. Even failure gives you XP if you take the time to learn from it.&lt;/p&gt;

&lt;p&gt;Momentum is everything. The grind is not a punishment—it’s the path. Every repetition, every small improvement, every “failed” experiment is quietly pushing your skill tree upward. And before you know it, you’ll look back and realize: you’ve gone from crafting daggers to forging your first legendary item.&lt;/p&gt;

&lt;h4&gt;
  
  
  Where I’m At in the Grind
&lt;/h4&gt;

&lt;p&gt;So where am I right now in my own journey? I’m building a simple QR code generator using Python and the Django web framework. It’s not flashy. It’s not a legendary sword. But it’s teaching me how to structure a Django app, work with forms, and think through the flow of a real project from start to finish.&lt;/p&gt;

&lt;p&gt;Eventually, I’d like to add more—an API using Django REST Framework, maybe even multi-tenancy. Each addition is another recipe unlocked, another refinement to the craft.&lt;/p&gt;

&lt;p&gt;This is my batch of iron daggers. Once I’ve mastered this, I’ll have the foundation to forge something greater. And one day, maybe that “something greater” will be a full-fledged SaaS app—my first real legendary.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: I used AI to help with editing and refining the flow of this post. Writing these articles is another part of my own “crafting grind”, a way to practice explaining my thoughts and what I’m learning as I go.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>learning</category>
      <category>coding</category>
      <category>gaming</category>
      <category>mmorpg</category>
    </item>
    <item>
      <title>Backup and Restore a WagtailCMS Website</title>
      <dc:creator>Skriptmonkey</dc:creator>
      <pubDate>Fri, 26 May 2023 15:04:59 +0000</pubDate>
      <link>https://dev.to/skriptmonkey/backup-and-restore-a-wagtailcms-website-5dmf</link>
      <guid>https://dev.to/skriptmonkey/backup-and-restore-a-wagtailcms-website-5dmf</guid>
      <description>&lt;p&gt;Essential Guide: Backing up and Restoring Your Wagtail Site for Data Security and Peace of Mind.&lt;/p&gt;

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

&lt;p&gt;Backups are an essential part of maintaining any website, including those built with Wagtail. Whether it's due to a server crash, a hacking incident, or accidental deletion, losing your website data can be devastating. In this blog post, I will walk you through the steps of manually creating a backup and restoring a Wagtail site. By following these steps, you can safeguard your website data and quickly restore it in the event of a disaster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a Backup
&lt;/h2&gt;

&lt;p&gt;There are two main types of backups that you need to create for your Wagtail site: a file system backup and a database backup. The file system backup will contain all the files that make up your website, while the database backup will contain all the data stored in your database.&lt;/p&gt;

&lt;h3&gt;
  
  
  Database Backup
&lt;/h3&gt;

&lt;p&gt;To create a database backup, follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;SSH into your server as a user with sudo privileges.&lt;/li&gt;
&lt;li&gt;(Optional) Navigate to your websites root directory. This is the directory where your Wagtail projects manage.py file is stored. For example, if you followed my guide to &lt;a href="https://experiencednovice.dev/blog/deploying-wagtail-on-centos8/" rel="noopener noreferrer"&gt;Deploying Wagtail&lt;/a&gt; your root directory would be at &lt;code&gt;/opt/wagtail/&amp;lt;projectname&amp;gt;&lt;/code&gt;. This is where I like to store the database backup so that it will be included in the file system backup.&lt;/li&gt;
&lt;li&gt;My server uses MariaDB so that's what I'll be documenting here. For other databases it's easy enough to do a search for creating a database dump. Run the following commands for switching to the root user, creating an SQL dump, then exiting back to your normal user.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo su
[sudo] password for user:
$ mysqldump -u root -p wagtail &amp;gt; db_backup.sql
Enter password:
$ exit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Move the file to a secure location. You can use commands like &lt;code&gt;scp&lt;/code&gt; or &lt;code&gt;rsync&lt;/code&gt; to copy the file to your local machine or to a remote backup server.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  File System Backup
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;SSH into your server as a user with sudo privileges.&lt;/li&gt;
&lt;li&gt;Use the tar command to compress and archive all the files in the root directory into a single file. For example, to create a backup file called 'example.com.tar.gz'  and store it in your users home directory use the following command
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ tar -czvf ~/example.com.tar.gz .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Move the file to a secure location. You can use commands like &lt;code&gt;scp&lt;/code&gt; or &lt;code&gt;rsync&lt;/code&gt; to copy the file to your local machine or to a remote backup server.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;At this point you should now have both a file system backup and a database backup stored in a secured location in case of emergencies. In the next section, I will walk you through the steps of restoring a backup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Restoring a Backup
&lt;/h2&gt;

&lt;p&gt;What good is a backup if you don't know how to restore? Whether you're restoring after an emergency or you're migrating your site to a new host, these steps will walk you through getting your site back up and running.&lt;/p&gt;

&lt;p&gt;I won't be going over setting up your web server, proxy software, or firewall. If you're not sure how to setup your host server have a look at my guide for &lt;a href="https://experiencednovice.dev/blog/deploying-wagtail-on-centos8/" rel="noopener noreferrer"&gt;Deploying Wagtail on CentOS 8&lt;/a&gt;. Instead of cloning a git repository follow the instructions on the next section to restore the file system. Instead of setting up the DB, follow the instructions in the Database Restore section.&lt;/p&gt;

&lt;h3&gt;
  
  
  File System Restore
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;SSH into your new server as a user with sudo privileges.&lt;/li&gt;
&lt;li&gt;Copy the backup file from your backup location. If you're using an attachable volume or an S3 equivalent, go ahead and mount that device to your new server, if you haven't already, and change into that directory using the &lt;code&gt;cd&lt;/code&gt; command.&lt;/li&gt;
&lt;li&gt;If you followed my deployment guide, linked above, change into your wagtail user.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo su - wagtail
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Create the folder where your project files will live. Then exit back to your user with sudo privileges (or switch to the tmux terminal with that user).
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ mkdir /opt/wagtail/&amp;lt;projectname&amp;gt;
$ exit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Extract the files from the backup tar.gz file.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo tar -xzvf example.com.tar.gz -C /opt/wagtail/&amp;lt;projectname&amp;gt;/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that the files are in place, we need to get the database setup before we continue.&lt;/p&gt;

&lt;h3&gt;
  
  
  Database Restore
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;As a user with sudo privileges switch to the root user.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo su
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Change into the directory with your SQL backup file. If you're following this guide it should be in your projects root folder.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cd /opt/wagtail/&amp;lt;projectname&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;To restore the database we need to first create it. And we might as well create the user and grant it all privileges while we're at it.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ mysql -u root -p
Enter password: &amp;lt;enter&amp;gt;
&amp;gt; CREATE DATABASE wagtail CHARACTER SET utf8mb4 COLLATE   utf8mb4_general_ci;
&amp;gt; CREATE USER 'wagtaildb'@'localhost' IDENTIFIED BY '&amp;lt;db user password&amp;gt;';
&amp;gt; GRANT ALL PRIVILEGES ON wagtail.* to wagtaildb@localhost;
&amp;gt; FLUSH PRIVILEGES;
&amp;gt; exit;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Now, restore the contents of the SQL file to your newly created wagtail database.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ mysql -u root -p wagtail &amp;lt; db_backup.sql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Finishing Up
&lt;/h3&gt;

&lt;p&gt;Now that your file system and database have been restored, I like to run migrations and collect static to make sure that everything is in place for your site. Switch to your wagtail user and make sure your have the virtual environment activated.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo su - wagtail
$ source .venv/bin/activate
$ cd &amp;lt;project name&amp;gt;
$ ./manage.py makemigrations
$ ./manage.py migrate
$ ./manage.py collectstatic --no-input
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Restore or configure your web server (Gunicorn, uWSGI, etc...) and your reverse proxy (Nginx, Apache) and you should be all set.&lt;/p&gt;

&lt;h2&gt;
  
  
  Best Practices for Backups and Restorations
&lt;/h2&gt;

&lt;p&gt;To ensure the effectiveness and reliability of your backups and restorations for a Wagtail site, consider the following best practices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Regularly Schedule Backups:&lt;/strong&gt; Set up a regular backup schedule to ensure that your data is consistently backed up. Depending on the frequency of updates and changes to your website, consider daily, weekly, or monthly backups.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test Your Backups:&lt;/strong&gt; Periodically test your backups by restoring them to a test environment. This step helps verify that your backups are complete and functional, allowing you to identify and address any issues before an actual restoration is needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Store Backups Off-Site:&lt;/strong&gt; Store your backups in an off-site location, separate from your production server. This practice provides protection against physical damage or server-related issues. Consider using cloud storage, external hard drives, or remote backup services.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Implement Multiple Backup Storage:&lt;/strong&gt; Avoid relying on a single backup location or storage device. Use multiple storage options to ensure redundancy and minimize the risk of data loss.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Encrypt Your Backups:&lt;/strong&gt; Protect the confidentiality and integrity of your backup data by encrypting it. This step ensures that even if your backups fall into the wrong hands, they will be unreadable without the encryption key.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Document the Backup and Restoration Process:&lt;/strong&gt; Maintain clear documentation outlining the step-by-step procedures for creating backups and restoring them. This documentation serves as a reference guide during emergency situations and helps ensure consistency in the process.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitor Backup Success and Errors:&lt;/strong&gt; Regularly check your backup logs and monitoring tools to verify the success of backups and identify any errors or failures. Promptly address any issues to maintain the reliability of your backup system.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep Software and Components Up to Date:&lt;/strong&gt; Regularly update and patch the software components of your Wagtail project, including the operating system, database, web server, and backup tools. This practice ensures compatibility, security, and optimal performance during backup and restoration processes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By following these best practices, you can enhance the reliability, security, and effectiveness of your backup and restoration procedures for your Wagtail site.&lt;/p&gt;

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

&lt;p&gt;In conclusion, implementing regular backups, testing them, and storing them off-site are crucial for ensuring the safety and integrity of your Wagtail site. By following best practices such as encryption, documentation, and monitoring, you can enhance the reliability and security of your backup and restoration processes. Additionally, keeping software and components up to date is essential for maintaining compatibility and optimal performance.&lt;/p&gt;

&lt;p&gt;Remember, preparedness and practice are key to successfully safeguarding your website data. With these practices in place, you can confidently navigate the backup and restoration process and protect your valuable Wagtail site.&lt;/p&gt;

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

&lt;p&gt;For more information and resources on Wagtail, backups, and website deployment, please visit the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.wagtail.org/en/stable/index.html" rel="noopener noreferrer"&gt;Official Wagtail Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://experiencednovice.dev/blog/deploying-wagtail-on-centos8/" rel="noopener noreferrer"&gt;Deploying Wagtail&lt;/a&gt; on CentOS8 with MariaDB/Nginx/Gunicorn&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Stay informed, explore, and keep your Wagtail website up and running smoothly!&lt;/p&gt;

</description>
      <category>wagtail</category>
      <category>python</category>
      <category>linux</category>
      <category>backup</category>
    </item>
    <item>
      <title>Updating WagtailCMS</title>
      <dc:creator>Skriptmonkey</dc:creator>
      <pubDate>Mon, 22 May 2023 13:58:30 +0000</pubDate>
      <link>https://dev.to/skriptmonkey/upgrading-wagtailcms-2ek5</link>
      <guid>https://dev.to/skriptmonkey/upgrading-wagtailcms-2ek5</guid>
      <description>&lt;p&gt;Step-by-Step Guide: Updating Your WagtailCMS Website on a RHEL Server for Improved Functionality and Security.&lt;/p&gt;

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

&lt;p&gt;Wagtail is a popular content management system that allows users to create and manage websites easily. However, as with any software, it's important to keep it up-to-date to ensure security and performance. In this blog post, we'll discuss the steps involved in manually updating Wagtail hosted on a Red Hat based Linux server. We'll cover everything from preparing for the update to troubleshooting common issues that may arise. By the end of this post, you'll be equipped with the knowledge you need to update your Wagtail site with confidence.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preparation
&lt;/h2&gt;

&lt;p&gt;Before updating Wagtail, it's important to prepare for the update process.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Read the release notes: It's important to read the release notes for the latest version of Wagtail to understand what changes have been made and if there are any compatibility issues that could affect your site. You can find the release notes on the official &lt;a href="https://docs.wagtail.org/en/stable/releases/index.html" rel="noopener noreferrer"&gt;Wagtail Docs&lt;/a&gt; website.&lt;/li&gt;
&lt;li&gt;Create a backup of your site: Creating a backup of your site is essential in case anything goes wrong during the update process. You can use a variety of backup methods, including using a backup plugin or manually backing up your site's files and database. It's important to store your backup files in a secure location.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Upgrade Steps
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;SSH into your Linux host with a user that has sudo privilages.
&lt;/li&gt;
&lt;li&gt;If you have a separate user that manages your Wagtail environment, switch into that user using this command, in my case I have a user named "wagtail".

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;$ sudo su - &amp;lt;user&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;NOTE: I like to use tmux with two terminals, one for the wagtail user and one for a user with sudo privileges. This helps with not having to constantly switch between users.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;Change into the root directory of your project. This will be the directory that has the &lt;code&gt;manage.py&lt;/code&gt; file.&lt;/li&gt;

&lt;li&gt;Edit your requirements.txt file to reference the version you'd like to upgrade to. 

&lt;ol&gt;
&lt;li&gt;Example: &lt;code&gt;wagtail&amp;gt;=5.0,&amp;lt;5.1&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;After saving the file, upgrade Wagtail using the pip command.

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;$ pip install -r requirements.txt&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;Once the upgrade process is complete, run the following commands to migrate any changes to the database.

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;$ python manage.py makemigrations&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$ python manage.py migrate&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;Fix any errors or warnings that pop up. If you fix errors, run the migration commands again.&lt;/li&gt;

&lt;li&gt;Run the collectstatic command to add all the new resources to your static folder.

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;$ python manage.py collectstatic --no-input&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;Restart your web server (Gunicorn, uWSGI, etc...) and test your website to make sure everything works as expected.&lt;/li&gt;

&lt;/ol&gt;

&lt;h2&gt;
  
  
  Troubleshooting
&lt;/h2&gt;

&lt;p&gt;If you encounter any issues during the WagtailCMS update process, try these troubleshooting steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Check the release notes to make sure you followed all the necessary steps, and that any prerequisites are in place. Make sure you're updating to a version that's compatible with your current setup.&lt;/li&gt;
&lt;li&gt;If you're using third-party packages or plugins make sure they're compatible with the new version. Check the documentation or contact the package/plugin developer for guidance.&lt;/li&gt;
&lt;li&gt;Seek support: If you can't resolve the issue on your own, reach out to the Wagtail community or the support team for assistance. Provide as much detail as possible about the issue, including any error messages or log files.&lt;/li&gt;
&lt;li&gt;As a last resort you can always redeploy your site using the most recent backup to get back to a functional state while you look further into why the upgrade failed.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By following these troubleshooting steps, you should be able to resolve any issues that may arise during the update process. Remember to always backup your data before making any updates or changes to your site.&lt;/p&gt;

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

&lt;p&gt;Updating Wagtail can seem like a daunting task, but it's an essential step to keep your site running smoothly and securely. By following the steps outlined in this blog post, you can successfully update Wagtail on both your development and production servers. Remember to always create a backup of your data before making any changes or updates, and to review the release notes and troubleshooting steps carefully to avoid any compatibility issues. If you encounter any issues, don't hesitate to seek support from the Wagtail community or the support team. With these tips, you can keep your Wagtail site up-to-date and running smoothly.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;The Wagtail Documentation for &lt;a href="https://docs.wagtail.org/en/stable/releases/upgrading.html" rel="noopener noreferrer"&gt;Upgrading Wagtail&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.wagtail.org/en/stable/releases/index.html" rel="noopener noreferrer"&gt;Release Notes&lt;/a&gt; for all the past Wagtail releases.&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://wagtail.org/slack" rel="noopener noreferrer"&gt;Wagtail Slack&lt;/a&gt; community is a great place to go to ask questions.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>django</category>
      <category>python</category>
      <category>linux</category>
      <category>wagtail</category>
    </item>
    <item>
      <title>TailwindCSS: Quick Setup</title>
      <dc:creator>Skriptmonkey</dc:creator>
      <pubDate>Thu, 16 Dec 2021 21:51:43 +0000</pubDate>
      <link>https://dev.to/skriptmonkey/tailwindcss-quick-setup-56k5</link>
      <guid>https://dev.to/skriptmonkey/tailwindcss-quick-setup-56k5</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;TailwindCSS is a utility-first CSS framework that allows you to style your HTML without needing to leave your HTML file. Most of the styling is done though pre-defined CSS classes. This results in a very easy system to use when adding style to your website.&lt;/p&gt;

&lt;p&gt;This quick setup guide will get you to a point where you can start writing HTML and adding in CSS as you go.&lt;/p&gt;

&lt;p&gt;If you're in a bit hurry and willing to sacrifice some features you can use the &lt;a href="https://tailwindcss.com/docs/installation/play-cdn" rel="noopener noreferrer"&gt;TailwindCSS CDN&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing Node.js
&lt;/h2&gt;

&lt;p&gt;This guide is written with Linux in mind but you can also install Nodejs on Windows and Mac.&lt;/p&gt;

&lt;p&gt;For RHEL based distros (Fedora, CentOS, Rocky Linux, etc..):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo dnf install nodejs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Ubuntu based distros you can install Node from &lt;a href="https://github.com/nodesource/distributions/blob/master/README.md" rel="noopener noreferrer"&gt;NodeSource&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ curl -fsSL https://deb.nodesource.com/setup_16.x | sudo -E bash -
$ sudo apt-get install -y nodejs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Now that we have Node installed, lets create our project environment.&lt;/p&gt;

&lt;p&gt;First, cd into your workspace. I like to use &lt;code&gt;~/Code&lt;/code&gt; as my main local workspace.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cd ~/Code
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a folder of us to work in and cd into that.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Initialize the directory for NPM. This will create a &lt;code&gt;package.json&lt;/code&gt; file within the folder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm init -y
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now install TailwindCSS.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm install tailwindcss
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To finish off this environment, lets create a &lt;code&gt;src&lt;/code&gt; and &lt;code&gt;public&lt;/code&gt; folder. You can name these folders whatever you want.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ mkdir src public
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Generating the TailwindCSS CSS file
&lt;/h2&gt;

&lt;p&gt;Next lets create a style.css file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ touch src/style.css
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, using your preferred text editor, add the &lt;a class="mentioned-user" href="https://dev.to/tailwind"&gt;@tailwind&lt;/a&gt; directives so your style.css file looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@tailwind base;
@tailwind components;
@tailwind utilities;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, open the &lt;code&gt;package.json&lt;/code&gt; file and add a new command to the scripts. The file should look like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "name": "tailwind",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "dev": "tailwind build -i src/style.css -o public/tailwind.css --watch"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "tailwindcss": "^3.0.1"
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, create a &lt;code&gt;tailwind.config.js&lt;/code&gt; file in your project root folder containing 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;module.exports = {
  content: ["./public/**/*.{html,js}"],
  theme: {
    extend: {},
  },
  plugins: [],
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember the "dev" script that we added into the &lt;code&gt;package.json&lt;/code&gt; file? Now we're going to run it in a separate terminal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will continue to run while you write your HTML. It will "watch" and "rebuild" your tailwind.css file as new utility classes are added into your HTML file. If you'd like to learn more about the Just-in-Time engine, check out this &lt;a href="https://tailwindcss.com/blog/just-in-time-the-next-generation-of-tailwind-css" rel="noopener noreferrer"&gt;blog post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You should now have a new tailwind.css file in the public folder. link this file into your HTML file and start coding away. Remember to keep the &lt;code&gt;npm run dev&lt;/code&gt; command running in a separate terminal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using the style.css file
&lt;/h2&gt;

&lt;p&gt;Now you can use the style.css file by adding a link tag into the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; of your html source file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;link href="./style.css" rel="stylesheet"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enjoy the new setup and happy coding!&lt;/p&gt;

</description>
      <category>tailwindcss</category>
      <category>html</category>
      <category>css</category>
      <category>web</category>
    </item>
    <item>
      <title>Migrate CentOS 8 to Alma Linux, Rocky Linux, or CentOS Stream</title>
      <dc:creator>Skriptmonkey</dc:creator>
      <pubDate>Mon, 12 Jul 2021 03:45:30 +0000</pubDate>
      <link>https://dev.to/skriptmonkey/migrate-centos-8-to-alma-linux-rocky-linux-or-centos-stream-4eed</link>
      <guid>https://dev.to/skriptmonkey/migrate-centos-8-to-alma-linux-rocky-linux-or-centos-stream-4eed</guid>
      <description>&lt;p&gt;So you went ahead and upgraded your CentOS 7 (or 6) servers up to CentOS 8 and then Red Hat announced that CentOS was turning into a rolling release distro. This decision has caused a fair amount of controversy on the Internet. A lot of people are upset that their freshly upgraded CentOS 8 servers are going EoL at the end of 2021. In this post I’ll share some options for migrating away from CentOS 8.&lt;/p&gt;

&lt;p&gt;Quick note: while writing this guide I’m using a fresh install of CentOS 8. I know that in most situations this will not be the case. Having a properly tested backup of your data is very, VERY important. We can’t assume that everything will go smoothly. Always have a way to restore.&lt;/p&gt;

&lt;p&gt;That being said, these will be quick and dirty guides. Before we begin go ahead and SSH into your CentOS server and make sure it’s up-to-date. Reboot if needed.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ssh user@centosserver
$ sudo dnf update -y
$ sudo reboot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Migrating to Alma Linux
&lt;/h2&gt;

&lt;p&gt;AlmaLinux is a community governed 1:1 RHEL clone created by CloudLinux to replace the soon-to-be EoL CentOS.&lt;/p&gt;

&lt;p&gt;First we’re going to download the almalinux-deploy.sh script.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ curl -O https://raw.githubusercontent.com/AlmaLinux/almalinux-deploy/master/almalinux-deploy.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Make the script executable and then run it.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ chmod +x almalinux-deploy.sh
$ sudo ./almalinux-deploy.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Wait until the script finishes running. You should see a “Migration to AlmaLinux is completed” when you’re done.&lt;/p&gt;

&lt;p&gt;Reboot the system to apply the changes.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo reboot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;After the reboot you can verify the migration by looking at the &lt;code&gt;/etc/os-release&lt;/code&gt; file.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cat /etc/os-release
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;All done! You’ve migrated from CentOS to AlmaLinux.&lt;/p&gt;

&lt;h2&gt;
  
  
  Migrating to Rocky Linux
&lt;/h2&gt;

&lt;p&gt;Rocky Linux was brought to life by the founder of the CentOS project, Gregory Kurtzer. Rocky intends to be a “100% bug-for-bug” clone of RHEL.&lt;/p&gt;

&lt;p&gt;Upgrading to Rocky Linux is as simple as the process for Alma Linux.&lt;/p&gt;

&lt;p&gt;First we’re going to download the migrate2rocky.sh script.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ curl -O https://raw.githubusercontent.com/rocky-linux/rocky-tools/main/migrate2rocky/migrate2rocky.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Make the script executable and execute the script with the &lt;code&gt;-r&lt;/code&gt; flag.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ chmod +x migrate2rocky.sh
$ sudo ./migrate2rocky.sh -r
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;When the script finishes reboot your system to apply the changes.&lt;/p&gt;

&lt;p&gt;You can verify the changes to your system by looking at the &lt;code&gt;/etc/os-release&lt;/code&gt; file.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cat /etc/os-release
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Upgrading to CentOS Stream
&lt;/h2&gt;

&lt;p&gt;The last option that I’m adding into this post, migrating to CentOS Stream.&lt;/p&gt;

&lt;p&gt;Also fairly simple, we have three main steps.&lt;/p&gt;

&lt;p&gt;First, enable the CentOS Stream repositories.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo dnf install centos-release-stream
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Second, update the CentOS repositories with CentOS Stream repositories.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo dnf swap centos-{linux,stream}-repos
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;And finally, migrate CentOS 8 to CentOS Stream.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo dnf distro-sync
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Reboot your system when this command finishes.&lt;/p&gt;

&lt;p&gt;You can verify the chances to your system by looking at the &lt;code&gt;/etc/os-release&lt;/code&gt; file.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cat /etc/os-release
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>migrate</category>
      <category>centos</category>
      <category>rockylinux</category>
      <category>almalinux</category>
    </item>
    <item>
      <title>Matomo Analytics with WagtailCMS</title>
      <dc:creator>Skriptmonkey</dc:creator>
      <pubDate>Wed, 31 Mar 2021 14:47:14 +0000</pubDate>
      <link>https://dev.to/skriptmonkey/matomo-analytics-with-wagtailcms-385c</link>
      <guid>https://dev.to/skriptmonkey/matomo-analytics-with-wagtailcms-385c</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Matomo is an open source alternative to Google Analytics that focuses on data ownership and privacy. Both a Cloud and an On-Premise solution exist. I opted for deploying Matomo to my own VPS. HowToForge has a great guide to help you deploy Matomo to your own server. &lt;a href="https://www.howtoforge.com/how-to-install-matomo-piwik-on-centos-8/" rel="noopener noreferrer"&gt;https://www.howtoforge.com/how-to-install-matomo-piwik-on-centos-8/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;WagtailCMS is an Open Source Content Management System built using Python and Django. This guide assumes that you have a website already built using Wagtail and you’re either ready to deploy or have already deployed into production.&lt;/p&gt;

&lt;p&gt;This guide will walk through integrating Matomo into your WagtailCMS website for a more private and secure method of tracking the number of visitors and other valuable metrics.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Access to the source code of your Wagtail site that is either in production or ready to be deployed to production.&lt;/li&gt;
&lt;li&gt;A Matomo account either in the Cloud or on your own On-Premise server.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Configuring Wagtail
&lt;/h2&gt;

&lt;p&gt;Let’s start by first configuring your Wagtail site for using the Matomo Javascript code. Matomo instructions say to add their Javascript to the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; tag of your site and to ensure the code is in all webpages. I try to avoid inline CSS/Javascript code when possible.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start by opening up the base.html page for your app. I like to separate my base.html files by apps instead of using one base.html for the whole project. In my case I have blog_base.html stored in
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/BASE_DIR/blog/templates/blog/blog_base.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Matomo instructions say to add the Javascript code  just before the &lt;code&gt;&amp;lt;/head&amp;gt;&lt;/code&gt; tag. Instead were going to add a &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag pointing to an analytics.js file. You can name this file whatever you want, analytics.js was the first thing to pop into my mind.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;script type="text/javascript" src="{% static 'js/analytics.js' %}"&amp;gt;&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Next we create the analytics.js file that we’ll use to import the Matomo JS code. Since I can potentially use this in other apps I created the file in the same folder that stores your settings folder.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BASE_DIR/ProjectName/static/js/analytics.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;If you’re using source control like Git, commit this file to your repository blank or with a comment indicating what the file is for.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Adding a new website to Matomo
&lt;/h2&gt;

&lt;p&gt;If you’re using a freshly installed instance of Matomo you will have created a website during the first time setup process. Just follow the instructions and you’ll be provided with the Javascript code to add into your Wagtail site. Otherwise follow the instructions below.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Log into your Matomo website and navigate to the “All Websites” tab in the top navigation bar.&lt;/li&gt;
&lt;li&gt;At the bottom of the list click on the “Add a new website” button.&lt;/li&gt;
&lt;li&gt;Assuming you’re using this on a website, click on the “Website” button to answer the “What would you like to measure?” dialog.&lt;/li&gt;
&lt;li&gt;Fill out the form for Managing Measurables and click Save at the bottom of the page.&lt;/li&gt;
&lt;li&gt;In your newly created website, find the link for “View Tracking Code”.&lt;/li&gt;
&lt;li&gt;On the Tracking Code page, scroll to the bottom of the Javascript Tracking section.&lt;/li&gt;
&lt;li&gt;Copy the Javascript only. Everything between the &lt;code&gt;&amp;lt;script&amp;gt;&amp;lt;/script&amp;gt;&lt;/code&gt; tags.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Last Step
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;On your production server, paste the code into the analytics.js file that was created in the Configuring Wagtial section.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  That’s it!
&lt;/h2&gt;

&lt;p&gt;Restart your HTTP server, in my case both Gunicorn and Nginx. Make sure that tracking is allowed in your browser for your website. You should see hits in Matomo when your site is visited.&lt;/p&gt;

&lt;p&gt;Cheers!&lt;/p&gt;

</description>
      <category>python</category>
      <category>analytics</category>
      <category>wagtail</category>
      <category>django</category>
    </item>
    <item>
      <title>Deploying Wagtail on CentOS8 with MariaDB/Nginx/Gunicorn</title>
      <dc:creator>Skriptmonkey</dc:creator>
      <pubDate>Sat, 02 Jan 2021 03:58:00 +0000</pubDate>
      <link>https://dev.to/skriptmonkey/deploying-wagtail-on-centos8-with-mariadb-nginx-gunicorn-3d6f</link>
      <guid>https://dev.to/skriptmonkey/deploying-wagtail-on-centos8-with-mariadb-nginx-gunicorn-3d6f</guid>
      <description>&lt;p&gt;Wagtail is an actively developed, open source CMS built on Python and the Django web framework. In this tutorial, we will go over how to deploy Wagtail on a CentOS 8 server with MariaDB, Nginx, and Gunicorn.&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting Started
&lt;/h3&gt;

&lt;p&gt;Start with a fresh install of CentOS 8 and make sure your server is up to date.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dnf update -y
# reboot the server to apply the updates if needed.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a non-root sudo user, if you haven't already&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;useradd &amp;lt;username&amp;gt;
passwd &amp;lt;username&amp;gt; #enter new password
# add the user to the wheel group for sudo access.
usermod -aG wheel &amp;lt;username&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, lets install Python 3.8 using our newly created sudo user account.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;su &amp;lt;username&amp;gt;
sudo dnf module -y install python38
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we need to install both Nginx and MariaDB.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo dnf install nginx mariadb-server git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Setup the environment
&lt;/h3&gt;

&lt;p&gt;At this point I like to create a Wagtail user account for managing the project code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo groupadd --system wagtail
sudo useradd --system --gid wagtail --shell /bin/bash --home /opt/wagtail wagtail
sudo mkdir /opt/wagtail
sudo chown wagtail:wagtail /opt/wagtail
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're hosting your project on GitHub or GitLab you can create an SSH key using the following commands.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo su wagtail
ssh-keygen -t rsa -b 2048 -C "&amp;lt;your email address&amp;gt;"
Generating public/private rsa key pair.
Enter file in which to save the key (/opt/wagtail/.ssh/id_rsa): &amp;lt;enter&amp;gt;
Created directory '/opt/wagtail/.ssh'.
Enter passphrase (empty for no passphrase): &amp;lt;enter password and/or press enter&amp;gt;
Enter same passphrase again: &amp;lt;enter password and/or press enter&amp;gt;
Your identification has been saved in /opt/wagtail/.ssh/id_rsa.
Your public key has been saved in /opt/wagtail/.ssh/id_rsa.pub.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can get the key by running the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cat /opt/wagtail/.ssh/id_rsa.pub
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Setting up the database
&lt;/h3&gt;

&lt;p&gt;Before we do anything else, lets start the MariaDB server and enable MariaDB on boot. Run these commands as root.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Now, to give ourselves a nice, secure default setup run the following command.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Enter current password for root (enter for none): &amp;lt;enter&amp;gt;
Set root password? [Y/n] n
Remove anonymous users? [Y/n] &amp;lt;enter&amp;gt;
Disallow root login remotely? [Y/n] &amp;lt;enter&amp;gt;
Remove test database and access to it? [Y/n] &amp;lt;enter&amp;gt;
Remove test database and access to it? [Y/n] &amp;lt;enter&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Log in to MariaDB and create the database and user.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mysql -u root -p
Enter password: &amp;lt;enter&amp;gt;
CREATE DATABASE wagtail CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
CREATE USER 'wagtaildb'@'localhost' IDENTIFIED BY '&amp;lt;db user password';
GRANT ALL PRIVILEGES ON wagtail.* to wagtaildb@localhost;
FLUSH PRIVILEGES;
exit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Deploying your Project
&lt;/h3&gt;

&lt;p&gt;The next step is to pull the code down from your repository. This guide assumes GitHub or GitLab is being used but feel free to use whatever you prefer. For this example I am using an empty project hosted on GitLab named Hello.&lt;/p&gt;

&lt;p&gt;If you're following this guide closely you should be logged in as root right now.&lt;/p&gt;

&lt;p&gt;Create the Python virtual environment in the wagtail users home directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;su - wagtail
python3.8 -m venv .venv
source .venv/bin/activate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Upgrade setuptools and pip&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Create a directory to store the logs.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Clone your git repositiory and cd into the project directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone https://gitlab.com/Skriptmonkey/hello.git
cd hello
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install the dependancies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install -r requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Migrate your database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python manage.py migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And finally, collect your static assets. Your STATIC_ROOT variable in the base.py settings file should be set to someplace that Nginx can easily access. I go with '/var/www/static'. Run the following commands as root.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd /opt/wagtail
source .venv/bin/activate
cd hello
python manage.py collectstatic --noinput
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Change back to the wagtail user and create a new settings file in the settings folder called &lt;code&gt;local.py&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;su - wagtail
vim /opt/wagtail/hello/hello/settings/local.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this settings file we want to import from &lt;code&gt;.base&lt;/code&gt;, add a &lt;code&gt;SECRET_KEY&lt;/code&gt;, and add in our &lt;code&gt;ALLOWED_HOSTS&lt;/code&gt;. How you generate a secret key is up to you. I like to create a "test" project on my local machine and take the &lt;code&gt;SECRET_KEY&lt;/code&gt; from that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from .base import *


SECRET_KEY = '&amp;lt;your secret key&amp;gt;' 

# SECURITY WARNING: define the correct hosts in production!
ALLOWED_HOSTS = ['exampleurl.com', 'www.exampleurl.com']

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configuring Gunicorn
&lt;/h3&gt;

&lt;p&gt;If Gunicorn hasn't been added to the requirements.txt file in your project it should be. But if it isn't you can install it through pip as the wagtail user.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;We need to create a start file for gunicorn. This file will be called whenever you need to start the application server. Feel free to use your favorite text editor.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vim /opt/wagtail/gunicorn_start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Paste this into your new file and update the variables to reflect your project. Pay special attention to the DJANGO_SETTINGS_MODULE, Wagtail uses a different convention than Django by default.&lt;br&gt;
&lt;/p&gt;

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

NAME="hello"
DJANGODIR=/opt/wagtail/hello
USER=wagtail
GROUP=wagtail
WORKERS=3
BIND=unix:/opt/wagtail/run/gunicorn.sock
DJANGO_SETTINGS_MODULE=hello.settings.production
DJANGO_WSGI_MODULE=hello.wsgi
LOGLEVEL=error

cd $DJANGODIR
source /opt/wagtail/.venv/bin/activate

export DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE
export PYTHONPATH=$DJANGODIR:$PYTHONPATH

exec /opt/wagtail/.venv/bin/gunicorn ${DJANGO_WSGI_MODULE}:application \
  --name $NAME \
  --workers $WORKERS \
  --user=$USER \
  --group=$GROUP \
  --bind=$BIND \
  --log-level=$LOGLEVEL \
  --log-file=-
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make the file executable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;chmod +x ~/gunicorn_start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make the run directory to store the unix socket file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir ~/run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set the permissions on the new directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;chmod 755 ~/run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now exit out of the wagtail user so we can setup the systemd gunicorn service.&lt;/p&gt;

&lt;p&gt;First create the systemd service file using your favorite editor.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Add the following to the file:&lt;br&gt;
&lt;/p&gt;

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

[Service]
User=wagtail
Group=wagtail
WorkingDirectory=/opt/wagtail
ExecStart=/opt/wagtail/gunicorn_start

[Install]
WantedBy=multi-user.target
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start the gunicorn service and enable the service to start on boot.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



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

&lt;p&gt;Lets get SELinux squared away before we start on configuring Nginx. We need to install the SELinux utilities.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo dnf install policycoreutils-python-utils -y
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we add &lt;code&gt;httpd_t&lt;/code&gt; to the permissive domains in SELinux.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo semanage permissive -a httpd_t
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While we're allowing things to happen on our server lets also allow both http and https through the server firewall.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo firewall-cmd --zone=public --permanent --add-service=http
sudo firewall-cmd --zone=public --permanent --add-service=https
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Change into the Nginx conf.d directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd /etc/nginx/conf.d/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once again, using your favorite editor create a config file for Nginx.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo vim wagtail.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add this into the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;upstream app_server {
    server unix:/opt/wagtail/run/gunicorn.sock fail_timeout=0;
}

server {
    listen 80;
    #listen [::]:80; # &amp;lt;- Uncomment this if you also have AAAA DNS record for IPV6.
    server_name IP_ADDRESS_OR_DOMAIN_NAME;  # &amp;lt;- insert here the ip address/domain name

    keepalive_timeout 5;
    client_max_body_size 4G;

    access_log /opt/wagtail/logs/nginx-access.log;
    error_log /opt/wagtail/logs/nginx-error.log;

    location /static/ {
        autoindex on;
        alias /opt/wagtail/hello/static/;
    }

    location /media/ {
        alias /opt/wagtail/hello/media/;
    }

    location / {
        try_files $uri @proxy_to_app;
    }

    location @proxy_to_app {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_pass http://app_server;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Test your Nginx configuration.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Start the service and enable it on boot.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Reboot 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;sudo reboot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  That's it!
&lt;/h3&gt;

&lt;p&gt;You should now have a functional Wagtail site deployed.&lt;/p&gt;

&lt;p&gt;Next I'd recommend configuring your webserver with an SSL certificate. Let's Encrypt is a good, free option.&lt;/p&gt;

</description>
      <category>linux</category>
      <category>wagtail</category>
      <category>nginx</category>
      <category>django</category>
    </item>
  </channel>
</rss>
