<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Alex&#039;s Home Network</title>
	<atom:link href="https://alexshomenetwork.com/feed/" rel="self" type="application/rss+xml" />
	<link>https://alexshomenetwork.com/</link>
	<description>Yet Another Pointless Blog</description>
	<lastBuildDate>Wed, 17 Dec 2025 15:31:35 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0</generator>

<image>
	<url>https://alexshomenetwork.com/wp-content/uploads/2022/11/cropped-favicon-32x32.png</url>
	<title>Alex&#039;s Home Network</title>
	<link>https://alexshomenetwork.com/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Using Fail2ban With Nginx and Cloudflare on Debian 13</title>
		<link>https://alexshomenetwork.com/fail2ban-nginx-cloudflare-debian-13/</link>
					<comments>https://alexshomenetwork.com/fail2ban-nginx-cloudflare-debian-13/#respond</comments>
		
		<dc:creator><![CDATA[Alex]]></dc:creator>
		<pubDate>Wed, 17 Dec 2025 15:22:57 +0000</pubDate>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Self-Hosting]]></category>
		<category><![CDATA[WordPress]]></category>
		<guid isPermaLink="false">https://alexshomenetwork.com/?p=923</guid>

					<description><![CDATA[<p>As a long-enough overdue update on my previous guide, Installing WordPress on Debian 13 (Link here), it&#8217;s time to focus a bit more on security, which happens to be the thing I mentioned I would talk about in that previous post. Like my previous guide, I&#8217;ve also written about this topic in the past (Read<a class="more-link" href="https://alexshomenetwork.com/fail2ban-nginx-cloudflare-debian-13/">Continue reading <span class="screen-reader-text">"Using Fail2ban With Nginx and Cloudflare on Debian 13"</span></a></p>
<p>The post <a href="https://alexshomenetwork.com/fail2ban-nginx-cloudflare-debian-13/">Using Fail2ban With Nginx and Cloudflare on Debian 13</a> appeared first on <a href="https://alexshomenetwork.com">Alex&#039;s Home Network</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">As a long-enough overdue update on my previous guide, Installing WordPress on Debian 13 (<a href="https://alexshomenetwork.com/installing-wordpress-on-debian-13/" target="_blank" rel="noreferrer noopener">Link here</a>), it&#8217;s time to focus a bit more on security, which happens to be the thing I mentioned I would talk about in that previous post. Like my previous guide, I&#8217;ve also written about this topic in the past (<a href="https://alexshomenetwork.com/using-cloudflare-and-fail2ban-with-wordpress/">Read here</a> if you&#8217;re curious), but I wanted to write a more up to date and better version of it, especially since nowadays it&#8217;s not very good, at least in my opinion.</p>



<h3 class="wp-block-heading">Fail2ban: A Crude and Dumb Yet Surprisingly Effective IPS</h3>



<p class="wp-block-paragraph">Before implementing Fail2ban, it&#8217;s important to have a basic understanding of how it works, what I&#8217;ll be showing you, and why I&#8217;m showing you certain things. If you already know this stuff, then feel free to skip this section. You can skip to <a href="https://alexshomenetwork.com/fail2ban-nginx-cloudflare-debian-13/#How_Does_Fail2ban_Help">How Does Fail2ban Help</a> or <a href="https://alexshomenetwork.com/fail2ban-nginx-cloudflare-debian-13/#Cutting_To_The_Chase_Installing_Fail2ban">Installing Fail2ban</a> if you don&#8217;t care about the background information.</p>



<h4 class="wp-block-heading">The Problem With Scrapers</h4>



<p class="wp-block-paragraph">If you&#8217;ve spent any time hosting a web server or any other service on the public internet, you&#8217;ve probably noticed stuff like this in your logs:</p>



<pre class="wp-block-code"><code>&lt;Redacted IP&gt; - - &#91;19/Oct/2025:23:18:33 +0000] "GET /ALFA_DATA/alfacgiapi/radio.php?bx=0e215962017 HTTP/1.1" 404 548 "-" "Mozilla/5.0 (Linux; Android 11; Redmi Note 9 Pro Build/RKQ1.200826.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/90.0.4430.210 Mobile Safari/537.36" "&lt;Redacted IP&gt;" "&lt;Redacted IP&gt;"
&lt;Redacted IP&gt; - - &#91;19/Oct/2025:23:18:33 +0000] "GET /ALFA_DATA/alfacgiapi/404.php?bx=0e215962017 HTTP/1.1" 404 548 "-" "Mozilla/5.0 (Linux; Android 11; Redmi Note 9 Pro Build/RKQ1.200826.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/90.0.4430.210 Mobile Safari/537.36" "&lt;Redacted IP&gt;" "&lt;Redacted IP&gt;"
&lt;Redacted IP&gt; - - &#91;19/Oct/2025:23:23:36 +0000] "GET /con.php HTTP/1.1" 404 548 "www.google.com" "Mozlila/5.0 (Linux; Android 7.0; SM-G892A Bulid/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/60.0.3112.107 Moblie Safari/537.36" "&lt;Redacted IP&gt;" "&lt;Redacted IP&gt;"
&lt;Redacted IP&gt; - - &#91;19/Oct/2025:23:23:36 +0000] "GET /con.php HTTP/1.1" 404 548 "www.google.com" "Mozlila/5.0 (Linux; Android 7.0; SM-G892A Bulid/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/60.0.3112.107 Moblie Safari/537.36" "&lt;Redacted IP&gt;" "&lt;Redacted IP&gt;"</code></pre>



<p class="wp-block-paragraph">While there&#8217;s lots of friendly scrapers, which will typically obey <code>robots.txt</code>, there are many more crudely written ones that are simply trying to brute-force a bunch of URL&#8217;s, hoping to find sensitive information or an exploit. These scrapers are ran by an infinite variety of people, ranging from middle schoolers trying to impress their friends after learning about Kali Linux, those trying to mine crypto or build a botnet, or more recently, thanks to the AI boom, AI crawlers DDoS&#8217;ing websites (<a href="https://techcrunch.com/2025/01/10/how-openais-bot-crushed-this-seven-person-companys-web-site-like-a-ddos-attack/" target="_blank" rel="noreferrer noopener">Exhibit A</a>, <a href="https://www.infosecurity-magazine.com/news/gray-bots-generative-ai-scraper/" target="_blank" rel="noreferrer noopener">Exhibit B</a>).</p>



<p class="wp-block-paragraph">Some of these scrapers are smart, some of which I&#8217;ve observed myself, but the vast majority of them are just running through a list of hosts, probably some of which come from places like Shodan to narrow their search, test a bunch of URL&#8217;s, and report back their findings. Hell, I still see several that don&#8217;t even bother changing their user agent from something like <code>python-requests</code>, use an empty user agent, or even whatever tool/script they&#8217;re using.</p>



<h5 class="wp-block-heading">Why Even Care?</h5>



<p class="wp-block-paragraph">Reading through this, you might be tempted to ask yourself &#8220;There&#8217;s nothing of interest on my website. Why even bother?&#8221;, which is a very valid question.</p>



<p class="wp-block-paragraph">The biggest issue with scrapers is that even if they&#8217;re not doing anything malicious, they&#8217;re still wasting resources on your web server. Your web server still has to accept that scraper&#8217;s request, send back a partial or even full response, and log it. Rinse and repeat with several scrapers doing this multiple times a day, it adds up to a lot of wasted resources. It&#8217;s significantly less resource intensive to simply blackhole all traffic from that IP address rather than having your web server respond to it.</p>



<p class="wp-block-paragraph">Another issue is that they might not be doing anything malicious today, but there&#8217;s a chance that they do find something, or a vulnerability comes out for something that you&#8217;re hosting (Log4j, for example). Best case scenario, you&#8217;re getting trolled or mining crypto for someone. Worst case scenario, your server is now being used as a relay to commit federal crimes, you&#8217;re now part of a nation-state operated botnet, and the feds (Along with your hosting provider) are now after you. It&#8217;s probably a good time to mention that you should check your backups.</p>



<p class="wp-block-paragraph">Regardless, the biggest thing is that it helps cut down on resource usage, and it helps mitigate against future vulnerabilities.</p>



<h4 class="wp-block-heading">How Does Fail2ban Help?</h4>



<p class="wp-block-paragraph">The reason why I described Fail2ban the way I did is because its operation is very simple, yet surprisingly effective. All Fail2ban does is look in a log file for failed requests within a certain time period (By default it&#8217;s the past 10 minutes), and if there&#8217;s enough matches, then it&#8217;ll block that IP address. </p>



<p class="wp-block-paragraph">Even though it&#8217;s very simple and arguably kind of crude, it still works surprisingly well. Even with smarter bots that try to mix in legitimate requests, presumably to try and fool proper IPS&#8217;s, Fail2ban still blocks them, since it only cares about failed requests made within a certain time.</p>


<div class="wp-block-image">
<figure class="aligncenter size-full is-resized"><img fetchpriority="high" decoding="async" width="1013" height="767" src="https://alexshomenetwork.com/wp-content/uploads/2025/10/Smart-Bot.png" alt="" class="wp-image-926" style="width:632px;height:auto" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/10/Smart-Bot.png 1013w, https://alexshomenetwork.com/wp-content/uploads/2025/10/Smart-Bot-300x227.png 300w, https://alexshomenetwork.com/wp-content/uploads/2025/10/Smart-Bot-768x581.png 768w" sizes="(max-width: 1013px) 100vw, 1013px" /><figcaption class="wp-element-caption">This particular bot alternated between making legitimate requests and requesting sensitive files.</figcaption></figure>
</div>


<h5 class="wp-block-heading">There Are Still Flaws</h5>



<p class="wp-block-paragraph">Despite the simplicity of Fail2ban bringing some advantages, the simplicity also brings some downsides. For example, since Fail2ban doesn&#8217;t care about any other requests, if legitimate users are causing 4xx errors on your web server, which can simply be caused by static assets getting updated, but old ones are still cached, their IP addresses might still get banned. Fail2ban is more simple to configure than a proper IPS, but it still requires some tuning and false positives. </p>



<p class="wp-block-paragraph">Another issue that Fail2ban has is when using it with Cloudflare, there might be a delay between Fail2ban banning the IP and it being banned in Cloudflare. In my experience, Cloudflare seemed to block IP&#8217;s pretty much instantly, but your mileage may vary. This might be a problem depending on your use case, but as long as you have some sort of rate limiting, and tell Fail2ban to multiply ban times for repeat offenders, then it shouldn&#8217;t be an issue. Plus, most bots are slow by design to evade rate limiting.</p>



<h3 class="wp-block-heading">Cutting To The Chase: Installing Fail2ban</h3>



<p class="wp-block-paragraph">Now that I&#8217;ve gotten the long enough introduction out of the way, let&#8217;s actually start setting up Fail2ban. First, install the <code>fail2ban</code> and <code>iptables-persistent</code> packages:</p>



<pre class="wp-block-code"><code>sudo apt install fail2ban iptables-persistent</code></pre>



<h4 class="wp-block-heading">Basic Configuration</h4>



<p class="wp-block-paragraph">Most of the default options that Fail2ban ships with are fine, but there&#8217;s a few changes you&#8217;ll want to make.</p>



<h5 class="wp-block-heading">Database Purge</h5>



<p class="wp-block-paragraph">The first thing that should be changed is the <code>dbpurgeage</code> setting. By default, it purges the database after just one day, which is pretty much useless for blocking repeat offenders. Even though you can directly modify <code>fail2ban.conf</code>, it can cause some headaches with major distro upgrade (Like upgrading from Debian 12 to 13), so you&#8217;ll want to create your own in <code>fail2ban.d</code>.</p>



<p class="wp-block-paragraph">First, create your custom configuration file, using whatever name you want:</p>



<pre class="wp-block-code"><code>sudo nano /etc/fail2ban/fail2ban.d/<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">fail2ban.conf</mark></code></pre>



<p class="wp-block-paragraph">Next, add the following content, setting <code>dbpurgeage</code> to whatever you see fit:</p>



<pre class="wp-block-code"><code>&#91;DEFAULT]
dbpurgeage = <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">1y</mark></code></pre>



<p class="wp-block-paragraph">You can set it to some absurdly high number like <code>99y</code> to effectively disable it, but IP addresses do change hands (Even if not frequently, especially for more simple bots), and it prevents your database from growing out of control. I personally have it set to one year. You can find all available options in <code>/etc/fail2ban/fail2ban.conf</code>, but make sure to make your changes in your custom configuration file.</p>



<h5 class="wp-block-heading">Nginx 4xx Filter</h5>



<p class="wp-block-paragraph">Even though Fail2ban ships with filters for Nginx, I prefer making my own filters, since for me at least, the ones Fail2ban ship with are not all that intuitive to implement. Plus, most other places I see seem to recommend creating your own filter rather than using the included ones.</p>



<p class="wp-block-paragraph">Create a new file named something like <code>nginx-4xx.conf</code> in <code>filter.d</code>, and add in the following content:</p>



<pre class="wp-block-code"><code>&#91;Definition]
failregex = ^&lt;HOST&gt;.*"(GET|POST).*" (400|401|403|404|444) .*$
            ^&lt;HOST&gt; - \S+ \&#91;\] "&#91;^"]*" 400
# Adjust the line below as needed. You might want to include paths where static assets and dynamic content might be stored to prevent false positives.
ignoreregex = ^&lt;HOST&gt;.*"(GET|POST).*(<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">favicon|apple-touch-icon</mark>).*" (401|403|404|444) .*$</code></pre>



<p class="wp-block-paragraph">Notice the second line in our <code>failregex</code>:</p>



<pre class="wp-block-code"><code>^&lt;HOST&gt; - \S+ \&#91;\] "&#91;^"]*" 400</code></pre>



<p class="wp-block-paragraph">This is taken directly from the included <code>nginx-bad-requests.conf</code> filter. This regex blocks requests that are either empty, or are just encoded garbage like this one:</p>



<pre class="wp-block-code"><code>&lt;Redacted IP&gt; - - &#91;17/Nov/2025:19:04:28 +0000] "\x16\x03\x01\x05\xA8\x01\x00\x05\xA4\x03\x033\x89\x7F\xD58\x0FG\xFD\xCD\xB6b\xFE*c\x97" 400 150 "-" "-"</code></pre>



<p class="wp-block-paragraph">We can add both regex&#8217;s to the same filter, so that way anything that matches one of those regex&#8217;s will be part of the same jail.</p>



<p class="wp-block-paragraph">I highly recommend using the <code>fail2ban-regex</code> command and <a href="https://regex101.com/">regex101.com</a> to fine tune your filter before implementing it:</p>



<pre class="wp-block-code"><code>sudo fail2ban-regex /var/log/nginx/access.log <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">nginx-4xx</mark></code></pre>



<h5 class="wp-block-heading">Jail Configuration</h5>



<p class="wp-block-paragraph">Like with <code>fail2ban.conf</code>, most of the defaults Fail2ban ships with in <code>jail.conf</code> are fine, but there are a few things that you should change.</p>



<p class="wp-block-paragraph">First, create a new configuration file in <code>jail.d</code> called <code>wordpress.conf</code> (Or a different name if you desire). This is also where our jails for Nginx will live:</p>



<pre class="wp-block-code"><code>&#91;DEFAULT]
# Somewhat randomizes ban times, so just put a random number here.
bantime.rndtime = 86400
# If you don't have a machine with a different public IP address to test, leave ignoreip blank. Set this to your own IP once you're done testing.
ignoreip = <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">5355:4253:4352::4942:4534:4d4f:5245/64 1.2.3.4</mark>
# How long to ban for the first time.
bantime = 5m
# How far back to look in the logs.
findtime = 10m
# How many failures until the IP is banned.
maxretry = 5</code></pre>



<p class="wp-block-paragraph">The settings for <code>bantime</code>, <code>findtime</code>, and <code>maxretry</code> are fairly conservative, but you&#8217;ll want to fine tune as needed. I set <code>maxretry</code> to <code>5</code> because I noticed that most bots seem to make at least around 5 requests, but it&#8217;s not so low that it could ban legitimate visitors. When testing, I recommend starting with more conservative settings, or at least not setting any actions when banning the IP.</p>



<p class="wp-block-paragraph">Under the settings for your jail, add in the <code>nginx-4xx</code> jail:</p>



<pre class="wp-block-code"><code>&#91;nginx-4xx]
enabled = true
port    = http,https
logpath = /var/log/nginx/access.log
# Keep this line commented out for testing, or at least make sure you can directly access your servers console in case you lock yourself out.
#action = <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">iptables-allports</mark></code></pre>



<p class="wp-block-paragraph">Finally, restart the Fail2ban service, and check the status of the jail with the following command:</p>



<pre class="wp-block-code"><code>sudo fail2ban-client status nginx-4xx</code></pre>



<p class="wp-block-paragraph">To test if it works, you can either just run <code>watch</code> with <code>fail2ban-client</code>, and start typing in invalid URL&#8217;s until you see your IP banned:</p>



<pre class="wp-block-code"><code>sudo watch -n 1 fail2ban-client status nginx-4xx</code></pre>



<p class="wp-block-paragraph">Or you can run something like <code>nikto</code>, which will also test the second regex:</p>



<pre class="wp-block-code"><code>nikto -h <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">https://your-domain-or-ip</mark></code></pre>



<p class="wp-block-paragraph">Just make sure to disable any rate limiting before running <code>nikto</code>, otherwise you&#8217;ll be blocked by it pretty much instantly, which will interfere with your test. </p>



<p class="wp-block-paragraph">After running your test, you should see your IP in the banned IP list:</p>



<pre class="wp-block-code"><code>Status for the jail: nginx-4xx
|- Filter
|  |- Currently failed: 1
|  |- Total failed:     16
|  `- File list:        /var/log/nginx/access.log
`- Actions
   |- Currently banned: 1
   |- Total banned:     1
   `- Banned IP list:   <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">1.2.3.4</mark></code></pre>



<p class="wp-block-paragraph">You can also use the <code>fail2ban-regex</code> command with the <code>--print-all-matched</code> flag to see what was matched:</p>



<pre class="wp-block-code"><code>sudo fail2ban-regex /var/log/nginx/access.log nginx-4xx --print-all-matched</code></pre>



<h6 class="wp-block-heading">A Warning Before Continuing</h6>



<p class="wp-block-paragraph">Before you move on to the next step, and I can&#8217;t emphasize this enough, make ABSOLUTELY sure you either have a machine with a different IP address to test with, or have some sort of out-of-band access to your server (Most hosting providers let you access the console to your server). Otherwise, you will end up locking yourself out (Don&#8217;t ask me how I know). You should test it before enabling any actions as well, since you don&#8217;t want to ban your own IP, only to find out you&#8217;re locked out of your server and have to wait out the ban.</p>



<h5 class="wp-block-heading">Enabling and Testing</h5>



<p class="wp-block-paragraph">Now that we&#8217;ve verified that the filter actually works, it&#8217;s time to test and see if you can actually ban IP&#8217;s. Open up <code>/etc/fail2ban/jail.d/wordpress.conf</code>, and uncomment the following line:</p>



<pre class="wp-block-code"><code>action = <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">iptables-allports</mark></code></pre>



<p class="wp-block-paragraph">Next, restart Fail2ban, and test again (I like using <code>nikto</code>):</p>



<pre class="wp-block-code"><code>nikto -h <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">https://your-domain-or-ip</mark></code></pre>



<p class="wp-block-paragraph">After running your test, not only should you see your IP address listed in <code>sudo fail2ban-client status nginx-4xx</code>, but your browser should timeout when trying to access your server:</p>


<div class="wp-block-image">
<figure class="aligncenter size-large is-resized"><img decoding="async" width="1024" height="390" src="https://alexshomenetwork.com/wp-content/uploads/2025/12/Browser-Timeout-1024x390.png" alt="" class="wp-image-941" style="width:578px;height:auto" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/12/Browser-Timeout-1024x390.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2025/12/Browser-Timeout-300x114.png 300w, https://alexshomenetwork.com/wp-content/uploads/2025/12/Browser-Timeout-768x293.png 768w, https://alexshomenetwork.com/wp-content/uploads/2025/12/Browser-Timeout.png 1512w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>
</div>


<p class="wp-block-paragraph">As a pro tip, you can also see how long it will be until an IP address is unbanned by using <code>sudo fail2ban-client get nginx-4xx banip --with-time</code>:</p>



<pre class="wp-block-code"><code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">1.2.3.4</mark> 2025-12-02 15:13:09 + 301 = 2025-12-02 15:18:10</code></pre>



<p class="wp-block-paragraph">You can either wait out the ban if it&#8217;s short enough (Or you found out the hard way that you locked yourself out of your own server), or unban your IP manually:</p>



<pre class="wp-block-code"><code>sudo fail2ban-client unban <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">1.2.3.4</mark></code></pre>



<h3 class="wp-block-heading">Configuring Cloudflare</h3>



<p class="wp-block-paragraph">For those that aren&#8217;t using Cloudflare, you&#8217;re free to stop right here. But if you do happen to be using Cloudflare, the setup is a little bit more involved. This is because Cloudflare acts as a proxy, which has the side effect of hiding the IP address of your visitors, preventing stuff like <code>iptables</code> from working correctly.</p>



<h4 class="wp-block-heading">Logging Actual IPs</h4>



<p class="wp-block-paragraph">When looking in <code>/var/log/nginx/access.log</code>, you may or may not see Cloudflare&#8217;s IP addresses rather than your visitors IP addresses. Even if you do happen to see visitors actual IP addresses, and verified that Cloudflare actually is proxying your traffic (Which I&#8217;ve personally noticed in some cases), I still recommend performing this step as a precaution.</p>



<p class="wp-block-paragraph">In case anything goes wrong, I recommend first creating a backup of your <code>nginx.conf</code>:</p>



<pre class="wp-block-code"><code>sudo cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak</code></pre>



<p class="wp-block-paragraph">First, open up <code>/etc/nginx/nginx.conf</code> in a text editor, and add the following content in <code>http</code> under where the <code>include</code> lines are:</p>



<pre class="wp-block-code"><code>http {
	...
	# Lines shown for reference, don't add these or anything above
	include /etc/nginx/conf.d/*.conf;
	include /etc/nginx/sites-enabled/*;

	# This is the stuff you add
	# Creates another log file identical to the default one, just with the visitor's actual IP address
	log_format  wordpress  '$remote_addr - $remote_user &#91;$time_local] "$request" '
                '$status $body_bytes_sent "$http_referer" '
                '"$http_user_agent" "$http_x_forwarded_for" "$http_cf_connecting_ip"';

	access_log /var/log/nginx/wordpress.log wordpress;

	# Sets the real IP header coming from Cloudflare's IP address ranges. Make sure these are up to date
	set_real_ip_from 173.245.48.0/20;
        set_real_ip_from 103.21.244.0/22;
        set_real_ip_from 103.22.200.0/22;
        set_real_ip_from 103.31.4.0/22;
        set_real_ip_from 141.101.64.0/18;
        set_real_ip_from 108.162.192.0/18;
        set_real_ip_from 190.93.240.0/20;
        set_real_ip_from 188.114.96.0/20;
        set_real_ip_from 197.234.240.0/22;
        set_real_ip_from 198.41.128.0/17;
        set_real_ip_from 162.158.0.0/15;
        set_real_ip_from 104.16.0.0/13;
        set_real_ip_from 104.24.0.0/14;
        set_real_ip_from 172.64.0.0/13;
        set_real_ip_from 131.0.72.0/22;
        set_real_ip_from 2400:cb00::/32;
        set_real_ip_from 2606:4700::/32;
        set_real_ip_from 2803:f800::/32;
        set_real_ip_from 2405:b500::/32;
        set_real_ip_from 2405:8100::/32;
        set_real_ip_from 2a06:98c0::/29;
        set_real_ip_from 2c0f:f248::/32;
	real_ip_header X-Forwarded-For;

# Make sure you add everything above this bracket
}</code></pre>



<p class="wp-block-paragraph">Even though they rarely change, depending on when you view this post, the IP ranges shown might be outdated. You can find Cloudflare&#8217;s latest list of IP ranges <a href="https://www.cloudflare.com/ips/" target="_blank" rel="noreferrer noopener">here</a>.</p>



<p class="wp-block-paragraph">Run <code>sudo nginx -t</code> to test the configuration, and if it&#8217;s successful, restart Nginx. If there&#8217;s any issues, make sure that your indentation is right and that you added everything in the right place. You can also revert back to the old configuration by running <code>sudo cp /etc/nginx/nginx.conf.bak /etc/nginx/nginx.conf</code>.</p>



<h6 class="wp-block-heading">Pro Tip</h6>



<p class="wp-block-paragraph">So that way attackers can&#8217;t bypass Cloudflare and access your server directly, I recommend configuring your server&#8217;s firewall to only allow Cloudflare&#8217;s and your own IP addresses. That way, even if attackers did find out your IP, they won&#8217;t be able to do much with it.</p>



<h4 class="wp-block-heading">Banning IPs</h4>



<p class="wp-block-paragraph">Now that we&#8217;ve gotten the logging situation under control, it&#8217;s time to figure out how to actually ban IP&#8217;s. Even though nginx can see your visitors IP addresses, <code>iptables</code> and whatnot can&#8217;t, so we&#8217;ll need to ban them from Cloudflare. Plus, it takes that load off your server.</p>



<h5 class="wp-block-heading">Getting an API Key</h5>



<p class="wp-block-paragraph">To allow Fail2ban to talk to Cloudflare, you&#8217;ll need to get an API token. First, navigate to the API Tokens section on your Cloudflare profile (<a href="https://dash.cloudflare.com/profile/api-tokens" target="_blank" rel="noreferrer noopener">Link here</a>), and click the blue Create Token button:</p>


<div class="wp-block-image">
<figure class="aligncenter size-large is-resized"><img decoding="async" width="1024" height="274" src="https://alexshomenetwork.com/wp-content/uploads/2025/12/Create-Cloudflare-Token-1024x274.png" alt="" class="wp-image-946" style="aspect-ratio:3.737123819905099;width:660px;height:auto" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/12/Create-Cloudflare-Token-1024x274.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2025/12/Create-Cloudflare-Token-300x80.png 300w, https://alexshomenetwork.com/wp-content/uploads/2025/12/Create-Cloudflare-Token-768x206.png 768w, https://alexshomenetwork.com/wp-content/uploads/2025/12/Create-Cloudflare-Token-1536x411.png 1536w, https://alexshomenetwork.com/wp-content/uploads/2025/12/Create-Cloudflare-Token-2048x548.png 2048w, https://alexshomenetwork.com/wp-content/uploads/2025/12/Create-Cloudflare-Token-1568x420.png 1568w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>
</div>


<p class="wp-block-paragraph">Next, scroll to the bottom, then click the blue Get Started button next to Create Custom Token:</p>


<div class="wp-block-image">
<figure class="aligncenter size-large is-resized"><img loading="lazy" decoding="async" width="1024" height="188" src="https://alexshomenetwork.com/wp-content/uploads/2025/12/Cloudflare-Token-Custom-1024x188.png" alt="" class="wp-image-957" style="aspect-ratio:5.446310687378076;width:651px;height:auto" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/12/Cloudflare-Token-Custom-1024x188.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2025/12/Cloudflare-Token-Custom-300x55.png 300w, https://alexshomenetwork.com/wp-content/uploads/2025/12/Cloudflare-Token-Custom-768x141.png 768w, https://alexshomenetwork.com/wp-content/uploads/2025/12/Cloudflare-Token-Custom.png 1402w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
</div>


<p class="wp-block-paragraph">Under Permissions, you&#8217;ll want to configure them as shown in the screenshot, and set Zone Resources to only include your domain. I recommend restricting the IP addresses that can use it to your server&#8217;s IP address and your own public IP:</p>


<div class="wp-block-image">
<figure class="aligncenter size-large is-resized"><img loading="lazy" decoding="async" width="1024" height="807" src="https://alexshomenetwork.com/wp-content/uploads/2025/12/Custom-Token-Permissions-1024x807.png" alt="" class="wp-image-961" style="width:648px;height:auto" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/12/Custom-Token-Permissions-1024x807.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2025/12/Custom-Token-Permissions-300x237.png 300w, https://alexshomenetwork.com/wp-content/uploads/2025/12/Custom-Token-Permissions-768x606.png 768w, https://alexshomenetwork.com/wp-content/uploads/2025/12/Custom-Token-Permissions-1536x1211.png 1536w, https://alexshomenetwork.com/wp-content/uploads/2025/12/Custom-Token-Permissions-1568x1236.png 1568w, https://alexshomenetwork.com/wp-content/uploads/2025/12/Custom-Token-Permissions.png 1778w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
</div>


<p class="wp-block-paragraph">Even though you technically can add multiple domains under Zone Resources, I recommend just creating an API token for each domain. This helps improve security (Or at least make you feel better), and provides a little bit more control.</p>



<p class="wp-block-paragraph">After choosing your permissions, scroll to the bottom and click Continue to Summary, then Create Token. Your token will be displayed. I recommend keeping it somewhere safe for reference:</p>


<div class="wp-block-image">
<figure class="aligncenter size-large is-resized"><img loading="lazy" decoding="async" width="1024" height="629" src="https://alexshomenetwork.com/wp-content/uploads/2025/12/Cloudflare-Token-Creation-Confirmation-1024x629.png" alt="" class="wp-image-954" style="aspect-ratio:1.6279959578832583;width:662px;height:auto" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/12/Cloudflare-Token-Creation-Confirmation-1024x629.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2025/12/Cloudflare-Token-Creation-Confirmation-300x184.png 300w, https://alexshomenetwork.com/wp-content/uploads/2025/12/Cloudflare-Token-Creation-Confirmation-768x471.png 768w, https://alexshomenetwork.com/wp-content/uploads/2025/12/Cloudflare-Token-Creation-Confirmation-1536x943.png 1536w, https://alexshomenetwork.com/wp-content/uploads/2025/12/Cloudflare-Token-Creation-Confirmation-1568x963.png 1568w, https://alexshomenetwork.com/wp-content/uploads/2025/12/Cloudflare-Token-Creation-Confirmation.png 1704w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
</div>


<p class="wp-block-paragraph">I also recommend using the provided <code>curl</code> command, ideally from your server, to test and see if the token works correctly.</p>



<p class="wp-block-paragraph">The last step is to get the Zone ID of your domain to feed to Fail2ban. It&#8217;s as easy as running the following command, substituting in your own API token:</p>



<pre class="wp-block-code"><code>curl https://api.cloudflare.com/client/v4/zones -H "Authorization: Bearer <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">46616b65436c6f7564666c617265415049546f6b656e</mark>"</code></pre>



<p class="wp-block-paragraph">Assuming that you&#8217;ve restricted it to a single zone, the output will only show the information for that zone. The Zone ID will be right at the top:</p>



<pre class="wp-block-code"><code>{"result":&#91;{"id":"<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">4e6f476f7653656372657473546f4265466f756e64</mark>","name":"<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">alexshomenetwork.com</mark>","status":"active","paused":false,"type":"full","development_mode":-12441583,
...
# You'll see a bunch of stuff, but id and name are the only things you'll need</code></pre>



<h5 class="wp-block-heading">Configuring Fail2ban</h5>



<p class="wp-block-paragraph">Now that you&#8217;re armed with the necessary information from Cloudflare, it&#8217;s time to configure Fail2ban. First, open <code>/etc/fail2ban/action.d/cloudflare-token.conf</code> in a text editor, navigate to the following lines, uncomment <code>cfzone</code> and <code>cftoken</code>, and add in your Cloudflare Zone ID and API Token:</p>



<pre class="wp-block-code"><code># The Cloudflare &lt;ZONE_ID&gt; of the domain you want to manage
#
cfzone = <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">4e6f476f7653656372657473546f4265466f756e64</mark>

# Your personal Cloudflare token.  Ideally restricted to just have "Zone.Firewall Services" permissions
#
cftoken = <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">46616b65436c6f7564666c617265415049546f6b656e</mark>
# There are several other options you can configure. For example, you can change cfmode from block to js_challenge to show a challenge rather than outright blocking an IP</code></pre>



<p class="wp-block-paragraph">Save and exit the file. Since this file contains your Cloudflare API token, and it&#8217;s world-readable by default, you&#8217;ll want to change the permissions to more restrictive ones:</p>



<pre class="wp-block-code"><code>sudo chmod 640 /etc/fail2ban/action.d/cloudflare-token.conf</code></pre>



<p class="wp-block-paragraph">Next, open <code>/etc/fail2ban/jail.d/wordpress.conf</code>, change <code>logpath</code> to <code>/var/log/nginx/wordpress.log</code>, and add <code>cloudflare-token</code> under <code>action</code>:</p>



<pre class="wp-block-code"><code>&#91;nginx-4xx]
enabled = true
port    = http,https
logpath = /var/log/nginx/<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">wordpress</mark>.log
action = iptables-allports
        <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">cloudflare-token</mark></code></pre>



<p class="wp-block-paragraph">After saving and exiting, restart the Fail2ban service.</p>



<h4 class="wp-block-heading">Testing (Again)</h4>



<p class="wp-block-paragraph">These changes won&#8217;t do us any good if we don&#8217;t know that they work, so we&#8217;ll need to run a quick test.</p>



<p class="wp-block-paragraph">First, navigate to your Cloudflare dashboard, click on your domain, navigate to Security Rules under Security, then scroll to the bottom. The IP access rules will appear under Managed Rules:</p>


<div class="wp-block-image">
<figure class="aligncenter size-large is-resized"><img loading="lazy" decoding="async" width="1024" height="653" src="https://alexshomenetwork.com/wp-content/uploads/2025/12/Cloudflare-Security-Rules-1024x653.png" alt="" class="wp-image-959" style="aspect-ratio:1.5681544221376258;width:534px;height:auto" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/12/Cloudflare-Security-Rules-1024x653.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2025/12/Cloudflare-Security-Rules-300x191.png 300w, https://alexshomenetwork.com/wp-content/uploads/2025/12/Cloudflare-Security-Rules-768x490.png 768w, https://alexshomenetwork.com/wp-content/uploads/2025/12/Cloudflare-Security-Rules.png 1120w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
</div>


<p class="wp-block-paragraph">Next, on your server&#8217;s console, run <code>sudo watch -n 1 fail2ban-client status nginx-4xx</code> to see in real time if your IP address was banned, since it might be slow to show up on Cloudflare. </p>



<p class="wp-block-paragraph">I&#8217;m sure you already know this by now, but as another warning, make sure you don&#8217;t lock yourself out of your own server.</p>



<p class="wp-block-paragraph">Finally, run the same tests that you did earlier, either using <code>nikto</code>, or doing it the manual way. After your IP address appears in the banned IP list, refresh the Cloudflare security rules page, and you should see your IP address listed under IP access rules:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="199" src="https://alexshomenetwork.com/wp-content/uploads/2025/12/Cloudflare-Banned-IP-1024x199.png" alt="" class="wp-image-966" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/12/Cloudflare-Banned-IP-1024x199.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2025/12/Cloudflare-Banned-IP-300x58.png 300w, https://alexshomenetwork.com/wp-content/uploads/2025/12/Cloudflare-Banned-IP-768x150.png 768w, https://alexshomenetwork.com/wp-content/uploads/2025/12/Cloudflare-Banned-IP-1536x299.png 1536w, https://alexshomenetwork.com/wp-content/uploads/2025/12/Cloudflare-Banned-IP-2048x399.png 2048w, https://alexshomenetwork.com/wp-content/uploads/2025/12/Cloudflare-Banned-IP-1568x305.png 1568w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">When you try accessing your website, you should see a page that looks something like this:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="702" src="https://alexshomenetwork.com/wp-content/uploads/2025/12/Cloudflare-Block-Page-1024x702.png" alt="" class="wp-image-964" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/12/Cloudflare-Block-Page-1024x702.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2025/12/Cloudflare-Block-Page-300x206.png 300w, https://alexshomenetwork.com/wp-content/uploads/2025/12/Cloudflare-Block-Page-768x526.png 768w, https://alexshomenetwork.com/wp-content/uploads/2025/12/Cloudflare-Block-Page-1536x1053.png 1536w, https://alexshomenetwork.com/wp-content/uploads/2025/12/Cloudflare-Block-Page-2048x1404.png 2048w, https://alexshomenetwork.com/wp-content/uploads/2025/12/Cloudflare-Block-Page-1568x1075.png 1568w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">If you&#8217;re not blocked, make sure that the correct IP address was blocked. Even though for me it blocked the IP instantly, you might need to wait a minute.</p>



<p class="wp-block-paragraph">To make sure that Fail2ban can unban an IP, which shouldn&#8217;t be an issue since you&#8217;ve already banned one, run the following command:</p>



<pre class="wp-block-code"><code>sudo fail2ban-client unban <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">&lt;your IP&gt;</mark></code></pre>



<p class="wp-block-paragraph">Refresh the page, and the IP access rule should be gone.</p>



<h5 class="wp-block-heading">Troubleshooting</h5>



<p class="wp-block-paragraph">If Fail2ban is able to ban your IP address, it&#8217;s showing up in the banned IP list, but Cloudflare isn&#8217;t blocking you, there&#8217;s a few things that you should check.</p>



<p class="wp-block-paragraph">The first thing you should do is check and see if the IP address is banned in Cloudflare. If it&#8217;s showing up, make sure that the IP address that was banned is the same one that you&#8217;re testing from. Make sure that it isn&#8217;t a private IP address. I mention this because it&#8217;s something that&#8217;s very simple but also very easy to forget.</p>



<p class="wp-block-paragraph">If you don&#8217;t see an IP access rule, then it might be a permissions issue on your API token. To verify this, open <code>/etc/fail2ban/fail2ban.d/fail2ban.conf</code>, and add the following line:</p>



<pre class="wp-block-code"><code>loglevel = DEBUG</code></pre>



<p class="wp-block-paragraph">You&#8217;ll want to remove this once you&#8217;re done, since this will flood your log files.</p>



<p class="wp-block-paragraph">After restarting the Fail2ban service, open a separate terminal, and follow <code>/var/log/fail2ban.log</code>:</p>



<pre class="wp-block-code"><code>sudo tail -f /var/log/fail2ban.log</code></pre>



<p class="wp-block-paragraph">If you see something like this when banning an IP in your logs:</p>



<pre class="wp-block-code"><code>'{"success":false,"errors":&#91;{"code":10000,"message":"Authentication error"}]}'</code></pre>



<p class="wp-block-paragraph">This indicates a permission issue with your Cloudflare API token. Unfortunately, this error doesn&#8217;t give much information, nor do the audit logs in your account. You can run the same <code>curl</code> command that Fail2ban does to see if you get the same error (Substituting in your own information):</p>



<pre class="wp-block-code"><code>curl -s -X POST "https://api.cloudflare.com/client/v4/zones/<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">4e6f476f7653656372657473546f4265466f756e64</mark>/firewall/access_rules/rules" -H "Authorization: Bearer <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">46616b65436c6f7564666c617265415049546f6b656e</mark>" -H "Content-Type: application/json" --data '{"mode":"block","configuration":{"target":"ip","value":"<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">1.2.3.4</mark>"},"notes":"Fail2Ban nginx-4xx"}'</code></pre>



<p class="wp-block-paragraph">If the command works, verify that the information in <code>/etc/fail2ban/action.d/cloudflare-token.conf</code> is correct. If the command gives the same error, check and see if your API token has Read access for Zone, and Edit access for Zone Settings and Firewall Services. You can also remove the IP addresses under Client IP Address Filtering and set Zone Resources to include all zones for testing. </p>



<p class="wp-block-paragraph">Using the same command that I showed earlier, verify that you have the correct zone ID:</p>



<pre class="wp-block-code"><code>curl https://api.cloudflare.com/client/v4/zones -H "Authorization: Bearer <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">46616b65436c6f7564666c617265415049546f6b656e</mark>"</code></pre>



<p class="wp-block-paragraph">If all else fails, or you&#8217;re not positive that the API key is correct (And you didn&#8217;t save it anywhere), you can generate a new one with the same permissions by using the Roll function:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="204" src="https://alexshomenetwork.com/wp-content/uploads/2025/12/Cloudflare-Token-Roll-1024x204.png" alt="" class="wp-image-965" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/12/Cloudflare-Token-Roll-1024x204.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2025/12/Cloudflare-Token-Roll-300x60.png 300w, https://alexshomenetwork.com/wp-content/uploads/2025/12/Cloudflare-Token-Roll-768x153.png 768w, https://alexshomenetwork.com/wp-content/uploads/2025/12/Cloudflare-Token-Roll-1536x306.png 1536w, https://alexshomenetwork.com/wp-content/uploads/2025/12/Cloudflare-Token-Roll-1568x312.png 1568w, https://alexshomenetwork.com/wp-content/uploads/2025/12/Cloudflare-Token-Roll.png 2010w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<h3 class="wp-block-heading">Conclusion</h3>



<p class="wp-block-paragraph">So that&#8217;s how you use Fail2ban with Cloudflare and Nginx to ban potentially malicious visitors from your website. Despite it being very simple and arguably kind of hacky, it&#8217;s still a surprisingly effective security measure, especially against more simple bots, which you&#8217;re most likely going to encounter. </p>



<p class="wp-block-paragraph">If you have any comments, suggestions, questions, complaints, or anything else to say, feel free to leave them in the comments, and I&#8217;ll try my best to address them.</p>



<h4 class="wp-block-heading">Why Wait so Long to Publish?</h4>



<p class="wp-block-paragraph">Some of you might have noticed that the timestamps shown in my examples at the beginning are from October, then further down one shown in November, and the date that this blog post was published is in December. </p>



<p class="wp-block-paragraph">If you&#8217;re wondering why it took so long to publish this post, especially because I promised I would make it &#8220;soon&#8221; in my <a href="https://alexshomenetwork.com/installing-wordpress-on-debian-13/">previous post</a>, this is simply because of several personal issues cropping up, eating away at the time I had to work on this post. Since my two options were either to wait, or rush out something half-baked, I decided to wait and polish it up.</p>
<p>The post <a href="https://alexshomenetwork.com/fail2ban-nginx-cloudflare-debian-13/">Using Fail2ban With Nginx and Cloudflare on Debian 13</a> appeared first on <a href="https://alexshomenetwork.com">Alex&#039;s Home Network</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://alexshomenetwork.com/fail2ban-nginx-cloudflare-debian-13/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Installing WordPress on Debian 13</title>
		<link>https://alexshomenetwork.com/installing-wordpress-on-debian-13/</link>
					<comments>https://alexshomenetwork.com/installing-wordpress-on-debian-13/#comments</comments>
		
		<dc:creator><![CDATA[Alex]]></dc:creator>
		<pubDate>Wed, 10 Sep 2025 18:34:55 +0000</pubDate>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Self-Hosting]]></category>
		<category><![CDATA[WordPress]]></category>
		<guid isPermaLink="false">https://alexshomenetwork.com/?p=847</guid>

					<description><![CDATA[<p>Today I will be showing you how to install WordPress on Debian 13, using Nginx, MariaDB, and PHP 8.4. Even though I&#8217;m using Debian, these steps should apply to other distros like Ubuntu. I will also be showing how to install phpMyAdmin for database management, how to implement some basic security measures, and some basic<a class="more-link" href="https://alexshomenetwork.com/installing-wordpress-on-debian-13/">Continue reading <span class="screen-reader-text">"Installing WordPress on Debian 13"</span></a></p>
<p>The post <a href="https://alexshomenetwork.com/installing-wordpress-on-debian-13/">Installing WordPress on Debian 13</a> appeared first on <a href="https://alexshomenetwork.com">Alex&#039;s Home Network</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Today I will be showing you how to install WordPress on Debian 13, using Nginx, MariaDB, and PHP 8.4. Even though I&#8217;m using Debian, these steps should apply to other distros like Ubuntu. I will also be showing how to install phpMyAdmin for database management, how to implement some basic security measures, and some basic PHP optimization.</p>



<h3 class="wp-block-heading">The Purpose of This Post (Not Important)</h3>



<p class="wp-block-paragraph">When I make a post on here, I like focusing on more niche and interesting stuff, or at least guides that are difficult to find elsewhere. You might be asking yourself &#8220;If you like focusing on more niche stuff, then why are you writing yet another WordPress installation tutorial?&#8221; The answer boils down to these two reasons:</p>



<ol class="wp-block-list">
<li>In 2022, I wrote a series of guides about installing WordPress on Debian 11 (<a href="https://alexshomenetwork.com/installing-nginx-mariadb-and-php74-on-debian/">Part 1</a>, <a href="https://alexshomenetwork.com/installing-wordpress-on-lemp-stack/">Part 2</a>, <a href="https://alexshomenetwork.com/my-top-picks-for-wordpress-plugins/">Part 3</a>, and <a href="https://alexshomenetwork.com/using-cloudflare-and-fail2ban-with-wordpress/">Part 4</a>). However, they were my first ever blog posts, and looking back at them now that I&#8217;m much more experienced, I&#8217;m not happy about them, so I&#8217;ve been wanting to make an updated version of them.</li>



<li>I plan on using this guide as a reference for future and much more interesting posts, and I don&#8217;t want to direct people to my old, outdated, and not very good posts.</li>
</ol>



<p class="wp-block-paragraph">Now that we&#8217;ve got the &#8220;Why?&#8221; out of the way, let&#8217;s move on to actually installing WordPress.</p>



<h3 class="wp-block-heading">Prerequisites</h3>



<p class="wp-block-paragraph">Before you can install WordPress, it&#8217;s important to get a few things out of the way:</p>



<ul class="wp-block-list">
<li>Make sure that your Debian install (Or Ubuntu, or similar) is up to date.</li>



<li>This guide is written with the assumption that you&#8217;re running a bare-bones Debian 13 install with nothing else running on it, so if you&#8217;re running other services, the configuration you&#8217;ll need might be different.</li>



<li>Since this is a very easy thing to overlook, make sure that whatever ports you&#8217;ll need are open on your system and on any firewalls in between (80 and 443 for WordPress, 8080 for phpMyAdmin, change as needed), otherwise you&#8217;ll spend way too much time troubleshooting. </li>



<li>If you use Ubuntu, you can check if UFW, the default firewall, is enabled by running <code>sudo ufw status</code>. Debian doesn&#8217;t seem to have a firewall installed. You can allow a port by running <code>sudo ufw allow 80</code>, for example.</li>
</ul>



<h3 class="wp-block-heading">Installing Nginx</h3>



<p class="wp-block-paragraph">No good website is complete without a web server, so all you need to do to install Nginx is run the following command:</p>



<pre class="wp-block-code"><code>sudo apt install nginx</code></pre>



<p class="wp-block-paragraph">Next, enable Nginx to run at startup:</p>



<pre class="wp-block-code"><code>sudo systemctl enable --now nginx</code></pre>



<p class="wp-block-paragraph">The command should complete successfully. Type the IP address or domain of your server into your web browser, and you should see the default welcome page:</p>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img decoding="async" src="https://alexshomenetwork.com/wp-content/uploads/2025/09/Nginx-Welcome.png" alt="" class="wp-image-864"/></figure>
</div>


<p class="wp-block-paragraph">If you don&#8217;t, check to see if Nginx is running correctly:</p>



<pre class="wp-block-code"><code>sudo systemctl status nginx</code></pre>



<p class="wp-block-paragraph">You should also check the log files in <code>/var/log/nginx</code> for additional information.</p>



<p class="wp-block-paragraph">And of course, check that any firewall running on your server or any firewall between your client and server is not blocking anything. You can run <code>curl http://127.0.0.1</code> and <code>curl http://ip-or-domain</code> on your server to see if it&#8217;s a server or network issue.</p>



<h4 class="wp-block-heading">Nginx Configuration</h4>



<p class="wp-block-paragraph">Now that you&#8217;ve verified that Nginx is working, remove the default virtual host to prevent any conflicts:</p>



<pre class="wp-block-code"><code>sudo rm /etc/nginx/sites-enabled/default</code></pre>



<p class="wp-block-paragraph">I recommend just deleting the symlink in <code>/etc/nginx/sites-enabled</code> rather than also deleting the default virtual host in <code>/etc/nginx/sites-available</code>, just to keep it as a reference and for troubleshooting.</p>



<p class="wp-block-paragraph">Next, create a new virtual host file:</p>



<pre class="wp-block-code"><code>sudo nano /etc/nginx/sites-available/wordpress</code></pre>



<p class="wp-block-paragraph">And paste the following content, adjusting as needed:</p>



<pre class="wp-block-code"><code>server {
	listen 80 default_server;
	listen &#91;::]:80 default_server;

	root /var/www/html/wordpress;

	index index.php index.html index.htm index.nginx-debian.html;

        # We will come back to this later when we configure Certbot for HTTPS, but for now, a catch-all is fine
	<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">server_name _;</mark>

        # Change this to a more rational value if you want an actual limit
	<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">client_max_body_size 999G;</mark>

	location / {
		try_files $uri $uri/ /index.php?$args;
	}

	# pass PHP scripts to FastCGI server
	#
	location ~ \.php$ {
		include snippets/fastcgi-php.conf;
		fastcgi_intercept_errors on;
		fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
		include fastcgi_params;
		fastcgi_pass unix:/run/php/php-fpm.sock;
		add_header X-Content-Type-Options nosniff;
		add_header X-XSS-Protection "1; mode=block";
		add_header X-Permitted-Cross-Domain-Policies none;
		add_header X-Frame-Options "SAMEORIGIN";
	}

	# YoastSEO sitemap support, it's best to remove if you don't have YoastSEO installed to prevent any conflicts

	<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">location ~ (&#91;^/]*)sitemap(.*).x(m|s)l$ {
		rewrite ^/sitemap.xml$ /sitemap_index.xml permanent;
		rewrite ^/(&#91;a-z]+)?-?sitemap.xsl$ /index.php?yoast-sitemap-xsl=$1 last;
		rewrite ^/sitemap_index.xml$ /index.php?sitemap=1 last;
		rewrite ^/(&#91;^/]+?)-sitemap(&#91;0-9]+)?.xml$ /index.php?sitemap=$1&amp;sitemap_n=$2 last;
	}</mark>

	# Don't log access to favicon.ico and robots.txt
	location = /favicon.ico {
		log_not_found off;
		access_log off;
	}

	location = /robots.txt {
		allow all;
		log_not_found off;
		access_log off;
	}
	
	# Deny access to hidden files
	location ~ /\.ht {
		deny all;
	}
	
	# Prevent PHP from running from upload directories
	location ~* /(?:uploads|files)/.*\.php$ {
		deny all;
	}

	# Caching and gzip configuration, change as you see fit
	location ~* \.(jpg|jpeg|gif|png|webp|svg|woff|woff2|ttf|css|js|ico|xml)$ {
		expires 30d;
		log_not_found off;
	}

        # Most stuff should already be covered under gzip_types, but you can add or remove as needed
	gzip on;
	gzip_vary on;
	gzip_min_length 1000;
	gzip_types
		text/plain
		text/css
		text/javascript
		application/javascript
		application/x-javascript
		application/json
		application/xml
		application/rss+xml
		application/atom+xml
		application/xhtml+xml
		image/svg+xml
		image/x-icon
		font/ttf
		font/otf
		font/woff
		font/woff2
		application/vnd.ms-fontobject;
	gzip_proxied any;

}</code></pre>



<p class="wp-block-paragraph">This is an Nginx config that I have somewhat written myself, using the default config as a base, enabling PHP and caching support, and adding a few bits for WordPress.</p>



<p class="wp-block-paragraph">After you&#8217;ve saved the file, symlink it to <code>/etc/nginx/sites-enabled/wordpress</code>:</p>



<pre class="wp-block-code"><code>sudo ln -s /etc/nginx/sites-available/wordpress /etc/nginx/sites-enabled/wordpress</code></pre>



<p class="wp-block-paragraph">Next, check to see if there&#8217;s any errors:</p>



<pre class="wp-block-code"><code>sudo nginx -t</code></pre>



<p class="wp-block-paragraph">If there aren&#8217;t, then you should see the following output:</p>



<pre class="wp-block-code"><code>nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful</code></pre>



<p class="wp-block-paragraph">Finally, restart Nginx:</p>



<pre class="wp-block-code"><code>sudo systemctl restart nginx</code></pre>



<p class="wp-block-paragraph">If you try accessing your server in your web browser, you&#8217;ll get a 404 error, since WordPress hasn&#8217;t been installed or configured yet. Regardless, it&#8217;ll tell you that Nginx at least sees your new virtual host.</p>



<h3 class="wp-block-heading">Installing PHP 8.4</h3>



<p class="wp-block-paragraph">PHP is what makes WordPress tick, so we&#8217;ll need to install it. First, install the <code>php-fpm</code> package, along with all of the modules that WordPress needs:</p>



<pre class="wp-block-code"><code>sudo apt install php-fpm php-mysql php-curl php-dom php-imagick php-mbstring php-zip php-gd php-intl</code></pre>



<p class="wp-block-paragraph">Next, enable and start the <code>php8.4-fpm</code> service:</p>



<pre class="wp-block-code"><code>sudo systemctl enable --now php8.4-fpm</code></pre>



<h4 class="wp-block-heading">Configuring php-fpm</h4>



<p class="wp-block-paragraph">Most of the defaults are fine, but some of them need changing. For example, you can only upload up to 2MB files, which is just way too small. Here&#8217;s a couple of commands to fix that:</p>



<pre class="wp-block-code"><code># Change 999G if you want some sort of limit
sudo sed -i "s/^post_max_size = 8M/post_max_size = <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">999G</mark>/g" /etc/php/8.4/fpm/php.ini
sudo sed -i "s/^upload_max_filesize = 2M/upload_max_filesize = <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">999G</mark>/g" /etc/php/8.4/fpm/php.ini</code></pre>



<h5 class="wp-block-heading">&#8220;Optimizing&#8221; pm_max_children</h5>



<p class="wp-block-paragraph">By default, <code>php-fpm</code> will only spawn up to 5 child processes, which is usually not enough for WordPress. This results in a lot of warnings in your logs saying that the limit of child processes has been reached, and can even cause performance issues.</p>



<p class="wp-block-paragraph">The reason why I put &#8220;optimizing&#8221; in quotes is because there&#8217;s two ways of doing this. The first way is the right way, which involves going into <code>www.conf</code>, setting <code>pm = dynamic</code> (The default), doing some math, and setting the values based on how much memory your server has.</p>



<p class="wp-block-paragraph">But since nobody wants to do math, I&#8217;ve come up with an easier way. My way involves setting <code>pm = ondemand</code> and <code>pm.max_children</code> to some absurdly high number, effectively removing the limit:</p>



<pre class="wp-block-code"><code># Change 99 to something lower if you want some sort of limit
sudo sed -i "s/^pm = dynamic/pm = ondemand/g" /etc/php/8.4/fpm/pool.d/www.conf
sudo sed -i "s/^pm.max_children = 5/pm.max_children = <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">99</mark>/g" /etc/php/8.4/fpm/pool.d/www.conf</code></pre>



<p class="wp-block-paragraph">Next, restart the <code>php-fpm</code> service:</p>



<pre class="wp-block-code"><code>sudo systemctl restart php8.4-fpm</code></pre>



<p class="wp-block-paragraph">Now <code>php-fpm</code> will spawn as many processes as it wants, and thanks to <code>pm = ondemand</code>, it&#8217;ll terminate idle ones after 10 seconds. You&#8217;ll most likely never need to worry about it again, and your server (probably) won&#8217;t explode. My method technically causes some overhead, since it needs to keep track of those processes, but probably not enough to be noticable.</p>



<h3 class="wp-block-heading">Installing MariaDB</h3>



<p class="wp-block-paragraph">Now that we&#8217;ve installed a web server and PHP, the last piece is installing a database for WordPress. First, install MariaDB:</p>



<pre class="wp-block-code"><code>sudo apt install mariadb-server</code></pre>



<p class="wp-block-paragraph">Next, enable and start MariaDB:</p>



<pre class="wp-block-code"><code>sudo systemctl enable --now mariadb</code></pre>



<p class="wp-block-paragraph">Then run the included script to secure MariaDB:</p>



<pre class="wp-block-code"><code>sudo mariadb-secure-installation</code></pre>



<p class="wp-block-paragraph">Note: Depending on your distro and MariaDB version, the command might be <code>mariadb_secure_installation</code>, <code>mysql_secure_installation</code> or <code>mysql-secure-installation</code>. <code>mariadb-secure-installation</code> is what the command is on Debian 13 and MariaDB 11.8.</p>



<p class="wp-block-paragraph">On the first step, it&#8217;ll ask you for the root password on your server, but if you don&#8217;t have one and you&#8217;re using <code>sudo</code> instead, just press enter. You can also say no for changing MariaDB&#8217;s root user password if you&#8217;re not using phpMyAdmin, or will create a different user. For everything else, choose yes.</p>



<h4 class="wp-block-heading">Installing phpMyAdmin (Optional)</h4>



<p class="wp-block-paragraph">Even though you don&#8217;t need phpMyAdmin, I still like having it since it makes database maintenance (if needed) easier, and it has fun statistics graphs to watch. Regardless, if you&#8217;re a command line junkie and don&#8217;t care about that stuff (And want a minimalish install), then move on to &#8220;Creating The WordPress Database (CLI)&#8221;.</p>



<p class="wp-block-paragraph">First, install the phpMyAdmin package:</p>



<pre class="wp-block-code"><code>sudo apt install phpmyadmin</code></pre>



<p class="wp-block-paragraph">It&#8217;ll ask you a few questions during installation. The first one it&#8217;ll ask is what webserver to configure automatically. Since we&#8217;re using Nginx, don&#8217;t select anything, press tab so your cursor is over <code>&lt;Ok&gt;</code>, and hit enter:</p>


<div class="wp-block-image">
<figure class="aligncenter size-full is-resized"><img loading="lazy" decoding="async" width="1124" height="672" src="https://alexshomenetwork.com/wp-content/uploads/2025/09/phpMyAdmin-Webserver-Question.png" alt="" class="wp-image-901" style="width:519px;height:auto" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/09/phpMyAdmin-Webserver-Question.png 1124w, https://alexshomenetwork.com/wp-content/uploads/2025/09/phpMyAdmin-Webserver-Question-300x179.png 300w" sizes="auto, (max-width: 1124px) 100vw, 1124px" /></figure>
</div>


<p class="wp-block-paragraph">It&#8217;ll then ask you if you want to configure a database for phpMyAdmin. Select yes, which is the default:</p>


<div class="wp-block-image">
<figure class="aligncenter size-full is-resized"><img loading="lazy" decoding="async" width="1128" height="648" src="https://alexshomenetwork.com/wp-content/uploads/2025/09/phpMyAdmin-Database-Configuration.png" alt="" class="wp-image-897" style="width:515px;height:auto" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/09/phpMyAdmin-Database-Configuration.png 1128w, https://alexshomenetwork.com/wp-content/uploads/2025/09/phpMyAdmin-Database-Configuration-300x172.png 300w" sizes="auto, (max-width: 1128px) 100vw, 1128px" /></figure>
</div>


<p class="wp-block-paragraph">Next, create a password for the phpMyAdmin user (Or leave it blank to have it generate a random one:</p>


<div class="wp-block-image">
<figure class="aligncenter size-full is-resized"><img loading="lazy" decoding="async" width="1128" height="646" src="https://alexshomenetwork.com/wp-content/uploads/2025/09/phpMyAdmin-User-Configuration.png" alt="" class="wp-image-900" style="width:519px;height:auto" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/09/phpMyAdmin-User-Configuration.png 1128w, https://alexshomenetwork.com/wp-content/uploads/2025/09/phpMyAdmin-User-Configuration-300x172.png 300w" sizes="auto, (max-width: 1128px) 100vw, 1128px" /></figure>
</div>


<h5 class="wp-block-heading">Configuring Nginx for phpMyAdmin</h5>



<p class="wp-block-paragraph">Since phpMyAdmin can&#8217;t configure Nginx automatically, we&#8217;ll have to do it ourselves. First, create a new virtual host file for phpMyAdmin:</p>



<pre class="wp-block-code"><code>sudo nano /etc/nginx/sites-available/phpmyadmin</code></pre>



<p class="wp-block-paragraph">Next, add the following content, which spoiler alert, is basically the same as the WordPress one, just with the WordPress specific stuff stripped out:</p>



<pre class="wp-block-code"><code>server {
        # Change this to 80 if you want to access it with a subdomain instead
	listen <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">8080</mark> default_server;
	listen &#91;::]:<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">8080</mark> default_server;

	root /usr/share/phpmyadmin;

	index index.php index.html index.htm index.nginx-debian.html;

        # If you want it to be accessible on a subdomain, replace _ with your subdomain, and make sure you have a DNS record pointing to your server
	server_name <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">_</mark>;


	location / {
		try_files $uri $uri/ /index.php?$args;
	}

	# pass PHP scripts to FastCGI server
	#
	location ~ \.php$ {
		include snippets/fastcgi-php.conf;
		fastcgi_intercept_errors on;
		fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
		include fastcgi_params;
		fastcgi_pass unix:/run/php/php-fpm.sock;
		add_header X-Content-Type-Options nosniff;
		add_header X-XSS-Protection "1; mode=block";
		add_header X-Permitted-Cross-Domain-Policies none;
		add_header X-Frame-Options "SAMEORIGIN";
	}<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color"></mark>

	# Don't log access to favicon.ico and robots.txt
	location = /favicon.ico {
		log_not_found off;
		access_log off;
	}

	location = /robots.txt {
		allow all;
		log_not_found off;
		access_log off;
	}
	
	# Deny access to hidden files
	location ~ /\.ht {
		deny all;
	}
}</code></pre>



<p class="wp-block-paragraph">Next, symlink it to <code>sites-enabled</code>:</p>



<pre class="wp-block-code"><code>sudo ln -s /etc/nginx/sites-available/phpmyadmin /etc/nginx/sites-enabled/phpmyadmin</code></pre>



<p class="wp-block-paragraph">Test it:</p>



<pre class="wp-block-code"><code>sudo nginx -t</code></pre>



<p class="wp-block-paragraph">And finally, if it was successful, restart Nginx:</p>



<pre class="wp-block-code"><code>sudo systemctl restart nginx</code></pre>



<p class="wp-block-paragraph">Now navigate to <code>server-ip-address:8080</code> (Or your subdomain), and if everything has gone well, you should be greeted with the phpMyAdmin login screen:</p>


<div class="wp-block-image">
<figure class="aligncenter size-full is-resized"><img loading="lazy" decoding="async" width="388" height="461" src="https://alexshomenetwork.com/wp-content/uploads/2025/09/phpMyAdmin-Login.png" alt="" class="wp-image-899" style="width:307px;height:auto" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/09/phpMyAdmin-Login.png 388w, https://alexshomenetwork.com/wp-content/uploads/2025/09/phpMyAdmin-Login-252x300.png 252w" sizes="auto, (max-width: 388px) 100vw, 388px" /></figure>
</div>


<p class="wp-block-paragraph">Try logging in with the root user, using the password you set (Or the phpMyAdmin user, which is <code>phpmyadmin</code>, but you&#8217;ll need root later on), and you should be greeted with the home page:</p>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img loading="lazy" decoding="async" width="1024" height="307" src="https://alexshomenetwork.com/wp-content/uploads/2025/09/phpMyAdmin-Home-1024x307.png" alt="" class="wp-image-909" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/09/phpMyAdmin-Home-1024x307.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2025/09/phpMyAdmin-Home-300x90.png 300w, https://alexshomenetwork.com/wp-content/uploads/2025/09/phpMyAdmin-Home-768x230.png 768w, https://alexshomenetwork.com/wp-content/uploads/2025/09/phpMyAdmin-Home-1536x460.png 1536w, https://alexshomenetwork.com/wp-content/uploads/2025/09/phpMyAdmin-Home-1568x470.png 1568w, https://alexshomenetwork.com/wp-content/uploads/2025/09/phpMyAdmin-Home.png 1602w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
</div>


<p class="wp-block-paragraph">If it doesn&#8217;t let you log in, you might need to reset the root password:</p>



<pre class="wp-block-code"><code>sudo mysql -e "ALTER USER 'root'@'localhost' IDENTIFIED VIA mysql_native_password USING PASSWORD('<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">Password</mark>') OR unix_socket;"</code></pre>



<p class="wp-block-paragraph">Or if you don&#8217;t want to use root, you can create a new user and disable the root user instead:</p>



<pre class="wp-block-code"><code>sudo mysql -e "CREATE USER '<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">notroot</mark>'@'localhost' IDENTIFIED VIA mysql_native_password USING PASSWORD('<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">Password</mark>');"
sudo mysql -e "GRANT ALL PRIVILEGES ON *.* TO '<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">notroot</mark>'@'localhost' WITH GRANT OPTION;"
sudo mysql -u <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">notroot</mark> -p
MariaDB &#91;(none)]&gt; ALTER USER 'root'@'localhost' ACCOUNT LOCK;</code></pre>



<p class="wp-block-paragraph">You can perform these steps in phpMyAdmin instead, besides resetting the root password.</p>



<h5 class="wp-block-heading">Additional phpMyAdmin Security</h5>



<p class="wp-block-paragraph">A mistake that people make far too often when configuring phpMyAdmin is leaving it wide open to the internet, and on top of that, using the default root user with a weak, or God forbid, no password. Not only can an attacker gain access to any database on your server, including your WordPress one, but it can also be used as an entrypoint to gain access to the rest of your server.</p>



<p class="wp-block-paragraph">We&#8217;ve already taken half of the measures we need by locking down the root user, so let&#8217;s focus on protecting phpMyAdmin itself by requiring a separate login to access it. First, install the <code>apache2-utils</code> package:</p>



<pre class="wp-block-code"><code>sudo apt install apache2-utils</code></pre>



<p class="wp-block-paragraph">Next, create a <code>.htpasswd</code> file in <code>/etc/nginx</code>. Make sure that you choose a different login from phpMyAdmin and WordPress, otherwise it&#8217;s pretty pointless:</p>



<pre class="wp-block-code"><code>sudo htpasswd -c /etc/nginx/.htpasswd <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">username</mark></code></pre>



<p class="wp-block-paragraph">You&#8217;ll be prompted twice to enter a password. Next, change the permissions on the file to more secure ones:</p>



<pre class="wp-block-code"><code>sudo chown www-data:www-data /etc/nginx/.htpasswd &amp;&amp; sudo chmod 640 /etc/nginx/.htpasswd</code></pre>



<p class="wp-block-paragraph">This will ensure that <code>www-data</code>, the Nginx user, is the only user that can access the file. Finally, modify the <code>location /</code> block in the phpMyAdmin virtual host as follows:</p>



<pre class="wp-block-code"><code>...
location / {
		try_files $uri $uri/ /index.php?$args;
		# Basic authentication
		auth_basic "Login Required";
		auth_basic_user_file /etc/nginx/.htpasswd;
}
...</code></pre>



<p class="wp-block-paragraph">For extra security, I would also recommend combining it with IP address rules:</p>



<pre class="wp-block-code"><code>...
location / {
		try_files $uri $uri/ /index.php?$args;

		# Requires that the user both has an allowed IP address and their login is correct

		satisfy all;

		# Your public IP address
		allow <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">1.2.3.4</mark>;
		# Your LAN (If applicable)
		allow <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">192.168.0.0/24</mark>;
		# You probably get the idea by now, add and remove as needed
		# Deny everyone else
		deny all;
		# Basic authentication
		auth_basic "Login Required";
		auth_basic_user_file /etc/nginx/.htpasswd;
}
...</code></pre>



<p class="wp-block-paragraph">Check your configuration and restart Nginx:</p>



<pre class="wp-block-code"><code>sudo nginx -t &amp;&amp; sudo systemctl restart nginx</code></pre>



<p class="wp-block-paragraph">If all is well, try navigating to phpMyAdmin, and you should be prompted for a login from Nginx:</p>


<div class="wp-block-image">
<figure class="aligncenter size-full is-resized"><img loading="lazy" decoding="async" width="382" height="285" src="https://alexshomenetwork.com/wp-content/uploads/2025/09/Nginx-Login.png" alt="" class="wp-image-895" style="width:328px;height:auto" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/09/Nginx-Login.png 382w, https://alexshomenetwork.com/wp-content/uploads/2025/09/Nginx-Login-300x224.png 300w" sizes="auto, (max-width: 382px) 100vw, 382px" /></figure>
</div>


<p class="wp-block-paragraph">If you entered your login correctly, but it&#8217;s not letting you in, check <code>/var/log/nginx/error.log</code> and see if it&#8217;s having issues accessing <code>.htpasswd</code>. If it&#8217;s having trouble accessing it, you can try giving everyone access (<code>sudo chmod a+r /etc/nginx/.htpasswd</code>) temporarily to see if that fixes it. Giving everyone access is very insecure, so make sure to change it back once it&#8217;s working.</p>



<p class="wp-block-paragraph">You can also recreate your user if you forgot your password (Or as a quick sanity check):</p>



<pre class="wp-block-code"><code>sudo htpasswd /etc/nginx/.htpasswd <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">username</mark></code></pre>



<p class="wp-block-paragraph">If you combine this with HTTPS (Certbot makes this easy) and Fail2ban (<a href="https://alexshomenetwork.com/fail2ban-nginx-cloudflare-debian-13/" target="_blank" rel="noreferrer noopener">Guide here</a>), then phpMyAdmin will be safe from the vast majority of attackers.</p>



<h4 class="wp-block-heading">Creating The WordPress Database (phpMyAdmin)</h4>



<p class="wp-block-paragraph">After you&#8217;ve made your way into phpMyAdmin one way or another, click the new button to create a new database:</p>


<div class="wp-block-image">
<figure class="aligncenter size-full is-resized"><img loading="lazy" decoding="async" width="482" height="516" src="https://alexshomenetwork.com/wp-content/uploads/2025/09/New-Database-Button.png" alt="" class="wp-image-893" style="width:243px;height:auto" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/09/New-Database-Button.png 482w, https://alexshomenetwork.com/wp-content/uploads/2025/09/New-Database-Button-280x300.png 280w" sizes="auto, (max-width: 482px) 100vw, 482px" /></figure>
</div>


<p class="wp-block-paragraph">Next, enter a name for your WordPress database, and select <code>utf8mb4_general_ci</code> from the dropdown menu, then click Create:</p>


<div class="wp-block-image">
<figure class="aligncenter size-large is-resized"><img loading="lazy" decoding="async" width="1024" height="313" src="https://alexshomenetwork.com/wp-content/uploads/2025/09/Create-Database-1024x313.png" alt="" class="wp-image-889" style="width:523px;height:auto" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/09/Create-Database-1024x313.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2025/09/Create-Database-300x92.png 300w, https://alexshomenetwork.com/wp-content/uploads/2025/09/Create-Database-768x235.png 768w, https://alexshomenetwork.com/wp-content/uploads/2025/09/Create-Database.png 1296w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
</div>


<p class="wp-block-paragraph">Since we now need a user to securely access this database, click the phpMyAdmin in the top left corner to navigate back to the home page, then click the User accounts tab:</p>


<div class="wp-block-image">
<figure class="aligncenter size-large is-resized"><img loading="lazy" decoding="async" width="1024" height="204" src="https://alexshomenetwork.com/wp-content/uploads/2025/09/Nav-To-Users-1024x204.png" alt="" class="wp-image-892" style="width:602px;height:auto" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/09/Nav-To-Users-1024x204.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2025/09/Nav-To-Users-300x60.png 300w, https://alexshomenetwork.com/wp-content/uploads/2025/09/Nav-To-Users-768x153.png 768w, https://alexshomenetwork.com/wp-content/uploads/2025/09/Nav-To-Users-1536x305.png 1536w, https://alexshomenetwork.com/wp-content/uploads/2025/09/Nav-To-Users-1568x312.png 1568w, https://alexshomenetwork.com/wp-content/uploads/2025/09/Nav-To-Users.png 1680w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
</div>


<p class="wp-block-paragraph">Under User accounts overview, click Add user account:</p>


<div class="wp-block-image">
<figure class="aligncenter size-full is-resized"><img loading="lazy" decoding="async" width="828" height="616" src="https://alexshomenetwork.com/wp-content/uploads/2025/09/New-User-Button.png" alt="" class="wp-image-894" style="width:410px;height:auto" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/09/New-User-Button.png 828w, https://alexshomenetwork.com/wp-content/uploads/2025/09/New-User-Button-300x223.png 300w, https://alexshomenetwork.com/wp-content/uploads/2025/09/New-User-Button-768x571.png 768w" sizes="auto, (max-width: 828px) 100vw, 828px" /></figure>
</div>


<p class="wp-block-paragraph">You can choose whatever username or password you want, but I would recommend entering <code>localhost</code> for Host name since that will only allow logins for that user from your server, and using the option to randomly generate a password (You&#8217;ll need to temporarily store it somewhere, since we&#8217;ll need it again):</p>


<div class="wp-block-image">
<figure class="aligncenter size-large is-resized"><img loading="lazy" decoding="async" width="1024" height="566" src="https://alexshomenetwork.com/wp-content/uploads/2025/09/WordPress-User-Information-1024x566.png" alt="" class="wp-image-906" style="width:472px;height:auto" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/09/WordPress-User-Information-1024x566.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2025/09/WordPress-User-Information-300x166.png 300w, https://alexshomenetwork.com/wp-content/uploads/2025/09/WordPress-User-Information-768x424.png 768w, https://alexshomenetwork.com/wp-content/uploads/2025/09/WordPress-User-Information.png 1296w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
</div>


<p class="wp-block-paragraph">Scroll to the bottom of the page, then click the Ok button towards the bottom left, under the SSL box:</p>


<div class="wp-block-image">
<figure class="aligncenter size-full is-resized"><img loading="lazy" decoding="async" width="738" height="694" src="https://alexshomenetwork.com/wp-content/uploads/2025/09/Creating-WordPress-User.png" alt="" class="wp-image-890" style="width:332px;height:auto" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/09/Creating-WordPress-User.png 738w, https://alexshomenetwork.com/wp-content/uploads/2025/09/Creating-WordPress-User-300x282.png 300w" sizes="auto, (max-width: 738px) 100vw, 738px" /></figure>
</div>


<p class="wp-block-paragraph">You should be brought back up to the top of the page, and a message should appear stating that your user was created successfully. </p>



<p class="wp-block-paragraph">Next, click the Database tab, select your WordPress database, then click Go:</p>


<div class="wp-block-image">
<figure class="aligncenter size-large is-resized"><img loading="lazy" decoding="async" width="1024" height="611" src="https://alexshomenetwork.com/wp-content/uploads/2025/09/Nav-to-Permissions-1024x611.png" alt="" class="wp-image-914" style="width:513px;height:auto" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/09/Nav-to-Permissions-1024x611.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2025/09/Nav-to-Permissions-300x179.png 300w, https://alexshomenetwork.com/wp-content/uploads/2025/09/Nav-to-Permissions-768x458.png 768w, https://alexshomenetwork.com/wp-content/uploads/2025/09/Nav-to-Permissions.png 1392w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
</div>


<p class="wp-block-paragraph">Click Check all under Database-specific privileges to give your WordPress user full access to your WordPress database, then click Go in the bottom left corner:</p>


<div class="wp-block-image">
<figure class="aligncenter size-large is-resized"><img loading="lazy" decoding="async" width="1024" height="970" src="https://alexshomenetwork.com/wp-content/uploads/2025/09/WordPress-User-Permissions-1024x970.png" alt="" class="wp-image-907" style="width:367px;height:auto" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/09/WordPress-User-Permissions-1024x970.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2025/09/WordPress-User-Permissions-300x284.png 300w, https://alexshomenetwork.com/wp-content/uploads/2025/09/WordPress-User-Permissions-768x727.png 768w, https://alexshomenetwork.com/wp-content/uploads/2025/09/WordPress-User-Permissions.png 1168w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
</div>


<h4 class="wp-block-heading">Creating The WordPress Database (CLI)</h4>



<p class="wp-block-paragraph">If you don&#8217;t use phpMyAdmin, or just want a more straight-forward way of creating a database and user, you can more easily do it via the MariaDB command line. </p>



<p class="wp-block-paragraph">First, connect to MariaDB and create a database for WordPress:</p>



<pre class="wp-block-code"><code># Replace notroot with your own user, or just use sudo mysql if you didn't set a password for root
mysql -u <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">notroot</mark> -p
MariaDB &#91;(none)]&gt; CREATE DATABASE <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">wordpress</mark>;</code></pre>



<p class="wp-block-paragraph">Next, create a user for your WordPress database, and give it full permissions:</p>



<pre class="wp-block-code"><code># You'll want to randomly generate a password
CREATE USER '<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">wordpress</mark>'@'localhost' IDENTIFIED BY '<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">VerySecurePassword</mark>';
GRANT ALL PRIVILEGES ON <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">wordpress</mark>.* TO '<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">wordpress</mark>'@'localhost';</code></pre>



<p class="wp-block-paragraph">Now I don&#8217;t know about you, but I personally find this method a lot easier, or at least a lot easier to write about. </p>



<h3 class="wp-block-heading">Actually Getting WordPress</h3>



<p class="wp-block-paragraph">We&#8217;re almost done with the hard part. We installed and configured Nginx, then PHP 8.4, and now MariaDB, so now that our server is setup, it&#8217;s time to actually download WordPress.</p>



<p class="wp-block-paragraph">First, install a couple of packages that will let you download and unzip WordPress into your web directory. These packages might already be included depending on your distro, but for a very bare bones Debian install, they&#8217;re not:</p>



<pre class="wp-block-code"><code>sudo apt install curl unzip</code></pre>



<p class="wp-block-paragraph">Next, download the WordPress ZIP file. I would recommend saving it to <code>/tmp</code> since you don&#8217;t need to worry about deleting it, but it doesn&#8217;t matter. Just don&#8217;t forget to delete it when you&#8217;re done:</p>



<pre class="wp-block-code"><code>curl https://wordpress.org/latest.zip -o /tmp/wordpress.zip</code></pre>



<p class="wp-block-paragraph">Next, unzip the WordPress archive to <code>/var/www/html</code>:</p>



<pre class="wp-block-code"><code>sudo unzip -d /var/www/html /tmp/wordpress.zip</code></pre>



<p class="wp-block-paragraph">Navigate to <code>/var/www/html/wordpress</code>, create a copy of <code>wp-config-sample.php</code>, and name it <code>wp-config.php</code>:</p>



<pre class="wp-block-code"><code>cd /var/www/html/wordpress &amp;&amp; sudo cp wp-config-sample.php wp-config.php</code></pre>



<p class="wp-block-paragraph">Next, open <code>wp-config.php</code> in a text editor, locate the database connection settings, and fill in your WordPress database information:</p>



<pre class="wp-block-code"><code>// ** Database settings - You can get this info from your web host ** //
/** The name of the database for WordPress */
define( 'DB_NAME', '<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">database_name_here</mark>' );

/** Database username */
define( 'DB_USER', '<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">username_here</mark>' );

/** Database password */
define( 'DB_PASSWORD', '<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">password_here</mark>' );

/** Database hostname */
define( 'DB_HOST', 'localhost' );</code></pre>



<p class="wp-block-paragraph">Finally, change the owner of the WordPress folder to Nginx&#8217;s user:</p>



<pre class="wp-block-code"><code>sudo chown -R www-data:www-data /var/www/html/wordpress</code></pre>



<h4 class="wp-block-heading">Finishing The Install</h4>



<p class="wp-block-paragraph">Try navigating to your server&#8217;s IP address or domain like you did earlier when testing Nginx, and you should see a screen asking you for your language. Your browser may try to redirect you to HTTPS, so make sure that it&#8217;s only using HTTP:</p>


<div class="wp-block-image">
<figure class="aligncenter size-full is-resized"><img loading="lazy" decoding="async" width="390" height="744" src="https://alexshomenetwork.com/wp-content/uploads/2025/09/WordPress-Language-Selection.png" alt="" class="wp-image-904" style="width:211px;height:auto" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/09/WordPress-Language-Selection.png 390w, https://alexshomenetwork.com/wp-content/uploads/2025/09/WordPress-Language-Selection-157x300.png 157w" sizes="auto, (max-width: 390px) 100vw, 390px" /></figure>
</div>


<p class="wp-block-paragraph">If you see it, then congratulations! You&#8217;ve successfully finished the hard part, and can continue setting it up. If you don&#8217;t, or you&#8217;re having problems, then move to the troubleshooting sections and come back.</p>



<p class="wp-block-paragraph">Click continue, and fill out your information:</p>


<div class="wp-block-image">
<figure class="aligncenter size-full is-resized"><img loading="lazy" decoding="async" width="766" height="802" src="https://alexshomenetwork.com/wp-content/uploads/2025/09/WordPress-Setup.png" alt="" class="wp-image-905" style="width:455px;height:auto" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/09/WordPress-Setup.png 766w, https://alexshomenetwork.com/wp-content/uploads/2025/09/WordPress-Setup-287x300.png 287w" sizes="auto, (max-width: 766px) 100vw, 766px" /><figcaption class="wp-element-caption">Please, don&#8217;t use &#8220;Password&#8221;, or any password that requires you to click the Confirm Password checkbox, unless if you want to get hacked.</figcaption></figure>
</div>


<p class="wp-block-paragraph">After clicking Install WordPress, you should now see the WordPress admin page:</p>


<div class="wp-block-image">
<figure class="aligncenter size-large is-resized"><img loading="lazy" decoding="async" width="1024" height="498" src="https://alexshomenetwork.com/wp-content/uploads/2025/09/WordPress-Admin-1024x498.png" alt="" class="wp-image-902" style="width:619px;height:auto" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/09/WordPress-Admin-1024x498.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2025/09/WordPress-Admin-300x146.png 300w, https://alexshomenetwork.com/wp-content/uploads/2025/09/WordPress-Admin-768x373.png 768w, https://alexshomenetwork.com/wp-content/uploads/2025/09/WordPress-Admin-1536x746.png 1536w, https://alexshomenetwork.com/wp-content/uploads/2025/09/WordPress-Admin-1568x762.png 1568w, https://alexshomenetwork.com/wp-content/uploads/2025/09/WordPress-Admin.png 1601w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
</div>


<p class="wp-block-paragraph">At this point, you should click on Updates under Dashboard, and make sure that everything is up to date. You should also navigate to Plugins, Installed Plugins, and click the Enable auto-updates link for every plugin that&#8217;s there. You&#8217;ll also need to do this to any new plugins that you install, since for whatever reason it&#8217;s disabled by default.</p>



<h5 class="wp-block-heading">Troubleshooting</h5>



<p class="wp-block-paragraph">When installing WordPress, especially for the first time, there are some common issues that me (Even after doing quite a few of them) and many others run into, so I&#8217;ll outline some common issues and their solutions.</p>



<h5 class="wp-block-heading">Error Establishing a Database Connection</h5>



<p class="wp-block-paragraph">One of the most common errors you get when setting up WordPress is that it can&#8217;t connect to your database (Usually it doesn&#8217;t display the troubleshooting steps):</p>


<div class="wp-block-image">
<figure class="aligncenter size-full is-resized"><img loading="lazy" decoding="async" width="816" height="432" src="https://alexshomenetwork.com/wp-content/uploads/2025/09/WordPress-Database-Error.png" alt="" class="wp-image-903" style="width:578px;height:auto" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/09/WordPress-Database-Error.png 816w, https://alexshomenetwork.com/wp-content/uploads/2025/09/WordPress-Database-Error-300x159.png 300w, https://alexshomenetwork.com/wp-content/uploads/2025/09/WordPress-Database-Error-768x407.png 768w" sizes="auto, (max-width: 816px) 100vw, 816px" /></figure>
</div>


<p class="wp-block-paragraph">The first step is to check and see if MariaDB is running, so run the following command:</p>



<pre class="wp-block-code"><code>sudo systemctl status mariadb</code></pre>



<p class="wp-block-paragraph">This command will also show if MariaDB is producing any errors. </p>



<p class="wp-block-paragraph">The next step is to ensure that the login credentials and database name in <code>wp-config.php</code> are correct, and that there aren&#8217;t any syntax issues with the file. As a sanity check, you can delete the <code>wp-config.php</code> file and copy it again from <code>wp-config-sample.php</code> (Assuming you&#8217;re in <code>/var/www/html/wordpress</code>):</p>



<pre class="wp-block-code"><code>sudo rm wp-config.php &amp;&amp; sudo cp wp-config-sample.php wp-config.php &amp;&amp; sudo chown www-data:www-data wp-config.php</code></pre>



<p class="wp-block-paragraph">Next, it&#8217;s time to verify that your WordPress database and user actually exist. First, connect to your database using the same commands you used earlier, and run the following command to show all of the databases on your server:</p>



<pre class="wp-block-code"><code>SHOW DATABASES;</code></pre>



<p class="wp-block-paragraph">If you&#8217;re using phpMyAdmin, your WordPress database will appear on the left side of the screen along with all of the other databases on your server.</p>



<p class="wp-block-paragraph">Next, verify that your WordPress user exists:</p>



<pre class="wp-block-code"><code>SHOW CREATE USER '<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">wordpress</mark>'@'localhost';</code></pre>



<p class="wp-block-paragraph">If your WordPress user exists, it&#8217;ll show the same <code>CREATE USER</code> command that you used when creating the user (The real password being replaced with a hash). </p>



<p class="wp-block-paragraph">If you forgot the password you set for your WordPress user, or it happens to contain a single <code>'</code> or double quote <code>"</code> (Which might break the syntax in <code>wp-config.php</code>), you can change it with the following command:</p>



<pre class="wp-block-code"><code>ALTER USER '<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">wordpress</mark>'@'localhost' IDENTIFIED BY '<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">VerySecurePassword</mark>';</code></pre>



<p class="wp-block-paragraph">For phpMyAdmin users, you can navigate to the same User accounts screen that you used when creating your WordPress user, and if you want to change its password, click on its name, then Change password towards the top of the screen.</p>



<p class="wp-block-paragraph">Finally, to verify that your WordPress database is accessible by your user, log into phpMyAdmin or connect using your WordPress user:</p>



<pre class="wp-block-code"><code>sudo mysql -u <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">wordpress</mark> -p</code></pre>



<p class="wp-block-paragraph">Then run the following commands to connect to your database:</p>



<pre class="wp-block-code"><code>SHOW DATABASES;
# If your WordPress database is in the list, then try using it
USE <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">wordpress</mark>;
SHOW TABLES;
# It'll say it's empty, which is normal</code></pre>



<p class="wp-block-paragraph">If you&#8217;re getting any errors, switch back to your root account, and try giving the WordPress user all privileges on your WordPress database:</p>



<pre class="wp-block-code"><code>GRANT ALL PRIVILEGES ON <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">wordpress</mark>.* TO '<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">wordpress</mark>'@'localhost';</code></pre>



<p class="wp-block-paragraph">A database permission issue may also manifest as WordPress letting you complete the setup, but it failing at installation, or otherwise giving permission issues.</p>



<p class="wp-block-paragraph">If needed, update your login credentials in <code>wp-config.php</code>, and refresh the page. You should now be prompted for your language.</p>



<h5 class="wp-block-heading">Permission Issues or Installation Failing</h5>



<p class="wp-block-paragraph">If WordPress is failing at the installation step, or it let you installed, but you keep getting permission errors when you try doing anything, then this can indicate a permission issue on the WordPress files, or a permission issue with your database.</p>



<p class="wp-block-paragraph">First, connect to MariaDB, and try giving your WordPress user full permissions on your WordPress database:</p>



<pre class="wp-block-code"><code>GRANT ALL PRIVILEGES ON <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">wordpress</mark>.* TO '<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">wordpress</mark>'@'localhost';</code></pre>



<p class="wp-block-paragraph">If you&#8217;re using phpMyAdmin, the steps are basically identical to creating the user, except under User accounts, you just select your WordPress user and click Database at the top.</p>



<p class="wp-block-paragraph">You can try logging in as your WordPress user and try accessing the database (Which the steps for I&#8217;ve already outlined at the end of the previous section).</p>



<p class="wp-block-paragraph">Next, verify that the Nginx user has access to WordPress&#8217;s files:</p>



<pre class="wp-block-code"><code>sudo chown -R www-data:www-data /var/www/html/wordpress</code></pre>



<p class="wp-block-paragraph">You should now be able to access WordPress without getting any permission issues.</p>



<h5 class="wp-block-heading">Browser Issues (Connection Timed Out, Connection Refused)</h5>



<p class="wp-block-paragraph">If you try accessing WordPress, but your browser is timing out, or giving an error like connection refused, then that usually indicates a problem with Nginx.</p>



<p class="wp-block-paragraph">First, make sure your browser is not trying to connect over HTTPS. Browsers like Firefox will show a warning message stating that the website doesn&#8217;t support HTTPS before letting you continue, but some browsers will redirect regardless, and fail. You might need to type in your server&#8217;s address as <code>http://ip-address-or-domain</code>, making sure you type <code>http</code> instead of <code>https</code>, since that usually forces browsers to use HTTP rather than HTTPS. You can also temporarily disable any features that automatically redirect you to HTTPS to ensure they&#8217;re not the problem.</p>



<p class="wp-block-paragraph">If you&#8217;re behind Cloudflare or another CDN provider, they might be trying to redirect you to HTTPS, so make sure that those features are disabled. After that, try clearing your CDN provider&#8217;s cache and accessing WordPress in a private browsing session.</p>



<p class="wp-block-paragraph">Once you&#8217;ve ruled out browser issues, it&#8217;s time to narrow it down to the network or your server. The easiest way to do this is to have your server send a request to itself using <code>curl</code>:</p>



<pre class="wp-block-code"><code>curl http://127.0.0.1
# Alternatively
curl http://localhost
# You can use your server's IP address or domain instead
curl http://<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">server-ip-or-domain</mark></code></pre>



<p class="wp-block-paragraph">You should get the response printed directly to your terminal. If it fails, check the status of the Nginx service:</p>



<pre class="wp-block-code"><code>sudo systemctl status nginx</code></pre>



<p class="wp-block-paragraph">If you try to restart the Nginx service (<code>sudo systemctl restart nginx</code>), and it fails, check your config for any errors:</p>



<pre class="wp-block-code"><code>sudo nginx -t</code></pre>



<p class="wp-block-paragraph">You can also check the log files in <code>/var/log/nginx</code> for any errors as well.</p>



<h4 class="wp-block-heading">Basic Security</h4>



<p class="wp-block-paragraph">Since this blog post is already long enough, I will only leave a couple of security tips here that are simple to implement, yet so many people neglect to do, despite being mentioned by basically every WordPress guide.</p>



<h5 class="wp-block-heading">Securing wp-admin</h5>



<p class="wp-block-paragraph">Despite being one of the most well known vulnerabilities of WordPress, many people still leave <code>/wp-admin</code> wide open to the internet, with weak credentials, and typically no security measures.</p>



<p class="wp-block-paragraph">The first thing you should do is use secure login credentials. Generate a random password with special characters, and make it as long as WordPress allows.</p>



<p class="wp-block-paragraph">The next thing you should do is limit access to <code>/wp-admin</code> and <code>/wp-login.php</code>. You can accomplish this by making Nginx require a separate login that&#8217;s different from your WordPress login. The steps used when securing phpMyAdmin are basically identical, but there&#8217;s still some stuff you should know.</p>



<p class="wp-block-paragraph">First, install the <code>apache2-utils</code> package so we can create a <code>.htaccess</code> file:</p>



<pre class="wp-block-code"><code>sudo apt install apache2-utils</code></pre>



<p class="wp-block-paragraph">Next, create your user. Again, make sure that this login is different from WordPress and anything else on your server, otherwise you&#8217;re wasting your time:</p>



<pre class="wp-block-code"><code>sudo htpasswd -c /etc/nginx/.htpasswd <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">username</mark>
# Or if .htpasswd already exists when we secured phpMyAdmin, name it something else
sudo htpasswd -c /etc/nginx/.<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">something-else</mark> <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">username</mark></code></pre>



<p class="wp-block-paragraph">Next, change the permissions on your <code>.htaccess</code> file to something more secure, replacing the file name with the one that you chose:</p>



<pre class="wp-block-code"><code>sudo chown www-data:www-data /etc/nginx/.<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">something-else</mark> &amp;&amp; sudo chmod 640 /etc/nginx/.<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">something-else</mark></code></pre>



<p class="wp-block-paragraph">After that, open <code>/etc/nginx/sites-available/wordpress</code> in a text editor, and locate the <code>location /</code> block. Under that, add in two blocks for <code>/wp-admin</code> and <code>/wp-login.php</code>:</p>



<pre class="wp-block-code"><code>...
# The default location / block for reference. You don't need to add this

location / {
	try_files $uri $uri/ /index.php?$args;
}

# Again, change .<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">something-else</mark> to the file name that you used
location /wp-admin {
	auth_basic "Login Required";
	auth_basic_user_file /etc/nginx/.<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">something-else</mark>;
}

location = /wp-login.php {
	auth_basic "Login Required";
	auth_basic_user_file /etc/nginx/.<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">something-else</mark>;

	# Copy the PHP stuff from the location ~\.php$ block
	# There's probably a better way to do this, but I also don't feel like figuring it out
	include snippets/fastcgi-php.conf;
	fastcgi_intercept_errors on;
	fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
	include fastcgi_params;
	fastcgi_pass unix:/run/php/php-fpm.sock;
	add_header X-Content-Type-Options nosniff;
	add_header X-XSS-Protection "1; mode=block";add_header X-Permitted-Cross-Domain-Policies none;
	add_header X-Frame-Options "SAMEORIGIN";
}</code></pre>



<p class="wp-block-paragraph">For yet an extra layer of security, I recommend adding IP address rules to further restrict access:</p>



<pre class="wp-block-code"><code>...
# Again, probably a better way to do this, but this works fine

location /wp-admin {
	satisfy all;
	# Your public IP address
	allow <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">1.2.3.4</mark>;
	# Your LAN (If applicable)
	allow <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">192.168.0.0/24</mark>;
	# Add or remove as needed, make sure deny all is at the bottom
	deny all;
	auth_basic "Login Required";
	auth_basic_user_file /etc/nginx/.<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">something-else</mark>;
}

location = /wp-login.php {
	satisfy all;
	allow <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">1.2.3.4</mark>;
	allow <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">192.168.0.0/24</mark>;
	deny all;
	auth_basic "Login Required";
	auth_basic_user_file /etc/nginx/.<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">something-else</mark>;
	...
}
...</code></pre>



<p class="wp-block-paragraph">Finally, tell Nginx to test your config, restart Nginx (You probably know the commands by now), and try navigating to <code>/wp-admin</code> and <code>/wp-login.php</code>. Nginx should prompt you for a login separate from your WordPress one:</p>


<div class="wp-block-image">
<figure class="aligncenter size-full is-resized"><img loading="lazy" decoding="async" width="382" height="285" src="https://alexshomenetwork.com/wp-content/uploads/2025/09/Nginx-Login.png" alt="" class="wp-image-895" style="width:382px;height:auto" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/09/Nginx-Login.png 382w, https://alexshomenetwork.com/wp-content/uploads/2025/09/Nginx-Login-300x224.png 300w" sizes="auto, (max-width: 382px) 100vw, 382px" /><figcaption class="wp-element-caption">Yes, this is the same screenshot from the phpMyAdmin setup. No, I&#8217;m not taking another screenshot that shows basically the same thing.</figcaption></figure>
</div>


<p class="wp-block-paragraph">Now <code>/wp-admin</code> and <code>/wp-login.php</code> have some extra layers of security, especially if you combine Fail2ban to block brute force attacks (<a href="https://alexshomenetwork.com/fail2ban-nginx-cloudflare-debian-13/" target="_blank" rel="noreferrer noopener">Guide here</a>).</p>



<p class="wp-block-paragraph">If you&#8217;ve typed in the right credentials but it&#8217;s not letting you login, check <code>/var/log/nginx/error.log</code> to see if it&#8217;s having any issues accessing your <code>.htpasswd</code> file. You can try running <code>sudo chmod a+r /etc/nginx/.<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">something-else</mark></code> (Obviously substituting with your own <code>.htpasswd</code> file) to see if that fixes it, but make sure to change this back since it&#8217;s very insecure.</p>



<h5 class="wp-block-heading">Disabling /xmlrpc.php</h5>



<p class="wp-block-paragraph">The <code>/xmlrpc.php</code> endpoint was used by WordPress to allow applications to communicate to your website, like the WordPress mobile app for example. However, nowadays it has been replaced by the REST API (Located at <code>/wp-json)</code>, and is only used for backwards compatibility. </p>



<p class="wp-block-paragraph">Regardless, unless if you plan on using ancient applications to talk to your website, all it does is serve as a flashing neon billboard for attackers. Despite this, not only is it enabled by default, but WordPress doesn&#8217;t include an option to disable it (Which did exist in the early days after its introduction, but was apparently removed).</p>



<p class="wp-block-paragraph">The two common ways of disabling <code>/xmlrpc.php</code> is by using a plugin, or blocking it on your webserver. I&#8217;ll be showing how to block it with Nginx, so you don&#8217;t need to install any plugins.</p>



<p class="wp-block-paragraph">First, fire up your WordPress virtual host file, and navigate to right where we left off in the previous section. Under your <code>location = /wp-login.php</code> block, add in a new one for <code>/xmlrpc.php</code>:</p>



<pre class="wp-block-code"><code># You can add an allow before the deny to allow certain IP's in the slim chance that you happen to need it, but you probably don't
location = /xmlrpc.php {
	deny all;
}</code></pre>



<p class="wp-block-paragraph">Test your config and restart Nginx, then try nagivating to <code>/xmlrpc.php</code>, like you did with <code>/wp-admin</code> and <code>/wp-login.php</code>. You should get a 403 forbidden error.</p>



<h3 class="wp-block-heading">Configuring HTTPS</h3>



<p class="wp-block-paragraph">If you&#8217;ve made it this far, and not only your server isn&#8217;t on fire, but you haven&#8217;t gone insane (Or lost me), then congratulations! You&#8217;ve made it to the home stretch, and we only have one last step left, which is configuring HTTPS. To make it easy, I&#8217;ll show how to use Certbot.</p>



<p class="wp-block-paragraph">Before we can do anything, it&#8217;s important to note that WordPress seems to listen on one URL and one URL only, and that URL is set when you first install WordPress. This means that since you&#8217;ve probably accessed your server with its IP address or <code>http://yourdomain.com</code>, WordPress will automatically redirect you to it.</p>



<p class="wp-block-paragraph">If you try setting up HTTPS without first changing this URL, you&#8217;ll either just get redirected to your server&#8217;s IP address, or get a redirect loop since Certbot tells Nginx to redirect to HTTPS, but WordPress keeps trying to redirect to HTTP.</p>



<p class="wp-block-paragraph">Thankfully, it&#8217;s easy to change this URL. You can either do this in <code>/wp-admin</code> under Settings and General, or modifying the WordPress database, which is what I&#8217;ll show. Keep in mind, you WILL temporarily loose access, but you can change it back if needed by modifying the database.</p>



<p class="wp-block-paragraph">First, connect to your database using your WordPress user, then switch to your WordPress database:</p>



<pre class="wp-block-code"><code>mysql -u <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">wordpress</mark> -p
MariaDB &#91;(none)]&gt; USE <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">wordpress</mark>;</code></pre>



<p class="wp-block-paragraph">Take note of your existing URL settings so you can easily revert back to it if needed:</p>



<pre class="wp-block-code"><code>SELECT * FROM wp_options WHERE option_name IN ('siteurl','home');
# Your current URL will be displayed under option_value</code></pre>



<p class="wp-block-paragraph">Once you&#8217;ve taken note of your existing URL, change it to your new one:</p>



<pre class="wp-block-code"><code>UPDATE wp_options SET option_value = "<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">https://changeme.alexshomenetwork.com</mark>" WHERE option_name = "siteurl" OR option_name = "home";</code></pre>



<p class="wp-block-paragraph">Now that you&#8217;ve updated your site URL&#8217;s, you can now install Certbot:</p>



<pre class="wp-block-code"><code>sudo apt install certbot python3-certbot-nginx</code></pre>



<p class="wp-block-paragraph">So that way Certbot actually sees your website, open your Nginx virtual host file WordPress, and locate <code>server_name _</code>; towards the top:</p>



<pre class="wp-block-code"><code># Remember me mentioning this earlier? Change the <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">_</mark> you set earlier to your domain
server_name <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">changeme.alexshomenetwork.com</mark>;
# I put my domain there just as an example</code></pre>



<p class="wp-block-paragraph">If you&#8217;re accessing phpMyAdmin from a subdomain, then your config should already be good.</p>



<p class="wp-block-paragraph">You know the Nginx drill by now. It&#8217;s a good time to verify that the correct DNS records are pointing to your server, and you can actually access your server from the public internet, from both HTTP and HTTPS, otherwise Certbot will fail. If you&#8217;re behind a CDN like Cloudflare, you should disable any features that automatically redirect you to HTTPS, and purge their cache.</p>



<p class="wp-block-paragraph">Next, run the <code>certbot</code> command, and follow the prompts. If you don&#8217;t want to do it interactively, you can use flags instead (<code>certbot --help</code>):</p>



<pre class="wp-block-code"><code>sudo certbot</code></pre>



<p class="wp-block-paragraph">Certbot should automatically restart Nginx for us, but if it doesn&#8217;t, do our ususal Nginx drill, and try accessing your website.</p>



<p class="wp-block-paragraph">If you can&#8217;t access your website, you might need to purge your cache with your CDN provider like Cloudflare if you&#8217;re behind one. I also recommend checking in a private browsing session, since your browser cache can cause issues as well.</p>



<h3 class="wp-block-heading">Conclusion</h3>



<p class="wp-block-paragraph">If your website is working, then congratulations! You&#8217;ve installed WordPress from start to finish, and even implemented some basic security measures. Like I mentioned a couple of times earlier, I do plan on writing an updated Fail2ban guide (Which I will <a href="https://alexshomenetwork.com/fail2ban-nginx-cloudflare-debian-13/" target="_blank" rel="noreferrer noopener">link here</a>). If you have any questions, feel free to leave them below, and I&#8217;ll try my best to help you, even though I can&#8217;t make any guarantees.</p>



<h3 class="wp-block-heading">References</h3>



<p class="wp-block-paragraph">Nginx Authentication: <a href="https://docs.nginx.com/nginx/admin-guide/security-controls/configuring-http-basic-authentication/">https://docs.nginx.com/nginx/admin-guide/security-controls/configuring-http-basic-authentication/</a></p>



<p class="wp-block-paragraph">Database Creation: <a href="https://developer.wordpress.org/advanced-administration/before-install/creating-database/">https://developer.wordpress.org/advanced-administration/before-install/creating-database/</a></p>



<p class="wp-block-paragraph">Where my Nginx Config is Derrived From: <a href="https://developer.wordpress.org/advanced-administration/server/web-server/nginx/">https://developer.wordpress.org/advanced-administration/server/web-server/nginx/</a></p>
<p>The post <a href="https://alexshomenetwork.com/installing-wordpress-on-debian-13/">Installing WordPress on Debian 13</a> appeared first on <a href="https://alexshomenetwork.com">Alex&#039;s Home Network</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://alexshomenetwork.com/installing-wordpress-on-debian-13/feed/</wfw:commentRss>
			<slash:comments>6</slash:comments>
		
		
			</item>
		<item>
		<title>Hacking an Old LotusCMS Box</title>
		<link>https://alexshomenetwork.com/hacking-an-old-lotuscms-box/</link>
					<comments>https://alexshomenetwork.com/hacking-an-old-lotuscms-box/#respond</comments>
		
		<dc:creator><![CDATA[Alex]]></dc:creator>
		<pubDate>Mon, 28 Apr 2025 16:00:10 +0000</pubDate>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Hacking]]></category>
		<category><![CDATA[LotusCMS]]></category>
		<guid isPermaLink="false">https://alexshomenetwork.com/?p=774</guid>

					<description><![CDATA[<p>Today I will be showing how I managed to hack into an old LotusCMS box. Usually I won&#8217;t bother writing about stuff like this, but I figured that it would make an interesting blog post given my discoveries, and it might be helpful to someone (Legally, of course) in the future. Legal Disclaimer In case<a class="more-link" href="https://alexshomenetwork.com/hacking-an-old-lotuscms-box/">Continue reading <span class="screen-reader-text">"Hacking an Old LotusCMS Box"</span></a></p>
<p>The post <a href="https://alexshomenetwork.com/hacking-an-old-lotuscms-box/">Hacking an Old LotusCMS Box</a> appeared first on <a href="https://alexshomenetwork.com">Alex&#039;s Home Network</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Today I will be showing how I managed to hack into an old LotusCMS box. Usually I won&#8217;t bother writing about stuff like this, but I figured that it would make an interesting blog post given my discoveries, and it might be helpful to someone (Legally, of course) in the future.</p>



<h3 class="wp-block-heading">Legal Disclaimer</h3>



<p class="wp-block-paragraph">In case it isn&#8217;t obvious, the stuff that I&#8217;m showing in this post is considered illegal in most sane jurisdictions. What I&#8217;m showing is for educational purposes ONLY, and should NOT be attempted on any machines or networks that aren&#8217;t yours. There&#8217;s also the possibility of data loss should you follow anything in this post, so make sure to have backups of anything important, and only perform anything in an isolated and controlled environment. If you&#8217;re dumb enough to try any of this stuff on your critical systems and you lose data, or you decide to try it on a machine that isn&#8217;t yours and now you&#8217;re in federal prison, then don&#8217;t come crying to me saying that I told you to do something illegal. I warned you.</p>



<p class="wp-block-paragraph">If you want to hack Linux machines legally, then check out <a href="https://www.vulnhub.com/">VulnHub</a> or <a href="https://www.hackthebox.com/">Hack The Box</a> for more machines like the one I&#8217;m demonstrating in this post.</p>



<p class="wp-block-paragraph">Now that we&#8217;ve got the legal stuff out of the way, time for the actual post.</p>



<h3 class="wp-block-heading">Backstory: Why This Post Even Exists</h3>



<p class="wp-block-paragraph">The backstory isn&#8217;t exactly relevant to the hacking itself, so feel free to skip this if you don&#8217;t care. </p>



<p class="wp-block-paragraph">Recently, in my pen-testing class, I got assigned a group project, which usually I hate. This is because there&#8217;s generally a massive knowledge gap between me and the other group members, so this results in a huge imbalance of work. Regardless, our professor had assigned us a Linux machine that we were supposed to hack into. Our professor only told us that it was some sort of server, gave us a VM image, and no other details. </p>



<p class="wp-block-paragraph">Long story short, while waiting for my group members to figure out what to do with it, I got bored over my Spring break and hacked into the VM myself. This happened well before they did anything with the VM, so now I&#8217;m writing this post as a tutorial for them, and educational/entertainment content for you. This post will show how I got to that point.</p>



<h3 class="wp-block-heading">First Observation: Metasploitable 2?</h3>



<p class="wp-block-paragraph">When I first booted up the VM, I noticed that the boot screen looked awfully familiar:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="744" height="422" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/VM-Boot.png" alt="" class="wp-image-776" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/VM-Boot.png 744w, https://alexshomenetwork.com/wp-content/uploads/2025/04/VM-Boot-300x170.png 300w" sizes="auto, (max-width: 744px) 100vw, 744px" /></figure>



<p class="wp-block-paragraph">It reminded me of <a href="https://sourceforge.net/projects/metasploitable/">Metasploitable 2</a>, a purposely vulnerable Ubuntu machine we&#8217;ve been using in class that&#8217;s basically designed to demonstrate different exploits using Metasploit. As I later found out, while it wasn&#8217;t directly based off of Metasploitable 2, it used a similarly old version of Ubuntu.</p>



<h3 class="wp-block-heading">First Steps: Scanning The Target</h3>



<p class="wp-block-paragraph">The very first thing I did was get the IP address and run an aggressive nmap scan on it:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="853" height="525" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/nmap-Scan.png" alt="" class="wp-image-778" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/nmap-Scan.png 853w, https://alexshomenetwork.com/wp-content/uploads/2025/04/nmap-Scan-300x185.png 300w, https://alexshomenetwork.com/wp-content/uploads/2025/04/nmap-Scan-768x473.png 768w" sizes="auto, (max-width: 853px) 100vw, 853px" /></figure>



<p class="wp-block-paragraph">Even though there wasn&#8217;t much running, it was running an ancient version of Apache, PHP, and SSH, with an equally ancient Linux kernel. Regardless, I still got excited because I knew it was going to get interesting.</p>



<h4 class="wp-block-heading">About Apache</h4>



<p class="wp-block-paragraph">Since we now know it&#8217;s running a web server, let&#8217;s see what it&#8217;s hosting:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="957" height="562" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/Website.png" alt="" class="wp-image-779" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/Website.png 957w, https://alexshomenetwork.com/wp-content/uploads/2025/04/Website-300x176.png 300w, https://alexshomenetwork.com/wp-content/uploads/2025/04/Website-768x451.png 768w" sizes="auto, (max-width: 957px) 100vw, 957px" /></figure>



<p class="wp-block-paragraph">Oh look, a blog! While I did later find out that there were a few hints on it, the first thing that caught my attention was that Login button, so let&#8217;s click it and see what happens:</p>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="320" height="337" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/Login-Screen.png" alt="" class="wp-image-780" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/Login-Screen.png 320w, https://alexshomenetwork.com/wp-content/uploads/2025/04/Login-Screen-285x300.png 285w" sizes="auto, (max-width: 320px) 100vw, 320px" /></figure>
</div>


<p class="wp-block-paragraph">We&#8217;ve got ourselves a login screen that reveals a critical detail: The server is running LotusCMS, which I quickly found out was a notoriously vulnerable blogging platform.</p>



<p class="wp-block-paragraph">Let&#8217;s see what else is running on this server by running <code>nikto</code>:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="1007" height="641" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/Nikto-Scan.png" alt="" class="wp-image-783" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/Nikto-Scan.png 1007w, https://alexshomenetwork.com/wp-content/uploads/2025/04/Nikto-Scan-300x191.png 300w, https://alexshomenetwork.com/wp-content/uploads/2025/04/Nikto-Scan-768x489.png 768w" sizes="auto, (max-width: 1007px) 100vw, 1007px" /></figure>



<p class="wp-block-paragraph">I made multiple observations, including multiple pages that ran <code>phpinfo()</code>, and much more interestingly, phpMyAdmin, which I initially assumed was responsible for managing the database for LotusCMS. Let&#8217;s navigate to <code>/phpmyadmin</code> and see what surprises we get:</p>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="503" height="435" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/phpMyAdmin-Login.png" alt="" class="wp-image-784" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/phpMyAdmin-Login.png 503w, https://alexshomenetwork.com/wp-content/uploads/2025/04/phpMyAdmin-Login-300x259.png 300w" sizes="auto, (max-width: 503px) 100vw, 503px" /></figure>
</div>


<p class="wp-block-paragraph">Wow! That is an absolutely ancient version of phpMyAdmin. Since I got excited about the LotusCMS exploit, I didn&#8217;t spend much time with phpMyAdmin.</p>



<h3 class="wp-block-heading">Getting a Foothold: Exploiting LotusCMS</h3>



<p class="wp-block-paragraph">Exploiting LotusCMS proved to be a bit more difficult than I initially thought, but regardless, it was still very easy. Since I had it right at my fingertips, I searched Metasploit for LotusCMS, and found the Holy Grail:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="972" height="183" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/LotusCMS-Metasploit-Search.png" alt="" class="wp-image-785" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/LotusCMS-Metasploit-Search.png 972w, https://alexshomenetwork.com/wp-content/uploads/2025/04/LotusCMS-Metasploit-Search-300x56.png 300w, https://alexshomenetwork.com/wp-content/uploads/2025/04/LotusCMS-Metasploit-Search-768x145.png 768w" sizes="auto, (max-width: 972px) 100vw, 972px" /></figure>



<p class="wp-block-paragraph">With an excellent rank and a disclosure date from forever ago, it seemed like the perfect exploit, so I went ahead and configured it:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="986" height="627" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/LotusCMS-Metasploit-Config.png" alt="" class="wp-image-786" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/LotusCMS-Metasploit-Config.png 986w, https://alexshomenetwork.com/wp-content/uploads/2025/04/LotusCMS-Metasploit-Config-300x191.png 300w, https://alexshomenetwork.com/wp-content/uploads/2025/04/LotusCMS-Metasploit-Config-768x488.png 768w" sizes="auto, (max-width: 986px) 100vw, 986px" /></figure>



<p class="wp-block-paragraph">And I tried to exploit it:</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="434" height="260" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/Exploit-Fail.png" alt="" class="wp-image-787" style="width:434px;height:auto" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/Exploit-Fail.png 434w, https://alexshomenetwork.com/wp-content/uploads/2025/04/Exploit-Fail-300x180.png 300w" sizes="auto, (max-width: 434px) 100vw, 434px" /></figure>



<p class="wp-block-paragraph">Which after a few attempts, failed. Unfortunately, even after a bit of trial and error, it didn&#8217;t work.</p>



<h4 class="wp-block-heading">Plan B: DuckDuckGo To The Rescue</h4>



<p class="wp-block-paragraph">After my fail with Metasploit, I decided to give a quick search for LotusCMS on DuckDuckGo, and even after just simply typing &#8220;lotuscms&#8221; revealed this on GitHub:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="1011" height="612" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/Exploit-GitHub.png" alt="" class="wp-image-788" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/Exploit-GitHub.png 1011w, https://alexshomenetwork.com/wp-content/uploads/2025/04/Exploit-GitHub-300x182.png 300w, https://alexshomenetwork.com/wp-content/uploads/2025/04/Exploit-GitHub-768x465.png 768w" sizes="auto, (max-width: 1011px) 100vw, 1011px" /><figcaption class="wp-element-caption">Credit: <a href="https://github.com/Hood3dRob1n/LotusCMS-Exploit">https://github.com/Hood3dRob1n/LotusCMS-Exploit</a></figcaption></figure>



<p class="wp-block-paragraph">Yeah it&#8217;s definitely not a great sign for security when you&#8217;re searching up a product online and the very first thing that comes up, even before the official SourceForge repository, is a exploit on GitHub for it. Regardless, I knew that this was probably my ticket, so I used Metasploit to create a reverse listener:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="724" height="435" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/Metasploit-Listener.png" alt="" class="wp-image-789" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/Metasploit-Listener.png 724w, https://alexshomenetwork.com/wp-content/uploads/2025/04/Metasploit-Listener-300x180.png 300w" sizes="auto, (max-width: 724px) 100vw, 724px" /></figure>



<p class="wp-block-paragraph">I then downloaded the script and configured it:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="438" height="138" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/Exploit-Config-1.png" alt="" class="wp-image-790" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/Exploit-Config-1.png 438w, https://alexshomenetwork.com/wp-content/uploads/2025/04/Exploit-Config-1-300x95.png 300w" sizes="auto, (max-width: 438px) 100vw, 438px" /></figure>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="565" height="315" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/Exploit-Config-2.png" alt="" class="wp-image-791" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/Exploit-Config-2.png 565w, https://alexshomenetwork.com/wp-content/uploads/2025/04/Exploit-Config-2-300x167.png 300w" sizes="auto, (max-width: 565px) 100vw, 565px" /></figure>



<p class="wp-block-paragraph">And after a few seconds:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="838" height="474" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/Shell-Access.png" alt="" class="wp-image-792" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/Shell-Access.png 838w, https://alexshomenetwork.com/wp-content/uploads/2025/04/Shell-Access-300x170.png 300w, https://alexshomenetwork.com/wp-content/uploads/2025/04/Shell-Access-768x434.png 768w" sizes="auto, (max-width: 838px) 100vw, 838px" /></figure>



<p class="wp-block-paragraph">Success! We&#8217;ve got ourselves a shell. You might notice that the path for the web server is <code>/home/www/kioptrix3.com</code>, which tells us that this VM was originally from kioptrix.com, a now defunct website owned by some gambling website in a language that I can&#8217;t speak. You can still view the original kioptrix.com website on the <a href="https://web.archive.org/web/20111216194225/http://www.kioptrix.com/">Wayback Machine</a>. Regardless, I figured that our professor grabbed a vulnerable VM from somewhere for us to hack rather than making their own, and I&#8217;m not sure if/how many changes my professor made to it, but it&#8217;s still interesting to know the backstory.</p>



<h3 class="wp-block-heading">Doing a Bit of Exploring</h3>



<p class="wp-block-paragraph">Now that we have access to a shell, let&#8217;s do a bit of exploration:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="998" height="573" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/Webroot-Exploration.png" alt="" class="wp-image-795" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/Webroot-Exploration.png 998w, https://alexshomenetwork.com/wp-content/uploads/2025/04/Webroot-Exploration-300x172.png 300w, https://alexshomenetwork.com/wp-content/uploads/2025/04/Webroot-Exploration-768x441.png 768w" sizes="auto, (max-width: 998px) 100vw, 998px" /></figure>



<p class="wp-block-paragraph">There&#8217;s kind of a lot going on here, mainly because I don&#8217;t feel like taking a bunch of screenshots, but as you can probably see, I find a file named <code>salt.dat</code> in <code>data/config</code> (Relative to <code>/home/www/kioptrix3.com</code>), and in <code>data/users</code>, I find a file named <code>admin.dat</code>, that contains some information on the admin user. We can save these for later as we can use this to crack the admin password.</p>



<p class="wp-block-paragraph">We can also check the password files to see what access we have to them:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="622" height="526" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/Password-Files.png" alt="" class="wp-image-796" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/Password-Files.png 622w, https://alexshomenetwork.com/wp-content/uploads/2025/04/Password-Files-300x254.png 300w" sizes="auto, (max-width: 622px) 100vw, 622px" /></figure>



<p class="wp-block-paragraph">Unsurprisingly, they didn&#8217;t make <code>/etc/shadow</code> world-readable, nor are password hashes are stored in <code>/etc/passwd</code>, so let&#8217;s explore some potential privilege escalation methods.</p>



<h3 class="wp-block-heading">The Fun Part: Exploring Privilege Escalation</h3>



<p class="wp-block-paragraph">Since this VM is running Linux kernel 2.6.24, there are plenty of potential privilege escalation vulnerability, including the notorious <a href="https://dirtycow.ninja/">DirtyCOW</a> exploit, allowing unprivileged users to write to read-only files like <code>/etc/passwd</code>. Even though I got excited again and used this method the first time, I found something that was much easier and didn&#8217;t require kernel-level exploits.</p>



<p class="wp-block-paragraph">First, lets explore <code>/home</code>:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="655" height="480" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/User-Homes.png" alt="" class="wp-image-798" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/User-Homes.png 655w, https://alexshomenetwork.com/wp-content/uploads/2025/04/User-Homes-300x220.png 300w" sizes="auto, (max-width: 655px) 100vw, 655px" /></figure>



<p class="wp-block-paragraph">There isn&#8217;t much of interest in <code>dreg</code>, however, even though <code>loneferret</code>&#8216;s bash history is empty, there are a couple of interesting files: <code>CompanyPolicy.README</code>, and <code>checksec.sh</code>. Let&#8217;s see what <code>CompanyPolicy.README</code> contains:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="827" height="164" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/Company-Policy-File.png" alt="" class="wp-image-799" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/Company-Policy-File.png 827w, https://alexshomenetwork.com/wp-content/uploads/2025/04/Company-Policy-File-300x59.png 300w, https://alexshomenetwork.com/wp-content/uploads/2025/04/Company-Policy-File-768x152.png 768w" sizes="auto, (max-width: 827px) 100vw, 827px" /></figure>



<p class="wp-block-paragraph">Boom, full sudo privileges to run <code>ht</code>, which is a hex editor. There are a few ways of exploiting this, but we&#8217;ll get to that later. For now, let&#8217;s change our focus to trying to get into <code>loneferret</code>.</p>



<h4 class="wp-block-heading">Brute Forcing Our User&#8217;s SSH Login</h4>



<p class="wp-block-paragraph">As you might have recalled earlier, SSH was open on the VM, so let&#8217;s try using nmap&#8217;s <code>ssh-bruteforce</code> script, adding the users we found to a list, and using good old <code>rockyou.txt</code> as a password list:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="785" height="145" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/SSH-Bruteforce.png" alt="" class="wp-image-800" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/SSH-Bruteforce.png 785w, https://alexshomenetwork.com/wp-content/uploads/2025/04/SSH-Bruteforce-300x55.png 300w, https://alexshomenetwork.com/wp-content/uploads/2025/04/SSH-Bruteforce-768x142.png 768w" sizes="auto, (max-width: 785px) 100vw, 785px" /></figure>



<p class="wp-block-paragraph">After a bit of waiting, we&#8217;ve got ourselves a hit for <code>loneferret</code>:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="710" height="149" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/nmap-Login.png" alt="" class="wp-image-801" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/nmap-Login.png 710w, https://alexshomenetwork.com/wp-content/uploads/2025/04/nmap-Login-300x63.png 300w" sizes="auto, (max-width: 710px) 100vw, 710px" /></figure>



<p class="wp-block-paragraph">Let&#8217;s try SSHing into <code>loneferret</code>, and see what happens:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="863" height="116" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/SSH-Fail.png" alt="" class="wp-image-802" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/SSH-Fail.png 863w, https://alexshomenetwork.com/wp-content/uploads/2025/04/SSH-Fail-300x40.png 300w, https://alexshomenetwork.com/wp-content/uploads/2025/04/SSH-Fail-768x103.png 768w" sizes="auto, (max-width: 863px) 100vw, 863px" /></figure>



<p class="wp-block-paragraph">Unfortunately, the SSH client included with Kali doesn&#8217;t like the ancient OpenSSH server included with our VM, and even after messing around, it still refused to connect. But don&#8217;t worry, I have a workaround.</p>



<p class="wp-block-paragraph">First, install Docker with their convenience script (Or another method described in their <a href="https://docs.docker.com/engine/install/debian/#install-using-the-repository">documentation</a>):</p>



<pre class="wp-block-code"><code>curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh</code></pre>



<p class="wp-block-paragraph">Next, create a Ubuntu 14.04 container, since we can install an SSH client old enough to connect:</p>



<pre class="wp-block-code"><code>sudo docker run --rm -it ubuntu:14.04 bash</code></pre>



<p class="wp-block-paragraph">After it pulls the image and creates the container, your prompt should change to something like this:</p>



<pre class="wp-block-code"><code>root@&lt;random string&gt;:/#</code></pre>



<p class="wp-block-paragraph">From there, run the following command in the container to install <code>openssh-client</code>:</p>



<pre class="wp-block-code"><code>apt update &amp;&amp; apt install -y openssh-client</code></pre>



<p class="wp-block-paragraph">After that, you can now use <code>ssh loneferret@ip-address</code> to connect to the VM:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="678" height="311" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/Docker-SSH.png" alt="" class="wp-image-803" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/Docker-SSH.png 678w, https://alexshomenetwork.com/wp-content/uploads/2025/04/Docker-SSH-300x138.png 300w" sizes="auto, (max-width: 678px) 100vw, 678px" /></figure>



<h4 class="wp-block-heading">Exploiting Sudo Permissions</h4>



<p class="wp-block-paragraph">Now that we&#8217;re logged in as <code>loneferret</code>, let&#8217;s see what sudo permissions we have by running <code>sudo -l</code>:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="555" height="86" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/Sudo-Permissions.png" alt="" class="wp-image-805" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/Sudo-Permissions.png 555w, https://alexshomenetwork.com/wp-content/uploads/2025/04/Sudo-Permissions-300x46.png 300w" sizes="auto, (max-width: 555px) 100vw, 555px" /></figure>



<p class="wp-block-paragraph">It appears that we only have access to <code>ht</code>, and have been explicitly denied access to <code>su</code>. So let&#8217;s open up <code>/etc/sudoers</code> to change that.</p>



<p class="wp-block-paragraph">Before I continue, now is a good time to take a snapshot, because if you break sudo, then you&#8217;re basically screwed (Unless if you want to boot another OS and fix it), so please, take some sort of snapshot or backup before continuing.</p>



<p class="wp-block-paragraph">After opening <code>/etc/sudoers</code> in <code>ht</code>, you&#8217;ll get a crazy looking screen like this:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="995" height="627" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/Hex-Editor.png" alt="" class="wp-image-806" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/Hex-Editor.png 995w, https://alexshomenetwork.com/wp-content/uploads/2025/04/Hex-Editor-300x189.png 300w, https://alexshomenetwork.com/wp-content/uploads/2025/04/Hex-Editor-768x484.png 768w" sizes="auto, (max-width: 995px) 100vw, 995px" /></figure>



<p class="wp-block-paragraph">This is because <code>ht</code> is designed to be a hex editor, and not a text editor. You can still view text files normally by switching modes, but you can&#8217;t edit them. Regardless, I&#8217;ll show you how to safely(ish) edit <code>/etc/sudoers</code> in <code>ht</code> in its hex view.</p>



<p class="wp-block-paragraph">First, press F4 on your keyboard to switch to edit mode. You&#8217;ll probably notice that your arrow keys move around the cursor.</p>



<p class="wp-block-paragraph">Next, press Tab on your keyboard. You will see the cursor switch over to the plaintext part. </p>



<p class="wp-block-paragraph">Next, navigate to the part in the file where it starts with <code>loneferret ALL=NOPASSWD</code>: </p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="137" height="265" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/Sudoers-File.png" alt="" class="wp-image-807" style="width:223px;height:auto"/></figure>



<p class="wp-block-paragraph">Since there&#8217;s a lot going on with no line breaks, it might be difficult to find at first. My cursor in this screenshot is white and indicates where you need to be in the file. </p>



<p class="wp-block-paragraph">Next, and this is an extremely important step to pay attention to, otherwise you&#8217;ll need to revert back to that aforementioned backup/snapshot, type over <code>/usr/local/bin/ht</code> with <code>/bin/bash</code>. Since there&#8217;s no way to delete characters, and <code>ht</code> only lets you replace characters, replace the extra ones with a space, right up until the red ??:</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="139" height="181" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/Sudoers-Edited.png" alt="" class="wp-image-808" style="width:249px;height:auto"/></figure>



<p class="wp-block-paragraph">The text that you overwrote will appear in red. It should look something like my screenshot. If you think you messed up, press F10 to quit without saving, and open it up again.</p>



<p class="wp-block-paragraph">To verify that you edited the file correctly, especially since sudo can be very picky about syntax, press F6 on your keyboard to bring up the mode selection:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="492" height="305" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/Mode-Screen.png" alt="" class="wp-image-809" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/Mode-Screen.png 492w, https://alexshomenetwork.com/wp-content/uploads/2025/04/Mode-Screen-300x186.png 300w" sizes="auto, (max-width: 492px) 100vw, 492px" /></figure>



<p class="wp-block-paragraph">Use your arrow keys to move to text, and press enter. The lines we edited will appear towards the bottom and are a bit hard to spot at first glance (Especially given the poor background/text colors), but they should look like this:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="470" height="72" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/Sudoers-Verification.png" alt="" class="wp-image-810" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/Sudoers-Verification.png 470w, https://alexshomenetwork.com/wp-content/uploads/2025/04/Sudoers-Verification-300x46.png 300w" sizes="auto, (max-width: 470px) 100vw, 470px" /></figure>



<p class="wp-block-paragraph">Press F6 again to bring back the mode screen, then select hex. If it looks right, press F2 to save, and then Press F10 to exit.</p>



<p class="wp-block-paragraph">Next, run <code>sudo -l</code> to verify that your <code>sudoers</code> file syntax is correct:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="499" height="83" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/New-Sudo-Permissions.png" alt="" class="wp-image-811" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/New-Sudo-Permissions.png 499w, https://alexshomenetwork.com/wp-content/uploads/2025/04/New-Sudo-Permissions-300x50.png 300w" sizes="auto, (max-width: 499px) 100vw, 499px" /></figure>



<p class="wp-block-paragraph">If you get a prompt asking for your password and/or you get a syntax error, then it&#8217;s time to use that snapshot you took. If it looks like the above screenshot, then congrats! You&#8217;ve successfully edited <code>/etc/sudoers</code> using a hex editor without breaking it!</p>



<p class="wp-block-paragraph">Now that we can run <code>bash</code> with full root permissions, let&#8217;s try that:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="518" height="163" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/First-Root-Sign.png" alt="" class="wp-image-812" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/First-Root-Sign.png 518w, https://alexshomenetwork.com/wp-content/uploads/2025/04/First-Root-Sign-300x94.png 300w" sizes="auto, (max-width: 518px) 100vw, 518px" /></figure>



<p class="wp-block-paragraph">Success! Now we can navigate to /root and retrieve our congratulations message:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="657" height="288" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/Congrats-Message-1.png" alt="" class="wp-image-815" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/Congrats-Message-1.png 657w, https://alexshomenetwork.com/wp-content/uploads/2025/04/Congrats-Message-1-300x132.png 300w" sizes="auto, (max-width: 657px) 100vw, 657px" /></figure>



<p class="wp-block-paragraph">Congratulations! You can now say that you&#8217;ve hacked a Linux system by simply exploiting a web server (Using the term &#8220;simply&#8221; loosely).</p>



<h3 class="wp-block-heading">But Wait! There&#8217;s More</h3>



<p class="wp-block-paragraph">Since you now have the entire VM in the palm of your hands, we can do a bit of exploring.</p>



<h4 class="wp-block-heading">Maintaining Persistent Access</h4>



<p class="wp-block-paragraph">Any good hacker will want to have persistent access to the machine they just hacked, because what would happen if that security hole was closed? We can simply accomplish this by creating a new user, and in case you didn&#8217;t already discover, the <code>admin</code> group gets full sudo permissions:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="487" height="96" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/Adding-User.png" alt="" class="wp-image-816" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/Adding-User.png 487w, https://alexshomenetwork.com/wp-content/uploads/2025/04/Adding-User-300x59.png 300w" sizes="auto, (max-width: 487px) 100vw, 487px" /></figure>



<p class="wp-block-paragraph">Next, log out of <code>root</code> and <code>loneferret</code>, and try SSHing using your new user:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="669" height="202" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/New-User-Test.png" alt="" class="wp-image-817" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/New-User-Test.png 669w, https://alexshomenetwork.com/wp-content/uploads/2025/04/New-User-Test-300x91.png 300w" sizes="auto, (max-width: 669px) 100vw, 669px" /></figure>



<p class="wp-block-paragraph">Success! Now you&#8217;ve got your own user.</p>



<h5 class="wp-block-heading">Important Note</h5>



<p class="wp-block-paragraph">For whatever reason that I haven&#8217;t bothered to figure out, it seems like the VM will wipe out any newly created users after you shut it down. I&#8217;m not sure if this is a bug or what, but I decided to just simply give <code>loneferret</code> full sudo permissions.</p>



<p class="wp-block-paragraph">Now that we can access all tools that require root, we can now safely edit <code>/etc/sudoers</code> with <code>visudo</code>, so open <code>visudo</code>. If you&#8217;re not root, then make sure to use <code>sudo</code> at the beginning:</p>



<pre class="wp-block-code"><code>EDITOR=/bin/nano visudo</code></pre>



<p class="wp-block-paragraph">Next, where we gave <code>loneferret</code> access to <code>/bin/bash</code>, comment out that line, and add the following line to give <code>loneferret</code> full sudo permissions:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="431" height="73" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/New-Sudoers-Entry-1.png" alt="" class="wp-image-820" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/New-Sudoers-Entry-1.png 431w, https://alexshomenetwork.com/wp-content/uploads/2025/04/New-Sudoers-Entry-1-300x51.png 300w" sizes="auto, (max-width: 431px) 100vw, 431px" /></figure>



<p class="wp-block-paragraph">Your file should look like mine. Since we&#8217;re using <code>visudo</code> to safely edit <code>/etc/sudoers</code>, you don&#8217;t have to worry about bad syntax breaking sudo since <code>visudo</code> verifies it. To verify that <code>loneferret</code> now has full sudo permissions, switch to <code>loneferret</code> with <code>su loneferret</code> (If you&#8217;re not already <code>loneferret</code>), and run <code>sudo -l</code>:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="489" height="83" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/loneferret-Full-Sudo-Permissions.png" alt="" class="wp-image-821" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/loneferret-Full-Sudo-Permissions.png 489w, https://alexshomenetwork.com/wp-content/uploads/2025/04/loneferret-Full-Sudo-Permissions-300x51.png 300w" sizes="auto, (max-width: 489px) 100vw, 489px" /></figure>



<h4 class="wp-block-heading">What About LotusCMS?</h4>



<p class="wp-block-paragraph">Even though we&#8217;re in the VM itself now, we can&#8217;t forget to hack the thing it&#8217;s actually hosting: LotusCMS. After exploring LotusCMS&#8217;s files, I managed to track down the function that generates the admin password, located in <code>/home/www/kioptrix3.com/core/lib/User.php</code>:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="474" height="231" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/Admin-Password-Function.png" alt="" class="wp-image-823" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/Admin-Password-Function.png 474w, https://alexshomenetwork.com/wp-content/uploads/2025/04/Admin-Password-Function-300x146.png 300w" sizes="auto, (max-width: 474px) 100vw, 474px" /></figure>



<p class="wp-block-paragraph">So what it does is it takes the passwords, adds the salt to the end of it, and hashes it with SHA1:</p>



<pre class="wp-block-code"><code>sha1(password.salt)</code></pre>



<p class="wp-block-paragraph">Thankfully Hashcat has a mode for this, so let&#8217;s first add add our password with its salt to a file, and try cracking it with <code>rockyou.txt</code> using <code>best64.rule</code> for our rules:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="812" height="216" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/Cracking-Admin.png" alt="" class="wp-image-824" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/Cracking-Admin.png 812w, https://alexshomenetwork.com/wp-content/uploads/2025/04/Cracking-Admin-300x80.png 300w, https://alexshomenetwork.com/wp-content/uploads/2025/04/Cracking-Admin-768x204.png 768w" sizes="auto, (max-width: 812px) 100vw, 812px" /></figure>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="759" height="383" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/Crack-Results.png" alt="" class="wp-image-825" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/Crack-Results.png 759w, https://alexshomenetwork.com/wp-content/uploads/2025/04/Crack-Results-300x151.png 300w" sizes="auto, (max-width: 759px) 100vw, 759px" /></figure>



<p class="wp-block-paragraph">That was&#8230; extremely fast, even on my crappy lab VM. Regardless, now that we know that the username is <code>admin</code> and the password is <code>Mast3r</code>, let&#8217;s try logging in:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="1023" height="684" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/Random-Redirect.png" alt="" class="wp-image-827" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/Random-Redirect.png 1023w, https://alexshomenetwork.com/wp-content/uploads/2025/04/Random-Redirect-300x201.png 300w, https://alexshomenetwork.com/wp-content/uploads/2025/04/Random-Redirect-768x514.png 768w" sizes="auto, (max-width: 1023px) 100vw, 1023px" /></figure>



<p class="wp-block-paragraph">That&#8217;s&#8230; not supposed to happen. It appears someone bought the domain <code>lotuscms.org</code>, and after doing a bit of debugging with inspect element, they&#8217;re making <code>update.lotuscms.org</code> and <code>news.lotuscms.org</code> redirect to some sketchy ad domains that are being blocked by my DNS servers.</p>



<p class="wp-block-paragraph">Thankfully, you can fix this by SSHing into the LotusCMS VM again, and adding the following lines to /etc/hosts (You need root permissions to edit it):</p>



<pre class="wp-block-code"><code>0.0.0.0    update.lotuscms.org
0.0.0.0    news.lotuscms.org</code></pre>



<p class="wp-block-paragraph">Now you just need to restart your browser (Or open a private session), and let&#8217;s try logging in again. It&#8217;ll take a little bit since it&#8217;ll try contacting those domains and eventually time out:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="783" height="598" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/LotusCMS-Dashboard.png" alt="" class="wp-image-828" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/LotusCMS-Dashboard.png 783w, https://alexshomenetwork.com/wp-content/uploads/2025/04/LotusCMS-Dashboard-300x229.png 300w, https://alexshomenetwork.com/wp-content/uploads/2025/04/LotusCMS-Dashboard-768x587.png 768w" sizes="auto, (max-width: 783px) 100vw, 783px" /></figure>



<p class="wp-block-paragraph">Success! Despite a few warnings from us blocking those domains, it works! We can now navigate the dashboard without worrying about getting redirected to some sketchy domains. Some pages like settings may take a bit to load because it&#8217;ll try contacting those domains again, but regardless, it all works.</p>



<h4 class="wp-block-heading">Gallerific</h4>



<p class="wp-block-paragraph">When we were exploring the root of LotusCMS earlier, you might have noticed a folder named <code>gallery</code>. As it turns out, it&#8217;s yet another service that this server is hosting. Unfortunately, there doesn&#8217;t seem to be any Metasploit modules for it, but regardless, let&#8217;s check it out:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="1022" height="631" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/Broken-Gallery.png" alt="" class="wp-image-829" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/Broken-Gallery.png 1022w, https://alexshomenetwork.com/wp-content/uploads/2025/04/Broken-Gallery-300x185.png 300w, https://alexshomenetwork.com/wp-content/uploads/2025/04/Broken-Gallery-768x474.png 768w" sizes="auto, (max-width: 1022px) 100vw, 1022px" /></figure>



<p class="wp-block-paragraph">That doesn&#8217;t look right. Since it appears that <code>kioptrix3.com</code> is hardcoded in multiple places, it&#8217;s trying to connect to that domain, which doesn&#8217;t exist, but you can fix that by adding <code>kioptrix3.com</code> to your clients <code>/etc/hosts</code> file, replacing the IP address with the actual IP address of the LotusCMS box:</p>



<pre class="wp-block-code"><code>10.1.1.20     kioptrix3.com</code></pre>



<p class="wp-block-paragraph">That&#8217;s a little better now:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="785" height="610" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/Gallery.png" alt="" class="wp-image-830" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/Gallery.png 785w, https://alexshomenetwork.com/wp-content/uploads/2025/04/Gallery-300x233.png 300w, https://alexshomenetwork.com/wp-content/uploads/2025/04/Gallery-768x597.png 768w" sizes="auto, (max-width: 785px) 100vw, 785px" /></figure>



<p class="wp-block-paragraph">There&#8217;s no apparent login button, but we can figure out where the login page is by simply exploring the <code>gallery</code> folder:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="818" height="94" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/Gallery-Root.png" alt="" class="wp-image-831" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/Gallery-Root.png 818w, https://alexshomenetwork.com/wp-content/uploads/2025/04/Gallery-Root-300x34.png 300w, https://alexshomenetwork.com/wp-content/uploads/2025/04/Gallery-Root-768x88.png 768w" sizes="auto, (max-width: 818px) 100vw, 818px" /></figure>



<p class="wp-block-paragraph">Let&#8217;s navigate to <code>http://kioptrix3.com/gallery/gadmin</code> in our browser and see what happens:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="670" height="284" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/Gallerific-Login.png" alt="" class="wp-image-832" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/Gallerific-Login.png 670w, https://alexshomenetwork.com/wp-content/uploads/2025/04/Gallerific-Login-300x127.png 300w" sizes="auto, (max-width: 670px) 100vw, 670px" /></figure>



<p class="wp-block-paragraph">The good news is that we&#8217;ve got ourselves a login page. The bad news is that the credentials for LotusCMS don&#8217;t work on it, so let&#8217;s try getting them.</p>



<h4 class="wp-block-heading">Getting The Login</h4>



<p class="wp-block-paragraph">If you check <code>gconfig.php</code> in <code>gallery</code>, there&#8217;s hardcoded database credentials for a MySQL server:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="511" height="117" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/Gallery-Database-Login.png" alt="" class="wp-image-834" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/Gallery-Database-Login.png 511w, https://alexshomenetwork.com/wp-content/uploads/2025/04/Gallery-Database-Login-300x69.png 300w" sizes="auto, (max-width: 511px) 100vw, 511px" /></figure>



<p class="wp-block-paragraph">Looks like it&#8217;s using the default <code>root</code> user and a password straight out of <code>rockyou.txt</code>, so let&#8217;s log in to phpMyAdmin using those credentials:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="1019" height="545" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/phpMyAdmin-Gallery.png" alt="" class="wp-image-835" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/phpMyAdmin-Gallery.png 1019w, https://alexshomenetwork.com/wp-content/uploads/2025/04/phpMyAdmin-Gallery-300x160.png 300w, https://alexshomenetwork.com/wp-content/uploads/2025/04/phpMyAdmin-Gallery-768x411.png 768w" sizes="auto, (max-width: 1019px) 100vw, 1019px" /></figure>



<p class="wp-block-paragraph">You can also use the <code>mysql</code> command, but what&#8217;s the fun of that when you have phpMyAdmin? Anyway, let&#8217;s explore the <code>gallery</code> database:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="479" height="354" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/Gallery-Database-Tables.png" alt="" class="wp-image-836" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/Gallery-Database-Tables.png 479w, https://alexshomenetwork.com/wp-content/uploads/2025/04/Gallery-Database-Tables-300x222.png 300w" sizes="auto, (max-width: 479px) 100vw, 479px" /></figure>



<p class="wp-block-paragraph">We&#8217;ve got ourselves a user table, so let&#8217;s check it out:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="647" height="428" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/Gallery-Database-Users.png" alt="" class="wp-image-837" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/Gallery-Database-Users.png 647w, https://alexshomenetwork.com/wp-content/uploads/2025/04/Gallery-Database-Users-300x198.png 300w" sizes="auto, (max-width: 647px) 100vw, 647px" /></figure>



<p class="wp-block-paragraph">Sweet! The login is stored in plaintext, so we don&#8217;t need to worry about cracking it. Let&#8217;s try logging in with those credentials:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="1021" height="611" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/Gallerific-Dashboard.png" alt="" class="wp-image-838" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/Gallerific-Dashboard.png 1021w, https://alexshomenetwork.com/wp-content/uploads/2025/04/Gallerific-Dashboard-300x180.png 300w, https://alexshomenetwork.com/wp-content/uploads/2025/04/Gallerific-Dashboard-768x460.png 768w" sizes="auto, (max-width: 1021px) 100vw, 1021px" /></figure>



<p class="wp-block-paragraph">We&#8217;ve successfully logged in! Not only do we have full root access to our VM, but now we have full access to all of the services running on it.</p>



<h4 class="wp-block-heading">phpMyAdmin?</h4>



<p class="wp-block-paragraph">As I was exploring the VM, I happened to notice something in <code>/etc/phpmyadmin</code>:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="844" height="98" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/phpMyAdmin-htpasswd.setup_.png" alt="" class="wp-image-839" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/phpMyAdmin-htpasswd.setup_.png 844w, https://alexshomenetwork.com/wp-content/uploads/2025/04/phpMyAdmin-htpasswd.setup_-300x35.png 300w, https://alexshomenetwork.com/wp-content/uploads/2025/04/phpMyAdmin-htpasswd.setup_-768x89.png 768w" sizes="auto, (max-width: 844px) 100vw, 844px" /></figure>



<p class="wp-block-paragraph">There was a file named <code>htpasswd.setup</code> containing a user named <code>admin</code> with no password, so I tried logging in with it:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="989" height="474" src="https://alexshomenetwork.com/wp-content/uploads/2025/04/phpMyAdmin-Admin.png" alt="" class="wp-image-840" srcset="https://alexshomenetwork.com/wp-content/uploads/2025/04/phpMyAdmin-Admin.png 989w, https://alexshomenetwork.com/wp-content/uploads/2025/04/phpMyAdmin-Admin-300x144.png 300w, https://alexshomenetwork.com/wp-content/uploads/2025/04/phpMyAdmin-Admin-768x368.png 768w" sizes="auto, (max-width: 989px) 100vw, 989px" /></figure>



<p class="wp-block-paragraph">Which turns out to be yet another valid login. Despite this, there didn&#8217;t appear to be anything interesting. Regardless, it still opens up another attack vector that I&#8217;m not going to go over, mainly because of a lack of time, and frankly this post is long enough as it is.</p>



<h3 class="wp-block-heading">Conclusion</h3>



<p class="wp-block-paragraph">So that&#8217;s how I managed to hack into an old LotusCMS box, which was actually a lot of fun, and I plan on doing more of this in the future. I&#8217;m not sure if I&#8217;ll blog about similar stuff like this in the future, but I might, especially given my infrequency of posts (This was posted over a year after my last post, after all). This was also written on short notice, and even though it&#8217;s very long, clocking in at just shy of 3k words, I&#8217;m still very happy with the result of it. I promise I will try blogging more frequently, but I can&#8217;t guarantee anything.</p>



<p class="wp-block-paragraph">In case you&#8217;re wondering, no, unfortunately I was not able to crack the root password, which doesn&#8217;t matter much anyway since we have full root access to the VM, and can easily change it.</p>
<p>The post <a href="https://alexshomenetwork.com/hacking-an-old-lotuscms-box/">Hacking an Old LotusCMS Box</a> appeared first on <a href="https://alexshomenetwork.com">Alex&#039;s Home Network</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://alexshomenetwork.com/hacking-an-old-lotuscms-box/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Running a Linux Desktop Environment in Your Web Browser</title>
		<link>https://alexshomenetwork.com/linux-desktop-in-browser/</link>
					<comments>https://alexshomenetwork.com/linux-desktop-in-browser/#comments</comments>
		
		<dc:creator><![CDATA[Alex]]></dc:creator>
		<pubDate>Mon, 25 Dec 2023 22:20:07 +0000</pubDate>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Self-Hosting]]></category>
		<guid isPermaLink="false">https://alexshomenetwork.com/?p=734</guid>

					<description><![CDATA[<p>In this post, I&#8217;ll be showing you how to run a Linux desktop environment inside of your web browser. The method that I will be showing is similar to Webtop and other similar projects, but the main difference is that you don&#8217;t need to have Docker installed, which reduces overhead. Unlike a typical VNC solution,<a class="more-link" href="https://alexshomenetwork.com/linux-desktop-in-browser/">Continue reading <span class="screen-reader-text">"Running a Linux Desktop Environment in Your Web Browser"</span></a></p>
<p>The post <a href="https://alexshomenetwork.com/linux-desktop-in-browser/">Running a Linux Desktop Environment in Your Web Browser</a> appeared first on <a href="https://alexshomenetwork.com">Alex&#039;s Home Network</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">In this post, I&#8217;ll be showing you how to run a Linux desktop environment inside of your web browser. The method that I will be showing is similar to <a href="https://github.com/linuxserver/docker-webtop" target="_blank" rel="noreferrer noopener">Webtop</a> and other similar projects, but the main difference is that you don&#8217;t need to have Docker installed, which reduces overhead. Unlike a typical VNC solution, you can access it from more devices as you don&#8217;t need to have a VNC client installed.</p>



<p class="wp-block-paragraph">In order for this to work, there are three main elements: Your desktop environment, <code>Xvnc</code> acting as a VNC server, and KasmVNC acting as a VNC client. <code>Xvnc</code> ties everything together by not only acting as a virtual display for <code>Xorg</code>, but also acting as a VNC server, which is then used by KasmVNC to display your desktop environment inside of your web browser. You can use noVNC instead of KasmVNC because it adheres to the VNC standard unlike KasmVNC (Allows you to use traditional VNC clients), but I prefer KasmVNC because it&#8217;s easier to setup, it&#8217;s better documented, and it seems to work better in my experience.</p>



<h3 class="wp-block-heading">Prerequisites</h3>



<ul class="wp-block-list">
<li>An up to date Debian 11 or Debian 12 host (I&#8217;ll be using Debian 12).</li>



<li>KasmVNC recommends an up to date Chromium based web browser (All of the popular ones should work), or Firefox. Safari is unsupported due to it being incompatible with their authentication system.</li>
</ul>



<p class="wp-block-paragraph">Unfortunately, from what I can tell after doing some research, KasmVNC and noVNC don&#8217;t seem to have native support for audio, which seems to be due to a limitation of the VNC protocol. If you need to use audio, you&#8217;ll most likely need to stick with Webtop, setup a <a href="https://www.kasmweb.com/">Kasm server</a> (Same people that develop KasmVNC), or find a workaround.</p>



<h3 class="wp-block-heading">Installing a Desktop Environment</h3>



<p class="wp-block-paragraph">The first step is to install a desktop environment of your choice. KasmVNC should work with any desktop environment or window manager, but it&#8217;s preconfigured for Cinnamon, Mate, LXDE, LXQT, KDE, Gnome, and XFCE out of the box. Other desktop environments may require some additional configuration.</p>



<p class="wp-block-paragraph">I will be using XFCE throughout this post, so to install <code>Xorg</code> and a minimal XFCE installation, run the following command:</p>



<pre class="wp-block-code"><code>sudo apt install --no-install-recommends xfce4 xorg policykit-1 xfce4-power-manager xfce4-terminal</code></pre>



<p class="wp-block-paragraph">The package <code>xfce4-terminal</code> is not needed if you&#8217;re going to use a different terminal. You can also install the <code>xfce4-goodies</code> package to install many of the packages typically included with an XFCE installation, or look through <a href="https://packages.debian.org/bookworm/xfce4-goodies" target="_blank" rel="noreferrer noopener">what packages</a> it includes to pick out the ones that you want.</p>



<p class="wp-block-paragraph">After your desktop environment has finished installing, it&#8217;s time to move on to the VNC side of things.</p>



<h3 class="wp-block-heading">Installing KasmVNC</h3>



<p class="wp-block-paragraph">First install. <code>wget</code> so that way you can download the package for KasmVNC:</p>



<pre class="wp-block-code"><code>sudo apt install wget</code></pre>



<p class="wp-block-paragraph">Next, navigate to the releases page on their GitHub (<a href="https://github.com/kasmtech/KasmVNC/releases" target="_blank" rel="noreferrer noopener">Found Here</a>), and under Assets, copy the link to download the package appropriate for your Debian version and architecture, and use <code>wget</code> to download it (I would recommend saving it in <code>/tmp</code> so it get automatically deleted). The command shown below is what I ran since I&#8217;m running Debian 12 (Bookworm) on a 64bit system:</p>



<pre class="wp-block-code"><code>wget https://github.com/kasmtech/KasmVNC/releases/download/v1.2.0/kasmvncserver_bookworm_1.2.0_amd64.deb</code></pre>



<p class="wp-block-paragraph">If you&#8217;re running Debian 11, replace <code>bookworm</code> with <code>bullseye</code>. If your host has an ARM processor, replace <code>amd64</code> with <code>arm64</code>.</p>



<p class="wp-block-paragraph">Next, navigate to where you saved the package, and run the following command to install it:</p>



<pre class="wp-block-code"><code>sudo apt install ./kasmvncserver_*.deb</code></pre>



<p class="wp-block-paragraph">Next, run the following command to create the ssl-cert group and add yourself to it:</p>



<pre class="wp-block-code"><code>sudo addgroup $USER ssl-cert</code></pre>



<p class="wp-block-paragraph">If you get an error that looks something like this:</p>



<pre class="wp-block-code"><code>addgroup: addgroup with two arguments is an unspecified operation.</code></pre>



<p class="wp-block-paragraph">Run the following command instead:</p>



<pre class="wp-block-code"><code>sudo usermod -aG ssl-cert $USER</code></pre>



<p class="wp-block-paragraph">After running one of the above commands, log out and log back in again. Run the <code>id</code> command to verify that you&#8217;re apart of the <code>ssl-cert</code> group. For example, this is what it looks like with me:</p>



<pre class="wp-block-code"><code>alex@wp-blog:~$ id
uid=1000(alex) gid=1000(alex) groups=1000(alex),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),100(users),106(netdev),109(<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">ssl-cert</mark>)</code></pre>



<p class="wp-block-paragraph">After that, run the <code>vncserver</code> command, which will prompt you to select a desktop environment, and create a user. If you&#8217;re not using a desktop environment that KasmVNC is preconfigured to work with, you may need to select the option to manually edit <code>xstartup</code>. Consult your desktop environment&#8217;s documentation for more information.</p>



<p class="wp-block-paragraph">After you have went through all of the prompts, you should see a message that looks something like this:</p>



<pre class="wp-block-code"><code>New 'wp-blog:1 (alex)' desktop is wp-blog:1

Users configured:
alex (can use keyboard and mouse)

Log file is /home/alex/.vnc/wp-blog:1.log

Starting applications specified in /home/alex/.vnc/xstartup

Paste this url in your browser:
https:&#47;&#47;127.0.1.1:8444</code></pre>



<p class="wp-block-paragraph">Type in <code>https://host-ip-address:8444</code> into your web browser, and after bypassing the SSL certificate warnings and logging in, you should now be able to see your desktop environment:</p>



<figure class="wp-block-image size-large is-style-default"><img loading="lazy" decoding="async" width="1024" height="562" src="https://alexshomenetwork.com/wp-content/uploads/2023/12/Screenshot-2023-12-21-at-1.24.34 PM-1024x562.png" alt="" class="wp-image-738" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/12/Screenshot-2023-12-21-at-1.24.34 PM-1024x562.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2023/12/Screenshot-2023-12-21-at-1.24.34 PM-300x165.png 300w, https://alexshomenetwork.com/wp-content/uploads/2023/12/Screenshot-2023-12-21-at-1.24.34 PM-768x422.png 768w, https://alexshomenetwork.com/wp-content/uploads/2023/12/Screenshot-2023-12-21-at-1.24.34 PM-1536x843.png 1536w, https://alexshomenetwork.com/wp-content/uploads/2023/12/Screenshot-2023-12-21-at-1.24.34 PM-2048x1124.png 2048w, https://alexshomenetwork.com/wp-content/uploads/2023/12/Screenshot-2023-12-21-at-1.24.34 PM-1568x861.png 1568w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<h4 class="wp-block-heading">Configuring Policykit</h4>



<p class="wp-block-paragraph">As you were playing around with your desktop environment, you might have noticed a problem:</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="264" height="278" src="https://alexshomenetwork.com/wp-content/uploads/2023/12/Screenshot-2023-12-21-at-1.33.57 PM.png" alt="" class="wp-image-740" style="width:167px;height:auto"/></figure>



<p class="wp-block-paragraph">As you can see, some of the buttons are grayed out and are unclickable. At least in the case of XFCE, this issue is due to the fact that Policykit isn&#8217;t configured out of the box, so we have to configure it ourselves.</p>



<p class="wp-block-paragraph">First, create the directory to house the Policykit rules (Assuming it doesn&#8217;t already exist), and set the permissions accordingly:</p>



<pre class="wp-block-code"><code>sudo mkdir /etc/polkit-1/rules.d
sudo chmod 755 /etc/polkit-1/rules.d</code></pre>



<p class="wp-block-paragraph">Next, create a file named <code>85-reboot.rules</code> inside of the <code>/etc/polkit-1/rules.d</code> directory, and add the following contents:</p>



<pre class="wp-block-code"><code>polkit.addRule(function(action, subject) {
    if (action.id == "org.freedesktop.login1.reboot" &amp;&amp;
        subject.isInGroup("users")) {
        return polkit.Result.YES;
    }
});</code></pre>



<p class="wp-block-paragraph">Next, create another file named <code>89-power-off.rules</code> in the same directory, and add the following contents:</p>



<pre class="wp-block-code"><code>polkit.addRule(function(action, subject) {
    if (action.id == "org.freedesktop.login1.power-off" &amp;&amp;
        subject.isInGroup("users")) {
        return polkit.Result.YES;
    }
});</code></pre>



<p class="wp-block-paragraph">After creating both files, set the permissions accordingly:</p>



<pre class="wp-block-code"><code>sudo chmod 644 /etc/polkit-1/rules.d/85-reboot.rules
sudo chmod 644 /etc/polkit-1/rules.d/89-power-off.rules</code></pre>



<p class="wp-block-paragraph">Next, open <code>/usr/share/polkit-1/actions/org.freedesktop.login1.policy</code> in a text editor and look for the below lines, then change <code>&lt;allow_any>auth_admin_keep&lt;/allow_any></code> to <code>&lt;allow_any>yes&lt;/allow_any></code>:</p>



<pre class="wp-block-code"><code>&lt;action id="org.freedesktop.login1.reboot"&gt;
                &lt;description gettext-domain="systemd"&gt;Reboot the system&lt;/descri&gt;
                &lt;message gettext-domain="systemd"&gt;Authentication is required to&gt;
                &lt;defaults&gt;
                        <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">&lt;allow_any&gt;yes&lt;/allow_any&gt;</mark>
                        &lt;allow_inactive&gt;auth_admin_keep&lt;/allow_inactive&gt;
                        &lt;allow_active&gt;yes&lt;/allow_active&gt;
                &lt;/defaults&gt;
                &lt;annotate key="org.freedesktop.policykit.imply"&gt;org.freedesktop&gt;
        &lt;/action&gt;</code></pre>



<p class="wp-block-paragraph">Next, look for the below lines in that same file, and also change <code>&lt;allow_any>auth_admin_keep&lt;/allow_any></code> to <code>&lt;allow_any>yes&lt;/allow_any></code>:</p>



<pre class="wp-block-code"><code>&lt;action id="org.freedesktop.login1.power-off"&gt;
                &lt;description gettext-domain="systemd"&gt;Power off the system&lt;/des&gt;
                &lt;message gettext-domain="systemd"&gt;Authentication is required to&gt;
                &lt;defaults&gt;
                        <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">&lt;allow_any&gt;yes&lt;/allow_any&gt;</mark>
                        &lt;allow_inactive&gt;auth_admin_keep&lt;/allow_inactive&gt;
                        &lt;allow_active&gt;yes&lt;/allow_active&gt;
                &lt;/defaults&gt;
                &lt;annotate key="org.freedesktop.policykit.imply"&gt;org.freedesktop&gt;
        &lt;/action&gt;</code></pre>



<p class="wp-block-paragraph">After rebooting and running the <code>vncserver</code> command again, you should now be able to shut down or reboot from your desktop environment. The process for configuring rules for stuff like suspending is basically identical. The only difference is that you&#8217;ll have to change <code>(action.id == "org.freedesktop.login1.power-off"</code> to the appropriate rule in the <code>.rules</code> file, and look for the appropriate rule in <code>/usr/share/polkit-1/actions/org.freedesktop.login1.policy</code>.</p>



<h4 class="wp-block-heading">Systemd Service</h4>



<p class="wp-block-paragraph">As you might have noticed, everytime you reboot your host, you have to log in and run the <code>vncserver</code> command to start KasmVNC. This isn&#8217;t a big deal, but it&#8217;s a little annoying. </p>



<p class="wp-block-paragraph">First, create a file under <code>/etc/systemd/system</code> and name it <code>kasmvnc.service</code>. After creating it, add the following contents, replacing <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">yourusername</mark></code> with the user that you run KasmVNC as:</p>



<pre class="wp-block-code"><code>&#91;Unit]
Description=KasmVNC Service
After=network.target

&#91;Service]
Type=simple
User=<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">yourusername</mark>
Group=ssl-cert
ExecStart=vncserver -fg
Restart=on-success
RestartSec=5

&#91;Install]
WantedBy=default.target</code></pre>



<p class="wp-block-paragraph">To provide a quick explanation of what you&#8217;re looking at, <code>ExecStart=vncserver -fg</code> makes the <code>vncserver</code> command run in the foreground, which prevents the service from immediately stopping and killing KasmVNC. Logging out through your desktop environment will exit KasmVNC and also kill the service, so <code>Restart=on-success</code> and <code>RestartSec=5</code> will automatically restart the service after 5 seconds. The <code>User</code> and <code>Group</code> options determine what user and group runs KasmVNC.</p>



<p class="wp-block-paragraph">After creating the service, reload Systemd&#8217;s services into memory:</p>



<pre class="wp-block-code"><code>sudo systemctl daemon-reload</code></pre>



<p class="wp-block-paragraph">Then start and enable the KasmVNC service you just created:</p>



<pre class="wp-block-code"><code>sudo systemctl enable --now kasmvnc.service</code></pre>



<p class="wp-block-paragraph">After rebooting, you should now be able to access KasmVNC without logging in and running the <code>vncserver</code> command. </p>



<p class="wp-block-paragraph">If you get an error message that looks like this (Happens on XFCE at least):</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="572" height="114" src="https://alexshomenetwork.com/wp-content/uploads/2023/12/Screenshot-2023-12-22-at-10.39.43 AM.png" alt="" class="wp-image-742" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/12/Screenshot-2023-12-22-at-10.39.43 AM.png 572w, https://alexshomenetwork.com/wp-content/uploads/2023/12/Screenshot-2023-12-22-at-10.39.43 AM-300x60.png 300w" sizes="auto, (max-width: 572px) 100vw, 572px" /></figure>



<p class="wp-block-paragraph">You&#8217;ll need to install the <code>dbus-x11</code> package:</p>



<pre class="wp-block-code"><code>sudo apt install dbus-x11</code></pre>



<p class="wp-block-paragraph">After rebooting, you should now be able to access KasmVNC with no problems.</p>



<h3 class="wp-block-heading">Optional: Reminder for Forgetful Folks</h3>



<p class="wp-block-paragraph">If you&#8217;re a more forgetful person like me, then you might forget that you have KasmVNC installed since there&#8217;s no indication on your host&#8217;s console that you have it installed. Thankfully, it&#8217;s easy to fix this problem.</p>



<h4 class="wp-block-heading">Editing /etc/motd</h4>



<p class="wp-block-paragraph">The much simpler method is simply opening up <code>/etc/motd</code> in your favorite text editor, and changing the default message to whatever you choose. This message is displayed everytime a user logs in to the host. Here&#8217;s what mine looks like for example:</p>



<pre class="wp-block-code"><code>Linux wp-blog 6.1.0-16-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.67-1 (2023-12-12) x86_64

Hey Dumbass,

You forgot (again) that the desktop is only accessible through KasmVNC.
The URL is https://ip-address:8444
Last login: Fri Dec 22 16:20:11 2023 from 10.0.1.69
alex@wp-blog:~$ </code></pre>



<p class="wp-block-paragraph">Despite this being a nice and simple solution, the only problem is that you&#8217;ll only see this message if you try to log in.</p>



<h4 class="wp-block-heading">A More Visually Pleasing Method</h4>



<p class="wp-block-paragraph">Unlike the last method which will only show a text-based message after logging in, this method will show a message in the form of an image, and it doesn&#8217;t require a user to log in. There&#8217;s probably a more efficient method, but the method that I like using and I will be showing you is using Openbox to display an image of your choice.</p>



<p class="wp-block-paragraph">The first step is to install Openbox along with the other packages that we&#8217;ll need:</p>



<pre class="wp-block-code"><code>sudo apt install --no-install-recommends openbox lightdm unclutter feh</code></pre>



<p class="wp-block-paragraph">Enable the LightDM service:</p>



<pre class="wp-block-code"><code>sudo systemctl enable lightdm</code></pre>



<p class="wp-block-paragraph">After rebooting your host, you should see LightDM come up and ask for your login. In the top right corner, click the page icon with a wrench, and make sure that Openbox is selected (As shown in the screenshot):</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="148" height="88" src="https://alexshomenetwork.com/wp-content/uploads/2023/12/Screenshot-2023-12-24-at-2.45.07 PM.png" alt="" class="wp-image-748" style="width:244px;height:auto"/></figure>



<p class="wp-block-paragraph">Enter your login information, and after clicking Log In, you should now see a black screen with a mouse cursor. Right click to access the Openbox menu, and if you&#8217;re not using SSH (Which I highly recommend that you do), locate your terminal under the Applications menu.</p>



<p class="wp-block-paragraph">After accessing your terminal, open <code>/etc/lightdm/lightdm.conf</code> in a text editor of your choice. Locate the section that starts with <code>[Seat:*]</code>, and locate the lines <code>autologin-user</code> and <code>autologin-user-timeout</code> towards the bottom. To provide a visual, you should see the following lines:</p>



<pre class="wp-block-code"><code>&#91;Seat:*]
#Rest of output not shown
#autologin-guest=false
#autologin-user=
#autologin-user-timeout=0
#autologin-in-background=false
#Rest of output not shown</code></pre>



<p class="wp-block-paragraph">Uncomment the lines <code>autologin-user</code> and <code>autologin-user-timeout</code>, and replace <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">yourusername</mark> with your name after <code>autologin-user</code>:</p>



<pre class="wp-block-code"><code>&#91;Seat:*]
#Rest of output not shown
#autologin-guest=false
autologin-user=<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">yourusername</mark>
autologin-user-timeout=0
#autologin-in-background=false
#Rest of output not shown</code></pre>



<p class="wp-block-paragraph">Notice how the lines <code>autologin-user</code> and <code>autologin-user-timeout</code> have been commented out. Since LightDM is automatically logging in to this user, you might want to create a separate user with little to no privileges. This is because someone with physical access to your host can access everything that your autologin user has access to. We&#8217;ll address this later by locking down Openbox.</p>



<p class="wp-block-paragraph">Next, create the image with the message that you want displayed, and upload it to your host. If you need a little inspiration, here&#8217;s what I use on one of my VM&#8217;s:</p>



<figure class="wp-block-image size-large is-resized"><img loading="lazy" decoding="async" width="1024" height="640" src="https://alexshomenetwork.com/wp-content/uploads/2023/12/Background-1024x640.png" alt="" class="wp-image-749" style="width:781px;height:auto" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/12/Background-1024x640.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2023/12/Background-300x188.png 300w, https://alexshomenetwork.com/wp-content/uploads/2023/12/Background-768x480.png 768w, https://alexshomenetwork.com/wp-content/uploads/2023/12/Background.png 1280w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">Next, verify that your image displays correctly by setting it as the wallpaper:</p>



<pre class="wp-block-code"><code>feh --bg-scale <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">/path/to/image</mark></code></pre>



<p class="wp-block-paragraph">Since it&#8217;ll reset when you reboot your host, open <code>/etc/xdg/openbox/autostart</code> in a text editor, and add the following lines at the end:</p>



<pre class="wp-block-code"><code>feh --bg-scale <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">/path/to/image</mark> &amp; unclutter -display :0 -root -idle 0</code></pre>



<p class="wp-block-paragraph">The <code>unclutter</code> command will automatically hide the mouse cursor. After rebooting your host, you should see your image come up.</p>



<p class="wp-block-paragraph">If your screen keeps blanking, install the <code>x11-xserver-utils</code> package and add the following lines instead:</p>



<pre class="wp-block-code"><code>feh --bg-scale <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">/path/to/image</mark> &amp; unclutter -display :0 -root -idle 0 &amp; xset -display :0 -dpms s off</code></pre>



<h5 class="wp-block-heading">Locking Down Openbox</h5>



<p class="wp-block-paragraph">Since the right click menu along with all of the keyboard shortcuts still work, we&#8217;ll need to disable all of this to help secure our autologin user. Fortunately, it&#8217;s easy to lock Openbox down.</p>



<p class="wp-block-paragraph">First, create a directory for Openbox inside of your home folder:</p>



<pre class="wp-block-code"><code>mkdir $HOME/.config/openbox/</code></pre>



<p class="wp-block-paragraph">Next, copy the default configuration file to the directory that you just created:</p>



<pre class="wp-block-code"><code>cp /etc/xdg/openbox/rc.xml $HOME/.config/openbox/rc.xml</code></pre>



<p class="wp-block-paragraph">Next, comment out or remove everything inside of <code>&lt;dock></code>, <code>&lt;keyboard></code>, <code>&lt;mouse></code>, <code>&lt;menu></code>, and <code>&lt;applications></code>. For your convenience, here&#8217;s an Openbox configuration file with everything removed for you that you should be able to use:</p>



<pre class="wp-block-code"><code>&lt;?xml version="1.0" encoding="UTF-8"?>

&lt;openbox_config xmlns="http://openbox.org/3.4/rc"
		xmlns:xi="http://www.w3.org/2001/XInclude">

&lt;resistance>
  &lt;strength>10&lt;/strength>
  &lt;screen_edge_strength>20&lt;/screen_edge_strength>
&lt;/resistance>

&lt;focus>
  &lt;focusNew>yes&lt;/focusNew>
  &lt;followMouse>no&lt;/followMouse>
  &lt;focusLast>yes&lt;/focusLast>
  &lt;underMouse>no&lt;/underMouse>
  &lt;focusDelay>200&lt;/focusDelay>
  &lt;raiseOnFocus>no&lt;/raiseOnFocus>
&lt;/focus>

&lt;placement>
  &lt;policy>Smart&lt;/policy>
  &lt;center>yes&lt;/center>
  &lt;monitor>Primary&lt;/monitor>
  &lt;primaryMonitor>1&lt;/primaryMonitor>
&lt;/placement>

&lt;theme>
  &lt;name>Clearlooks&lt;/name>
  &lt;titleLayout>NLIMC&lt;/titleLayout>
  &lt;keepBorder>yes&lt;/keepBorder>
  &lt;animateIconify>yes&lt;/animateIconify>
  &lt;font place="ActiveWindow">
    &lt;name>sans&lt;/name>
    &lt;size>8&lt;/size>
    &lt;weight>bold&lt;/weight>
    &lt;slant>normal&lt;/slant>
  &lt;/font>
  &lt;font place="InactiveWindow">
    &lt;name>sans&lt;/name>
    &lt;size>8&lt;/size>
    &lt;weight>bold&lt;/weight>
    &lt;slant>normal&lt;/slant>
  &lt;/font>
  &lt;font place="MenuHeader">
    &lt;name>sans&lt;/name>
    &lt;size>9&lt;/size>
    &lt;weight>normal&lt;/weight>
    &lt;slant>normal&lt;/slant>
  &lt;/font>
  &lt;font place="MenuItem">
    &lt;name>sans&lt;/name>
    &lt;size>9&lt;/size>
    &lt;weight>normal&lt;/weight>
    &lt;slant>normal&lt;/slant>
  &lt;/font>
  &lt;font place="ActiveOnScreenDisplay">
    &lt;name>sans&lt;/name>
    &lt;size>9&lt;/size>
    &lt;weight>bold&lt;/weight>
    &lt;slant>normal&lt;/slant>
  &lt;/font>
  &lt;font place="InactiveOnScreenDisplay">
    &lt;name>sans&lt;/name>
    &lt;size>9&lt;/size>
    &lt;weight>bold&lt;/weight>
    &lt;slant>normal&lt;/slant>
  &lt;/font>
&lt;/theme>

&lt;desktops>
  &lt;number>4&lt;/number>
  &lt;firstdesk>1&lt;/firstdesk>
  &lt;names>
    &lt;name>desktop 1&lt;/name>
    &lt;name>desktop 2&lt;/name>
  &lt;/names>
  &lt;popupTime>875&lt;/popupTime>
&lt;/desktops>

&lt;resize>
  &lt;drawContents>yes&lt;/drawContents>
  &lt;popupShow>Nonpixel&lt;/popupShow>
  &lt;popupPosition>Center&lt;/popupPosition>
  &lt;popupFixedPosition>
    &lt;x>10&lt;/x>
    &lt;y>10&lt;/y>
  &lt;/popupFixedPosition>
&lt;/resize>

&lt;margins>
  &lt;top>0&lt;/top>
  &lt;bottom>0&lt;/bottom>
  &lt;left>0&lt;/left>
  &lt;right>0&lt;/right>
&lt;/margins>

&lt;/openbox_config></code></pre>



<p class="wp-block-paragraph">Finally, save the file, and reboot your host. You should now no longer be able to access the right click menu or use any of the keyboard shortcuts.</p>



<h3 class="wp-block-heading">Conclusion</h3>



<p class="wp-block-paragraph">After reading this post, you should now have a mostly working desktop environment within your web browser. Unfortunately, both KasmVNC and noVNC don&#8217;t seem to have any support for audio. Audio seems to be planned for KasmVNC, but it doesn&#8217;t appear to be for noVNC. There seems to be some workarounds, but I didn&#8217;t cover them in this post because it was getting long enough, and I felt like it was somewhat outside of the scope of it. </p>



<p class="wp-block-paragraph">If you have an questions, comments, or complaints, feel free to leave a comment below. I&#8217;ll try my best to answer any questions that you might have.</p>



<h3 class="wp-block-heading">References:</h3>



<p class="wp-block-paragraph">KasmVNC Documentation: <a href="https://www.kasmweb.com/kasmvnc/docs/1.0.0/index.html" target="_blank" rel="noreferrer noopener">https://www.kasmweb.com/kasmvnc/docs/1.0.0/index.html</a></p>



<p class="wp-block-paragraph">XFCE Policykit Configuration: <a href="https://wiki.debian.org/Xfce#Suspend_and_backlight_issues" target="_blank" rel="noreferrer noopener">https://wiki.debian.org/Xfce#Suspend_and_backlight_issues</a></p>



<p class="wp-block-paragraph">Setting a Wallpaper on Openbox: <a href="https://wiki.debian.org/Openbox#Wallpapers" target="_blank" rel="noreferrer noopener">https://wiki.debian.org/Openbox#Wallpapers</a></p>



<p class="wp-block-paragraph">Enabling Autologin for LightDM: <a href="https://wiki.debian.org/LightDM#Enable_autologin" target="_blank" rel="noreferrer noopener">https://wiki.debian.org/LightDM#Enable_autologin</a></p>
<p>The post <a href="https://alexshomenetwork.com/linux-desktop-in-browser/">Running a Linux Desktop Environment in Your Web Browser</a> appeared first on <a href="https://alexshomenetwork.com">Alex&#039;s Home Network</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://alexshomenetwork.com/linux-desktop-in-browser/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
			</item>
		<item>
		<title>Installing an *arr Stack on Proxmox</title>
		<link>https://alexshomenetwork.com/installing-an-arr-stack-on-proxmox/</link>
					<comments>https://alexshomenetwork.com/installing-an-arr-stack-on-proxmox/#comments</comments>
		
		<dc:creator><![CDATA[Alex]]></dc:creator>
		<pubDate>Mon, 10 Jul 2023 19:33:18 +0000</pubDate>
				<category><![CDATA[Self-Hosting]]></category>
		<guid isPermaLink="false">https://alexshomenetwork.com/?p=670</guid>

					<description><![CDATA[<p>In this post, I&#8217;ll be showing you how to install an *arr stack on a Proxmox host. It will contain qBittorrent with a VPN, Sonarr, and Jackett. This particular *arr stack will allow you to download your favorite TV shows and store them in a format that can be viewed by something like Jellyfin, and<a class="more-link" href="https://alexshomenetwork.com/installing-an-arr-stack-on-proxmox/">Continue reading <span class="screen-reader-text">"Installing an *arr Stack on Proxmox"</span></a></p>
<p>The post <a href="https://alexshomenetwork.com/installing-an-arr-stack-on-proxmox/">Installing an *arr Stack on Proxmox</a> appeared first on <a href="https://alexshomenetwork.com">Alex&#039;s Home Network</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">In this post, I&#8217;ll be showing you how to install an *arr stack on a Proxmox host. It will contain qBittorrent with a VPN, Sonarr, and Jackett. This particular *arr stack will allow you to download your favorite TV shows and store them in a format that can be viewed by something like Jellyfin, and even automatically look for new episodes. You can also install other *arr apps that look for different types of content, but that&#8217;s outside of the scope of this post.</p>



<p class="wp-block-paragraph">Regardless of your choice of apps, these steps should be pretty similar. You can also choose to have some of these apps share the same VM or container. You could even run everything in Docker containers, but that&#8217;s outside of the scope of this post, and kinda defeats the purpose of it.</p>



<h3 class="wp-block-heading">Prerequisites</h3>



<p class="wp-block-paragraph">The only things that you will need are a Proxmox host (Obviously), some basic knowledge of using Proxmox, and optionally but highly recommended a VPN that&#8217;s compatible with OpenVPN.</p>



<p class="wp-block-paragraph">You should also plan on what services should share a VM or container, or if everything should be separate. I personally have Jackett and my *arr apps (Only Sonarr in my case) share a single container, and qBittorrent with my VPN share a single VM. Regardless of what you decide, the main issue that you need to worry about is ensuring that nothing uses the same port. Besides that, there shouldn&#8217;t be any concerns of conflicts.</p>



<h3 class="wp-block-heading">qBittorrent with OpenVPN</h3>



<p class="wp-block-paragraph">You don&#8217;t need to run qBittorrent with a VPN, but chances are for the majority of the people reading this, I would highly recommend running one. Not only will running one improve the privacy and security of your setup, but you also won&#8217;t need to worry about your ISP sending you letters or cutting off your service.</p>



<h4 class="wp-block-heading">Container Setup</h4>



<p class="wp-block-paragraph">If you plan on running qBittorrent inside of an LXC container, there&#8217;s a few steps that you have to take while creating it. The first step is if you&#8217;re storing your downloaded content on a separate machine, uncheck &#8220;Unprivileged container&#8221;. This will allow you to enable the needed features for transferring files over the network:</p>



<figure class="wp-block-image size-large is-resized"><img loading="lazy" decoding="async" src="https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-02-at-1.47.31-PM-1024x721.png" alt="" class="wp-image-675" width="512" height="361" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-02-at-1.47.31-PM-1024x721.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-02-at-1.47.31-PM-300x211.png 300w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-02-at-1.47.31-PM-768x541.png 768w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-02-at-1.47.31-PM.png 1468w" sizes="auto, (max-width: 512px) 100vw, 512px" /></figure>



<p class="wp-block-paragraph">After creating the container, edit its configuration file:</p>



<pre class="wp-block-code"><code>nano /etc/pve/lxc/<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">container-id</mark>.conf</code></pre>



<p class="wp-block-paragraph">Add the following lines to the configuration file:</p>



<pre class="wp-block-code"><code>lxc.cgroup2.devices.allow: c 10:200 rwm
lxc.mount.entry: /dev/net dev/net none bind,create=dir</code></pre>



<p class="wp-block-paragraph">Change the owner of <code>/dev/net/tun</code> to allow the container to access it:</p>



<pre class="wp-block-code"><code>chown 100000:100000 /dev/net/tun</code></pre>



<p class="wp-block-paragraph">This will make <code>/dev/net/tun</code> available to the container, thus allowing you to use OpenVPN.</p>



<p class="wp-block-paragraph">Finally, start the container, and access its console.</p>



<h4 class="wp-block-heading">Installing qBittorrent</h4>



<p class="wp-block-paragraph">After ensuring that the container starts and is up to date, ensure that the following packages are installed:</p>



<pre class="wp-block-code"><code>apt install curl gpg</code></pre>



<p class="wp-block-paragraph">By default, the container uses root as the default user and doesn&#8217;t have <code>sudo</code> configured, so this post will assume that you haven&#8217;t setup <code>sudo</code>. If you have setup <code>sudo</code>, use <code>sudo</code> on the appropriate commands.</p>



<p class="wp-block-paragraph">Add the necessary repository to APT:</p>



<pre class="wp-block-code"><code>echo 'deb http://download.opensuse.org/repositories/home:/nikoneko:/test/Debian_12/ /' | tee /etc/apt/sources.list.d/home:nikoneko:test.list
curl -fsSL https://download.opensuse.org/repositories/home:nikoneko:test/Debian_12/Release.key | gpg --dearmor | tee /etc/apt/trusted.gpg.d/home_nikoneko_test.gpg &gt; /dev/null
apt update</code></pre>



<p class="wp-block-paragraph">Run the following command to install qBittorrent without a GUI and with only the web interface:</p>



<pre class="wp-block-code"><code>apt install qbittorrent-nox</code></pre>



<p class="wp-block-paragraph">After it has successfully installed, run the following command to start the initial setup:</p>



<pre class="wp-block-code"><code>qbittorrent-nox</code></pre>



<p class="wp-block-paragraph">After accepting the agreement, you&#8217;ll be prompted with a username, password, and URL to login. Replace <code>localhost</code> with the appropriate IP address. Press Ctrl+C to exit once you&#8217;ve confirmed that qBittorrent works.</p>



<p class="wp-block-paragraph">To run the qBittorrent service in the background, run the following command:</p>



<pre class="wp-block-code"><code>systemctl start qbittorrent-nox@root</code></pre>



<p class="wp-block-paragraph">You can also allow it to run at startup by running the following command:</p>



<pre class="wp-block-code"><code>systemctl enable qbittorrent-nox@root</code></pre>



<p class="wp-block-paragraph">If you get an error about a missing unit file, create a new one under <code>/usr/lib/systemd/system/qbittorrent-nox@.service</code>, then add the following contents:</p>



<pre class="wp-block-code"><code>&#91;Unit]
Description=qBittorrent-nox service for user %I
Documentation=man:qbittorrent-nox(1)
Wants=network-online.target
After=local-fs.target network-online.target nss-lookup.target

&#91;Service]
Type=simple
PrivateTmp=false
User=%i
ExecStart=qbittorrent-nox
TimeoutStopSec=1800

&#91;Install]
WantedBy=multi-user.target</code></pre>



<p class="wp-block-paragraph">Run <code>systemctl daemon-reload</code>, and you should be able to run the aforementioned commands without issue.</p>



<p class="wp-block-paragraph">As a quick side note, I noticed that the qBittorrent service can take a few minutes to stop, at least from my personal experience, so keep that in mind when rebooting the container.</p>



<h4 class="wp-block-heading">Mounting Network Drives</h4>



<p class="wp-block-paragraph">If you plan on storing your downloaded content on a network drive, first ensure that the following check boxes are checked under Options then Features:</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" src="https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-03-at-1.53.04-PM.png" alt="" class="wp-image-677" width="357" height="293" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-03-at-1.53.04-PM.png 714w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-03-at-1.53.04-PM-300x246.png 300w" sizes="auto, (max-width: 357px) 100vw, 357px" /><figcaption class="wp-element-caption">These features are only available on privileged containers</figcaption></figure>



<p class="wp-block-paragraph">After enabling those features, install the needed packages:</p>



<pre class="wp-block-code"><code>apt install cifs-utils</code></pre>



<p class="wp-block-paragraph">Next, open <code>/etc/fstab</code> in a text editor, and add the following line (Add more if needed):</p>



<pre class="wp-block-code"><code>//<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">ServerNameOrIP</mark>/<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">ShareName</mark> <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">/Path/Of/Choice</mark> cifs _netdev,username=<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">YourUsername</mark>,password=<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">YourPassword</mark>,iocharset=utf8 0 0</code></pre>



<p class="wp-block-paragraph">Run <code>mount -a</code>, then navigate to the directory that you chose to verify that it mounted correctly.</p>



<p class="wp-block-paragraph">If you&#8217;re using a VM instead of a container, add the following line to your <code>/etc/fstab</code> (You also need <code>cifs-utils</code> installed)</p>



<pre class="wp-block-code"><code>//<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">ServerNameOrIP</mark>/<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">ShareName</mark> <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">/Path/Of/Choice</mark> cifs _netdev,noauto,x-systemd.automount,username=<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">YourUsername</mark>,password=<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">YourPassword</mark>,iocharset=utf8,rw,uid=<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">UIDofqBittorrentUser</mark>,gid=<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">GIDofqBittorrentUser</mark> 0 0</code></pre>



<p class="wp-block-paragraph">You can get the UID and GID of your qBittorrent user by running <code>id <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">qBittorrentUser</mark></code>. Run <code>mount -a</code>, and navigate to the directory that you chose. Unlike the <code>fstab</code> for the container, after rebooting, the volume will only be mounted after something tries to access it, not at startup. </p>



<p class="wp-block-paragraph">Log into qBittorrent, then under Options and Downloads, enter the path that you mounted your network drive to:</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" src="https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-03-at-2.09.50-PM.png" alt="" class="wp-image-678" width="503" height="189" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-03-at-2.09.50-PM.png 671w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-03-at-2.09.50-PM-300x113.png 300w" sizes="auto, (max-width: 503px) 100vw, 503px" /><figcaption class="wp-element-caption">Adjust other save options if desired</figcaption></figure>



<p class="wp-block-paragraph">If you&#8217;re using something like Jellyfin or Plex, you&#8217;ll need to ensure that it has access to the directory that you chose.</p>



<h3 class="wp-block-heading">OpenVPN</h3>



<p class="wp-block-paragraph">This step is optional, but for the reasons I stated above, I would highly recommend using one. There&#8217;s probably a better way of doing this, but this is a tried and true method that I&#8217;ve used enough times. If you don&#8217;t know what VPN to use, I personally have had a great experience with ProtonVPN, but there&#8217;s various options out there.</p>



<p class="wp-block-paragraph">First, install the OpenVPN package:</p>



<pre class="wp-block-code"><code>apt install openvpn</code></pre>



<p class="wp-block-paragraph">Next, disable the default OpenVPN service. It&#8217;s enabled by default, and if you reboot your container, you&#8217;ll be staring at a black screen for minutes, then you&#8217;ll keep getting asked for a login (I found this out the hard way). </p>



<pre class="wp-block-code"><code>systemctl disable openvpn</code></pre>



<p class="wp-block-paragraph">Next, obtain the needed configuration files from your provider, and your OpenVPN username and password. If you happen to be using ProtonVPN, your OpenVPN username and password is located under Account, and the configuration files are located under Downloads.</p>



<p class="wp-block-paragraph">Save your downloaded configuration file under <code>/etc/openvpn/openvpn.conf</code>, and create a text file under <code>/etc/openvpn/login.txt</code> with your OpenVPN username and password. It should look something like this:</p>



<pre class="wp-block-code"><code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">ProvidedOpenVPNUsername
ProvidedOpenVPNPassword</mark></code></pre>



<p class="wp-block-paragraph">Next, create a new Systemd unit file under <code>/etc/systemd/system/openvpn-qbittorrent.service</code>, and add the following content:</p>



<pre class="wp-block-code"><code>&#91;Unit]
Description=OpenVPN Client for qBittorrent
After=network.target

&#91;Service]
ExecStart=openvpn --config  /etc/openvpn/openvpn.conf --auth-user-pass /etc/openvpn/login.txt

&#91;Install]
WantedBy=multi-user.target</code></pre>



<p class="wp-block-paragraph">Run <code>systemctl daemon-reload</code>, then run <code>systemctl start openvpn-qbittorrent</code>, and after ensuring that it&#8217;s running correctly, run <code>systemctl enable openvpn-qbittorrent</code> to allow it to run at startup.</p>



<p class="wp-block-paragraph">Last but most importantly, login to qBittorrent then navigate to Options, Advanced, then select <code>tun0</code> as the network interface. This will ensure that qBittorrent won&#8217;t try to fall back to a different interface in case your VPN goes down:</p>



<figure class="wp-block-image size-large is-resized"><img loading="lazy" decoding="async" src="https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-03-at-2.30.00-PM-1024x339.png" alt="" class="wp-image-679" width="512" height="170" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-03-at-2.30.00-PM-1024x339.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-03-at-2.30.00-PM-300x99.png 300w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-03-at-2.30.00-PM-768x254.png 768w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-03-at-2.30.00-PM.png 1408w" sizes="auto, (max-width: 512px) 100vw, 512px" /></figure>



<p class="wp-block-paragraph">Now you should have a working qBittorrent install that&#8217;s protected by a VPN.</p>



<h3 class="wp-block-heading">Jackett, Sonarr, and Others</h3>



<p class="wp-block-paragraph">Now that you have a working qBittorrent install with a VPN, it&#8217;s time to do something with it by installing some indexers. This is what will actually allow you to download content by using your qBittorrent setup. </p>



<p class="wp-block-paragraph">You can either run these indexers inside of the same container as qBittorrent, or in their own container. I personally chose to run all of my indexers inside of their own separate container.</p>



<h4 class="wp-block-heading">Jackett</h4>



<p class="wp-block-paragraph">After adding indexers to Jackett, its job is to simply look for the content that you tell it to by using something like Sonarr. After it has found the content that you&#8217;re looking for, it will relay that information to Sonarr (Or whatever *arr app you&#8217;re using) so it can start downloading it.</p>



<h5 class="wp-block-heading">Jackett Install</h5>



<p class="wp-block-paragraph">Before you can install Jackett, you need to create a new user that has access to the <code>sudo</code> command. This is because Jackett will fail to install if you&#8217;re using the default root user, and even if you modify the script to allow it, you&#8217;ll get a banner saying that Jackett is being ran as root everytime you launch it.</p>



<p class="wp-block-paragraph">First, install the <code>sudo</code> package:</p>



<pre class="wp-block-code"><code>apt install sudo</code></pre>



<p class="wp-block-paragraph">After installing the sudo package, create a new user, then add it to the <code>sudo</code> group:</p>



<pre class="wp-block-code"><code>useradd -mG sudo <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">username</mark></code></pre>



<p class="wp-block-paragraph">Set a password for the user:</p>



<pre class="wp-block-code"><code>passwd <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">username</mark></code></pre>



<p class="wp-block-paragraph">Now switch to the user, and try running any command with the <code>sudo</code> command to ensure that it&#8217;s setup correctly:</p>



<pre class="wp-block-code"><code>su <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">username</mark>
sudo apt update</code></pre>



<p class="wp-block-paragraph">After verifying that <code>sudo</code> works correctly, ensure that <code>wget</code> has been installed:</p>



<pre class="wp-block-code"><code>sudo apt install wget</code></pre>



<p class="wp-block-paragraph">The Jackett developers provide this handy one line installation command:</p>



<pre class="wp-block-code"><code>cd /opt &amp;&amp; f=Jackett.Binaries.LinuxAMDx64.tar.gz &amp;&amp; release=$(wget -q https://github.com/Jackett/Jackett/releases/latest -O - | grep "title&gt;Release" | cut -d " " -f 4) &amp;&amp; sudo wget -Nc https://github.com/Jackett/Jackett/releases/download/$release/"$f" &amp;&amp; sudo tar -xzf "$f" &amp;&amp; sudo rm -f "$f" &amp;&amp; cd Jackett* &amp;&amp; sudo ./install_service_systemd.sh &amp;&amp; systemctl status jackett.service &amp;&amp; cd - &amp;&amp; echo -e "\nVisit http://127.0.0.1:9117"</code></pre>



<p class="wp-block-paragraph">After Jackett has been successfully installed, visit Jackett by typing in your container&#8217;s IP address and the listed port.</p>



<h5 class="wp-block-heading">Jackett Configuration</h5>



<p class="wp-block-paragraph">Configuring Jackett is very simple. All you need to do is add some indexers, and you&#8217;ll be all set. Here&#8217;s the indexers I personally use:</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" src="https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-04-at-1.57.39-PM.png" alt="" class="wp-image-681" width="662" height="321" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-04-at-1.57.39-PM.png 882w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-04-at-1.57.39-PM-300x146.png 300w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-04-at-1.57.39-PM-768x373.png 768w" sizes="auto, (max-width: 662px) 100vw, 662px" /></figure>



<p class="wp-block-paragraph">Feel free to scroll down and explore all of the other settings. We&#8217;ll get back to Jackett in a moment. At this point, I will be assuming that you will be using the default <code>root</code> user. </p>



<h4 class="wp-block-heading">FlareSolverr Installation/Configuration</h4>



<p class="wp-block-paragraph">Since some indexers might use Cloudflare&#8217;s captcha, this may prevent Jackett from indexing them. Luckily someone made a very easy solution to this problem.</p>



<p class="wp-block-paragraph">Since the recommended way to install FlareSolverr is to use Docker, you&#8217;ll need to setup Docker on your container. Before installing Docker, ensure that your container is a privileged container. </p>



<p class="wp-block-paragraph">First, install Docker according to their documentation. I would recommend <a href="https://docs.docker.com/engine/install/debian/#install-using-the-repository" target="_blank" rel="noreferrer noopener">installing Docker using the APT repository</a> as this makes it very easy to update. After you&#8217;ve verified that Docker is installed correctly, create a file named <code>docker-compose.yml</code> in a place that you would remember, then add the following contents:</p>



<pre class="wp-block-code"><code>version: "2.1"
services:
  flaresolverr:
    # DockerHub mirror flaresolverr/flaresolverr:latest
    image: ghcr.io/flaresolverr/flaresolverr:latest
    container_name: flaresolverr
    environment:
      - LOG_LEVEL=${LOG_LEVEL:-info}
      - LOG_HTML=${LOG_HTML:-false}
      - CAPTCHA_SOLVER=${CAPTCHA_SOLVER:-none}
      - TZ=Europe/London
    ports:
      - "${PORT:-8191}:8191"
    restart: unless-stopped</code></pre>



<p class="wp-block-paragraph">You should be able to keep all of the options at their defaults without any issues. You can run the container by running the following command:</p>



<pre class="wp-block-code"><code>docker compose up -d</code></pre>



<p class="wp-block-paragraph">If you&#8217;d rather not use Docker Compose, use the following Docker command instead:</p>



<pre class="wp-block-code"><code>docker run -d --name=flaresolverr -p 8191:8191 -e LOG_LEVEL=info --restart unless-stopped ghcr.io/flaresolverr/flaresolverr:latest</code></pre>



<p class="wp-block-paragraph">After the container has been created, enter <code>yourcontainerip:8191</code> into your web browser, and you should see a message stating that FlareSolverr is ready. If you want to update FlareSolverr, run the following commands:</p>



<pre class="wp-block-code"><code>docker rm -v flaresolverr &amp;&amp; docker rmi ghcr.io/flaresolverr/flaresolverr</code></pre>



<p class="wp-block-paragraph">Now use the <code>docker run</code> command or the <code>docker compose</code> command depending on what you chose.</p>



<p class="wp-block-paragraph">Finally, configure Jackett to use FlareSolverr by scrolling down to the bottom of the page, and entering the URL to access FlareSolverr under FlareSolverr API URL:</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" src="https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-04-at-2.31.14-PM.png" alt="" class="wp-image-684" width="429" height="179" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-04-at-2.31.14-PM.png 572w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-04-at-2.31.14-PM-300x125.png 300w" sizes="auto, (max-width: 429px) 100vw, 429px" /></figure>



<h4 class="wp-block-heading">Sonarr</h4>



<p class="wp-block-paragraph">Sonarr is used to tell Jackett what content to look for inside of your indexers, and it also instructs qBittorrent to start downloading it. Sonarr can even look for new releases to automatically download. All you need to do is add the shows that you want to watch to Sonarr, and it does the rest.</p>



<h5 class="wp-block-heading">Sonarr Installation</h5>



<p class="wp-block-paragraph">I will only be showing the installation for Sonarr, but the installation process for similar *arr apps should be very similar.</p>



<p class="wp-block-paragraph">First, add the Sonarr APT repository (Even though it says Buster, it works fine on Bullseye):</p>



<pre class="wp-block-code"><code>apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 2009837CBFFD68F45BC180471F4F90DE2A9B4BF8
echo "deb https://apt.sonarr.tv/debian buster main" | tee /etc/apt/sources.list.d/sonarr.list</code></pre>



<p class="wp-block-paragraph">Next, install the Sonarr package:</p>



<pre class="wp-block-code"><code>apt update &amp;&amp; apt install sonarr</code></pre>



<p class="wp-block-paragraph">When prompted, just hit enter to keep the defaults. This will create a user named <code>sonarr</code> that will be responsible for well&#8230; running Sonarr.</p>



<p class="wp-block-paragraph">If you want Sonarr to store your media on a network drive, you&#8217;ll need to install <code>cifs-utils</code>:</p>



<pre class="wp-block-code"><code>apt install cifs-utils</code></pre>



<p class="wp-block-paragraph">Next, get the UID and GID of the Sonarr user:</p>



<pre class="wp-block-code"><code>id sonarr</code></pre>



<p class="wp-block-paragraph">The <code>/etc/fstab</code> configuration is similar to the one that you used for qBittorrent:</p>



<pre class="wp-block-code"><code># For containers
//<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">ServerNameOrIP</mark>/<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">ShareName</mark> <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">/Path/Of/Choice</mark> cifs _netdev,username=<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">YourUsername</mark>,password=<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">YourPassword</mark>,iocharset=utf8,rw,uid=<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">SonarrUserUID</mark>,gid=<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">SonarrUserGID</mark> 0 0
# For VM's
//<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">ServerNameOrIP</mark>/<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">ShareName</mark> <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">/Path/Of/Choice</mark> cifs _netdev,noauto,x-systemd.automount,username=<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">YourUsername</mark>,password=<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">YourPassword</mark>,iocharset=utf8,rw,uid=<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">SonarrUserUID</mark>,gid=<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">SonarrUserGID</mark> 0 0</code></pre>



<p class="wp-block-paragraph">Run <code>mount -a</code>, and browse to the path that you chose to ensure that the share was mounted correctly.</p>



<h5 class="wp-block-heading">Sonarr Configuration</h5>



<p class="wp-block-paragraph">Open your container&#8217;s IP address with port 8989 in your web browser to access Sonarr. This is where all of the configuration of Sonarr will take place. First, you&#8217;ll want to tell Sonarr where to store all of your media, so click on Settings, then Media Management in the sidebar:</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" src="https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-10.41.15-AM.png" alt="" class="wp-image-693" width="211" height="335" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-10.41.15-AM.png 422w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-10.41.15-AM-189x300.png 189w" sizes="auto, (max-width: 211px) 100vw, 211px" /></figure>



<p class="wp-block-paragraph">Next, scroll down to Root Folders, remove any unneeded ones by clicking the little X, and add your network share by clicking on Add Root Folder:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="174" src="https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-10.46.03-AM-1024x174.png" alt="" class="wp-image-694" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-10.46.03-AM-1024x174.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-10.46.03-AM-300x51.png 300w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-10.46.03-AM-768x130.png 768w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-10.46.03-AM-1536x261.png 1536w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-10.46.03-AM-2048x348.png 2048w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-10.46.03-AM-1568x266.png 1568w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">Next, configure Sonarr to use qBittorrent by clicking on Download Clients under Settings:</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" src="https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-10.51.09-AM.png" alt="" class="wp-image-695" width="199" height="300" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-10.51.09-AM.png 398w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-10.51.09-AM-199x300.png 199w" sizes="auto, (max-width: 199px) 100vw, 199px" /></figure>



<p class="wp-block-paragraph">Under Download Clients, click the big button with the + icon:</p>



<figure class="wp-block-image size-large is-resized"><img loading="lazy" decoding="async" src="https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-10.52.09-AM-1024x313.png" alt="" class="wp-image-696" width="512" height="157" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-10.52.09-AM-1024x313.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-10.52.09-AM-300x92.png 300w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-10.52.09-AM-768x234.png 768w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-10.52.09-AM.png 1330w" sizes="auto, (max-width: 512px) 100vw, 512px" /><figcaption class="wp-element-caption">Ignore the fact that I&#8217;ve already configured mine</figcaption></figure>



<p class="wp-block-paragraph">Click qBittorrent under Torrents:</p>



<figure class="wp-block-image size-large is-resized"><img loading="lazy" decoding="async" src="https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-10.53.03-AM-1024x555.png" alt="" class="wp-image-697" width="512" height="278" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-10.53.03-AM-1024x555.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-10.53.03-AM-300x163.png 300w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-10.53.03-AM-768x417.png 768w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-10.53.03-AM-1536x833.png 1536w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-10.53.03-AM-2048x1111.png 2048w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-10.53.03-AM-1568x851.png 1568w" sizes="auto, (max-width: 512px) 100vw, 512px" /></figure>



<p class="wp-block-paragraph">Finally, fill out the needed information according to your setup, then Click Test and Save:</p>



<figure class="wp-block-image size-large is-resized"><img loading="lazy" decoding="async" src="https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-10-at-3.00.54-PM-1024x1010.png" alt="" class="wp-image-716" width="512" height="505" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-10-at-3.00.54-PM-1024x1010.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-10-at-3.00.54-PM-300x296.png 300w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-10-at-3.00.54-PM-768x757.png 768w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-10-at-3.00.54-PM.png 1448w" sizes="auto, (max-width: 512px) 100vw, 512px" /></figure>



<p class="wp-block-paragraph">Next, you&#8217;ll need to configure Sonarr to use your Jackett indexers by clicking on Indexers under Settings. At this point you&#8217;ll want to have the web interface for Jackett pulled up:</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" src="https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.02.11-AM.png" alt="" class="wp-image-699" width="199" height="257" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.02.11-AM.png 398w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.02.11-AM-232x300.png 232w" sizes="auto, (max-width: 199px) 100vw, 199px" /></figure>



<p class="wp-block-paragraph">Next, click the large + button under Indexers:</p>



<figure class="wp-block-image size-large is-resized"><img loading="lazy" decoding="async" src="https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.03.41-AM-1024x555.png" alt="" class="wp-image-700" width="512" height="278" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.03.41-AM-1024x555.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.03.41-AM-300x162.png 300w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.03.41-AM-768x416.png 768w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.03.41-AM-1536x832.png 1536w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.03.41-AM-1568x849.png 1568w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.03.41-AM.png 1902w" sizes="auto, (max-width: 512px) 100vw, 512px" /><figcaption class="wp-element-caption">Like with configuring qBittorrent, ignore the fact that I&#8217;ve already added my indexers</figcaption></figure>



<p class="wp-block-paragraph">Click Torznab under Torrents:</p>



<figure class="wp-block-image size-large is-resized"><img loading="lazy" decoding="async" src="https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.09.06-AM-1024x436.png" alt="" class="wp-image-701" width="512" height="218" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.09.06-AM-1024x436.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.09.06-AM-300x128.png 300w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.09.06-AM-768x327.png 768w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.09.06-AM-1536x654.png 1536w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.09.06-AM-1568x668.png 1568w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.09.06-AM.png 2000w" sizes="auto, (max-width: 512px) 100vw, 512px" /></figure>



<p class="wp-block-paragraph">You should see a screen that looks something like this:</p>



<figure class="wp-block-image size-large is-resized"><img loading="lazy" decoding="async" src="https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.16.41-AM-1024x1013.png" alt="" class="wp-image-703" width="512" height="507" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.16.41-AM-1024x1013.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.16.41-AM-300x297.png 300w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.16.41-AM-150x150.png 150w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.16.41-AM-768x760.png 768w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.16.41-AM.png 1448w" sizes="auto, (max-width: 512px) 100vw, 512px" /></figure>



<p class="wp-block-paragraph">Next, navigate to Jackett, then click Copy Torznab Feed next to the indexer that you want to add:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="187" src="https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.13.32-AM-1-1024x187.png" alt="" class="wp-image-704" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.13.32-AM-1-1024x187.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.13.32-AM-1-300x55.png 300w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.13.32-AM-1-768x141.png 768w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.13.32-AM-1-1536x281.png 1536w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.13.32-AM-1-1568x287.png 1568w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.13.32-AM-1.png 1748w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">Navigate back to Sonarr, then paste it under URL. </p>



<p class="wp-block-paragraph">Next, copy the API key for Jackett. It&#8217;s displayed in the top right corner of Jackett&#8217;s page:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="108" src="https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.14.30-AM-1024x108.png" alt="" class="wp-image-705" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.14.30-AM-1024x108.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.14.30-AM-300x32.png 300w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.14.30-AM-768x81.png 768w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.14.30-AM-1536x161.png 1536w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.14.30-AM-1568x165.png 1568w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.14.30-AM.png 1808w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">Paste your API key under API Key.</p>



<p class="wp-block-paragraph">Finally, click on the Categories drop down menu, and select the categories as needed. This will vary from indexer to indexer. Configure all of the other settings as needed.</p>



<p class="wp-block-paragraph">After you&#8217;ve configured everything, click Test and Save:</p>



<figure class="wp-block-image size-large is-resized"><img loading="lazy" decoding="async" src="https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.21.43-AM-1024x1010.png" alt="" class="wp-image-706" width="512" height="505" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.21.43-AM-1024x1010.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.21.43-AM-300x296.png 300w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.21.43-AM-768x757.png 768w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.21.43-AM.png 1448w" sizes="auto, (max-width: 512px) 100vw, 512px" /></figure>



<p class="wp-block-paragraph">Finally, you should be able to click Series, and then add TV shows as needed. I could go over all of the options here, but I would recommend that you explore them yourself. I personally like using the interactive search instead of letting Sonarr look for new episodes automatically. Depending on how many indexers you have and other factors, it can take a long time:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="173" src="https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.27.29-AM-1024x173.png" alt="" class="wp-image-707" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.27.29-AM-1024x173.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.27.29-AM-300x51.png 300w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.27.29-AM-768x129.png 768w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.27.29-AM-1536x259.png 1536w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.27.29-AM-2048x345.png 2048w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.27.29-AM-1568x264.png 1568w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">Button to access the interactive search feature</figcaption></figure>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="676" src="https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.27.15-AM-1024x676.png" alt="" class="wp-image-708" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.27.15-AM-1024x676.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.27.15-AM-300x198.png 300w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.27.15-AM-768x507.png 768w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.27.15-AM-1536x1014.png 1536w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.27.15-AM-2048x1351.png 2048w, https://alexshomenetwork.com/wp-content/uploads/2023/07/Screenshot-2023-07-09-at-11.27.15-AM-1568x1035.png 1568w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">Interactive search example</figcaption></figure>



<h3 class="wp-block-heading">Conclusion</h3>



<p class="wp-block-paragraph">After reading this post, you should now have a working *arr stack to automatically download your favorite TV shows. Unfortunately I can&#8217;t shows the installation process for Jellyfin since GPU passthrough doesn&#8217;t work correctly on my Proxmox host, and even though you technically don&#8217;t need it, I feel like it&#8217;s an important thing to have.</p>



<p class="wp-block-paragraph">Feel free to leave any thoughts, suggestions, or complaints in the comments below. If you have any questions, I&#8217;ll try my best to answer them.</p>



<h3 class="wp-block-heading">References</h3>



<p class="wp-block-paragraph">Proxmox&#8217;s official guide on running OpenVPN in LXC: <a href="https://pve.proxmox.com/wiki/OpenVPN_in_LXC" target="_blank" rel="noreferrer noopener">https://pve.proxmox.com/wiki/OpenVPN_in_LXC</a></p>



<p class="wp-block-paragraph">qBittorrent Installation: <a href="https://github.com/qbittorrent/qBittorrent/wiki/Running-qBittorrent-without-X-server-(WebUI-only,-systemd-service-set-up,-Ubuntu-15.04-or-newer)" target="_blank" rel="noreferrer noopener">https://github.com/qbittorrent/qBittorrent/wiki/Running-qBittorrent-without-X-server-(WebUI-only,-systemd-service-set-up,-Ubuntu-15.04-or-newer</a></p>



<p class="wp-block-paragraph">Jackett Installation: <a href="https://github.com/Jackett/Jackett" target="_blank" rel="noreferrer noopener">https://github.com/Jackett/Jackett</a></p>



<p class="wp-block-paragraph">FlareSolverr Installation: <a href="https://github.com/FlareSolverr/FlareSolverr/blob/master/docker-compose.yml" target="_blank" rel="noreferrer noopener">https://github.com/FlareSolverr/FlareSolverr/</a></p>



<p class="wp-block-paragraph">Sonarr Installation: <a href="https://sonarr.tv/#downloads-v3-linux" target="_blank" rel="noreferrer noopener">https://sonarr.tv/#downloads-v3-linux</a></p>
<p>The post <a href="https://alexshomenetwork.com/installing-an-arr-stack-on-proxmox/">Installing an *arr Stack on Proxmox</a> appeared first on <a href="https://alexshomenetwork.com">Alex&#039;s Home Network</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://alexshomenetwork.com/installing-an-arr-stack-on-proxmox/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
			</item>
		<item>
		<title>Using Openweathermap with Grafana and Displaying it on a Raspberry Pi Touchscreen</title>
		<link>https://alexshomenetwork.com/using-openweathermap-with-grafana-and-displaying-it-on-a-raspberry-pi/</link>
					<comments>https://alexshomenetwork.com/using-openweathermap-with-grafana-and-displaying-it-on-a-raspberry-pi/#comments</comments>
		
		<dc:creator><![CDATA[Alex]]></dc:creator>
		<pubDate>Mon, 20 Feb 2023 21:53:02 +0000</pubDate>
				<category><![CDATA[Self-Hosting]]></category>
		<guid isPermaLink="false">https://alexshomenetwork.com/?p=586</guid>

					<description><![CDATA[<p>In this post, I&#8217;ll show you how to use the Openweathermap API with Grafana, and how to display it on a nice little touchscreen powered by a Raspberry Pi. Even though I&#8217;ll be going over the hardware I&#8217;ll be using specifically, you don&#8217;t need to be using the same hardware as me. The software setup<a class="more-link" href="https://alexshomenetwork.com/using-openweathermap-with-grafana-and-displaying-it-on-a-raspberry-pi/">Continue reading <span class="screen-reader-text">"Using Openweathermap with Grafana and Displaying it on a Raspberry Pi Touchscreen"</span></a></p>
<p>The post <a href="https://alexshomenetwork.com/using-openweathermap-with-grafana-and-displaying-it-on-a-raspberry-pi/">Using Openweathermap with Grafana and Displaying it on a Raspberry Pi Touchscreen</a> appeared first on <a href="https://alexshomenetwork.com">Alex&#039;s Home Network</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">In this post, I&#8217;ll show you how to use the Openweathermap API with Grafana, and how to display it on a nice little touchscreen powered by a Raspberry Pi. Even though I&#8217;ll be going over the hardware I&#8217;ll be using specifically, you don&#8217;t need to be using the same hardware as me. The software setup should be pretty similar to most hardware.</p>



<h3 class="wp-block-heading">Prerequisites</h3>



<p class="wp-block-paragraph">Before you start, you&#8217;ll need a working Grafana install (<a href="https://grafana.com/docs/grafana/latest/setup-grafana/installation/" target="_blank" rel="noreferrer noopener">Instructions here if you don&#8217;t</a>), and an <a href="https://openweathermap.org" target="_blank" rel="noreferrer noopener">Openweathermap API key</a>. I would recommend using the <a href="https://openweathermap.org/api/one-call-api" target="_blank" rel="noreferrer noopener">Onecall API</a> since it provides a good amount of information with a single API call (Although Grafana still makes multiple calls, more on that later).</p>



<h3 class="wp-block-heading">Setting up The Raspberry Pi</h3>



<p class="wp-block-paragraph">Before creating your dashboard, you&#8217;ll want something to test it on. If you&#8217;re going to do the hardware part last, I recommend setting up a Debian VM with the same screen resolution as the display that you&#8217;re going to use. I&#8217;ll be going over hardware (Briefly) and software setup. If you&#8217;re not using the same hardware as me, then skip the hardware sections. If you only care about using the Openweathermap API with Grafana, then skip this entire section.</p>



<h4 class="wp-block-heading">Hardware</h4>



<p class="wp-block-paragraph">The hardware I&#8217;m using is a Raspberry Pi 3B with an official Raspberry Pi touchscreen and a case that I happened to have laying around. The pictures below show the case that I&#8217;m using, and I believe that you can still purchase it on Amazon:</p>



<figure class="wp-block-image size-large is-resized"><img loading="lazy" decoding="async" width="1024" height="768" src="https://alexshomenetwork.com/wp-content/uploads/2023/01/IMG_0477-1024x768.jpg" alt="" class="wp-image-601" style="width:512px;height:384px" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/01/IMG_0477-1024x768.jpg 1024w, https://alexshomenetwork.com/wp-content/uploads/2023/01/IMG_0477-300x225.jpg 300w, https://alexshomenetwork.com/wp-content/uploads/2023/01/IMG_0477-768x576.jpg 768w, https://alexshomenetwork.com/wp-content/uploads/2023/01/IMG_0477-1536x1152.jpg 1536w, https://alexshomenetwork.com/wp-content/uploads/2023/01/IMG_0477-1568x1176.jpg 1568w, https://alexshomenetwork.com/wp-content/uploads/2023/01/IMG_0477.jpg 1707w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">Ignore my messy desk</figcaption></figure>



<figure class="wp-block-image size-large is-resized"><img loading="lazy" decoding="async" width="1024" height="768" src="https://alexshomenetwork.com/wp-content/uploads/2023/01/IMG_0478-1024x768.jpg" alt="" class="wp-image-602" style="width:512px;height:384px" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/01/IMG_0478-1024x768.jpg 1024w, https://alexshomenetwork.com/wp-content/uploads/2023/01/IMG_0478-300x225.jpg 300w, https://alexshomenetwork.com/wp-content/uploads/2023/01/IMG_0478-768x576.jpg 768w, https://alexshomenetwork.com/wp-content/uploads/2023/01/IMG_0478-1536x1152.jpg 1536w, https://alexshomenetwork.com/wp-content/uploads/2023/01/IMG_0478-1568x1176.jpg 1568w, https://alexshomenetwork.com/wp-content/uploads/2023/01/IMG_0478.jpg 1707w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">All I had to do to install the Pi was to put it in the case (It was kind of difficult because of the black foam pads), and screw in two screws. I also needed to connect the ribbon cable:</p>



<figure class="wp-block-image size-large is-resized"><img loading="lazy" decoding="async" width="1024" height="768" src="https://alexshomenetwork.com/wp-content/uploads/2023/01/IMG_0479-1024x768.jpg" alt="" class="wp-image-604" style="width:512px;height:384px" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/01/IMG_0479-1024x768.jpg 1024w, https://alexshomenetwork.com/wp-content/uploads/2023/01/IMG_0479-300x225.jpg 300w, https://alexshomenetwork.com/wp-content/uploads/2023/01/IMG_0479-768x576.jpg 768w, https://alexshomenetwork.com/wp-content/uploads/2023/01/IMG_0479-1536x1152.jpg 1536w, https://alexshomenetwork.com/wp-content/uploads/2023/01/IMG_0479-1568x1176.jpg 1568w, https://alexshomenetwork.com/wp-content/uploads/2023/01/IMG_0479.jpg 1707w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">I remember having a shorter cable at one point, but I guess I lost it</figcaption></figure>



<p class="wp-block-paragraph">For whatever reason, the cover wasn&#8217;t fitting right, so I just clipped it in and rested it on the case. Luckily it still feels pretty secure:</p>



<figure class="wp-block-image size-large is-resized"><img loading="lazy" decoding="async" width="1024" height="768" src="https://alexshomenetwork.com/wp-content/uploads/2023/01/IMG_0480-1024x768.jpg" alt="" class="wp-image-605" style="width:512px;height:384px" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/01/IMG_0480-1024x768.jpg 1024w, https://alexshomenetwork.com/wp-content/uploads/2023/01/IMG_0480-300x225.jpg 300w, https://alexshomenetwork.com/wp-content/uploads/2023/01/IMG_0480-768x576.jpg 768w, https://alexshomenetwork.com/wp-content/uploads/2023/01/IMG_0480-1536x1152.jpg 1536w, https://alexshomenetwork.com/wp-content/uploads/2023/01/IMG_0480-1568x1176.jpg 1568w, https://alexshomenetwork.com/wp-content/uploads/2023/01/IMG_0480.jpg 1707w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">And to my relief, my Pi (I manhandled it out of my old case) and my screen (It has been sitting for months) still worked. It&#8217;s impossible to find Pi&#8217;s for a reasonable price, so if I broke mine, then this blog post would be even more overdue.</p>



<h4 class="wp-block-heading">Installing Raspberry Pi OS</h4>



<p class="wp-block-paragraph">Since the Pi will be doing nothing more than displaying a Grafana dashboard inside of a web browser, you don&#8217;t need anything fancy. You also don&#8217;t need to use Raspberry Pi OS specifically, but I recommend using it for the best compatibility. To install Raspberry Pi OS, download the Raspberry Pi Imager from <a href="https://www.raspberrypi.com/software/" target="_blank" rel="noreferrer noopener">here</a>.</p>



<p class="wp-block-paragraph">Once you&#8217;ve launched Raspberry Pi Imager, insert your SD card, and select the Choose OS button:</p>



<figure class="wp-block-image size-large is-resized"><img loading="lazy" decoding="async" width="1024" height="675" src="https://alexshomenetwork.com/wp-content/uploads/2023/01/Screen-Shot-2023-01-26-at-5.17.02-PM-1024x675.png" alt="" class="wp-image-607" style="width:512px;height:338px" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/01/Screen-Shot-2023-01-26-at-5.17.02-PM-1024x675.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2023/01/Screen-Shot-2023-01-26-at-5.17.02-PM-300x198.png 300w, https://alexshomenetwork.com/wp-content/uploads/2023/01/Screen-Shot-2023-01-26-at-5.17.02-PM-768x506.png 768w, https://alexshomenetwork.com/wp-content/uploads/2023/01/Screen-Shot-2023-01-26-at-5.17.02-PM.png 1362w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">From the list, select Raspberry Pi OS (Other):</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="118" src="https://alexshomenetwork.com/wp-content/uploads/2023/01/Screen-Shot-2023-01-26-at-5.18.51-PM-1024x118.png" alt="" class="wp-image-608" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/01/Screen-Shot-2023-01-26-at-5.18.51-PM-1024x118.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2023/01/Screen-Shot-2023-01-26-at-5.18.51-PM-300x35.png 300w, https://alexshomenetwork.com/wp-content/uploads/2023/01/Screen-Shot-2023-01-26-at-5.18.51-PM-768x89.png 768w, https://alexshomenetwork.com/wp-content/uploads/2023/01/Screen-Shot-2023-01-26-at-5.18.51-PM.png 1144w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">Since we don&#8217;t need a desktop or anything fancy preinstalled, select Raspberry Pi OS Lite (I recommend 64-bit for better software compatibility):</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="216" src="https://alexshomenetwork.com/wp-content/uploads/2023/01/Screen-Shot-2023-01-26-at-5.19.05-PM-1024x216.png" alt="" class="wp-image-609" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/01/Screen-Shot-2023-01-26-at-5.19.05-PM-1024x216.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2023/01/Screen-Shot-2023-01-26-at-5.19.05-PM-300x63.png 300w, https://alexshomenetwork.com/wp-content/uploads/2023/01/Screen-Shot-2023-01-26-at-5.19.05-PM-768x162.png 768w, https://alexshomenetwork.com/wp-content/uploads/2023/01/Screen-Shot-2023-01-26-at-5.19.05-PM.png 1140w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">To save yourself some time, click the settings icon to preconfigure some settings. It will allow you to do stuff like enable SSH, set a hostname, and connect it to a WiFi network. I would recommend enabling SSH and setting a static IP later on so you can easily manage the Pi.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="289" src="https://alexshomenetwork.com/wp-content/uploads/2023/01/Screen-Shot-2023-01-26-at-5.19.26-PM-1024x289.png" alt="" class="wp-image-610" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/01/Screen-Shot-2023-01-26-at-5.19.26-PM-1024x289.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2023/01/Screen-Shot-2023-01-26-at-5.19.26-PM-300x85.png 300w, https://alexshomenetwork.com/wp-content/uploads/2023/01/Screen-Shot-2023-01-26-at-5.19.26-PM-768x216.png 768w, https://alexshomenetwork.com/wp-content/uploads/2023/01/Screen-Shot-2023-01-26-at-5.19.26-PM.png 1242w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">Once you click Save, select the Choose Storage button, select your SD card, then click write. Once it&#8217;s done, you should now have a bootable SD card for your Pi, and if you&#8217;ve preconfigured it, you shouldn&#8217;t need to do any additional setup for now. </p>



<p class="wp-block-paragraph">After your Pi has successfully booted (And maybe asked a few questions depending on how you&#8217;ve preconfigured it), you should see a screen that looks something like this:</p>



<figure class="wp-block-image size-large is-resized"><img loading="lazy" decoding="async" width="1024" height="768" src="https://alexshomenetwork.com/wp-content/uploads/2023/01/IMG_0590-1024x768.jpg" alt="" class="wp-image-611" style="width:512px;height:384px" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/01/IMG_0590-1024x768.jpg 1024w, https://alexshomenetwork.com/wp-content/uploads/2023/01/IMG_0590-300x225.jpg 300w, https://alexshomenetwork.com/wp-content/uploads/2023/01/IMG_0590-768x576.jpg 768w, https://alexshomenetwork.com/wp-content/uploads/2023/01/IMG_0590-1536x1152.jpg 1536w, https://alexshomenetwork.com/wp-content/uploads/2023/01/IMG_0590-1568x1176.jpg 1568w, https://alexshomenetwork.com/wp-content/uploads/2023/01/IMG_0590.jpg 1707w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<h4 class="wp-block-heading">Installing Some Software</h4>



<p class="wp-block-paragraph">In order to display your Grafana dashboard, you&#8217;ll need some sort of desktop environment or window manager. I personally used Openbox with Lightdm, and I had it open Firefox automatically in kiosk mode. There&#8217;s probably a bunch of other ways of doing this (And might be more efficient), but I&#8217;ll show you my way.</p>



<p class="wp-block-paragraph">First, you&#8217;ll want to install Openbox (Window Manager), Lightdm (Login Screen Thing), and XFCE Terminal (To manage the Pi directly if you need to):</p>



<pre class="wp-block-code"><code>sudo apt install openbox lightdm xfce4-terminal</code></pre>



<p class="wp-block-paragraph">Manually start Lightdm&#8217;s service:</p>



<pre class="wp-block-code"><code>sudo systemctl start lightdm</code></pre>



<p class="wp-block-paragraph">After about 5-10 seconds at most, you should see a login screen that looks something like this:</p>



<figure class="wp-block-image size-large is-resized"><img loading="lazy" decoding="async" width="1024" height="768" src="https://alexshomenetwork.com/wp-content/uploads/2023/01/IMG_0591-1024x768.jpg" alt="" class="wp-image-612" style="width:512px;height:384px" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/01/IMG_0591-1024x768.jpg 1024w, https://alexshomenetwork.com/wp-content/uploads/2023/01/IMG_0591-300x225.jpg 300w, https://alexshomenetwork.com/wp-content/uploads/2023/01/IMG_0591-768x576.jpg 768w, https://alexshomenetwork.com/wp-content/uploads/2023/01/IMG_0591-1536x1152.jpg 1536w, https://alexshomenetwork.com/wp-content/uploads/2023/01/IMG_0591-1568x1176.jpg 1568w, https://alexshomenetwork.com/wp-content/uploads/2023/01/IMG_0591.jpg 1707w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">This is a more general tip, but if you&#8217;re stuck with a black screen, or you forgot to install a terminal emulator, you can switch your tty by using the following keyboard shortcut:</p>



<pre class="wp-block-code"><code>ctrl + alt + <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">random function key</mark></code></pre>



<p class="wp-block-paragraph">After a few attempts with random function keys, you should eventually be brought to a normal text-based terminal. Using F7 will bring you back to Openbox.</p>



<p class="wp-block-paragraph">If you&#8217;re able to successfully login, you should see a screen that looks something like this (You might have a wallpaper):</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="611" src="https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-11-at-4.52.51-PM-1024x611.png" alt="" class="wp-image-619" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-11-at-4.52.51-PM-1024x611.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-11-at-4.52.51-PM-300x179.png 300w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-11-at-4.52.51-PM-768x458.png 768w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-11-at-4.52.51-PM-1536x916.png 1536w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-11-at-4.52.51-PM-1568x935.png 1568w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-11-at-4.52.51-PM.png 1724w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">Screenshot because of the reflection</figcaption></figure>



<p class="wp-block-paragraph">To access the terminal, right click, and locate it in the applications menu. Configure Lightdm&#8217;s autologin by opening <code>/etc/lightdm/lightgm.conf</code>, and look for the following lines under <code>[Seat:*]</code>:</p>



<pre class="wp-block-code"><code>#autologin-user=
#autologin-user-timeout=</code></pre>



<p class="wp-block-paragraph">Uncomment both lines, and replace <code>username</code> with the user that you want to autologin with:</p>



<pre class="wp-block-code"><code>autologin-user=<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">username</mark>
autologin-user-timeout=0</code></pre>



<p class="wp-block-paragraph">Restart Lightdm&#8217;s service:</p>



<pre class="wp-block-code"><code>sudo systemctl restart lightdm</code></pre>



<p class="wp-block-paragraph">And if you&#8217;ve followed these steps correctly, after a few seconds you should automatically be dropped into Openbox. If Lightdm&#8217;s service is not already enabled, enable it by running the following command:</p>



<pre class="wp-block-code"><code>sudo systemctl enable lightdm</code></pre>



<p class="wp-block-paragraph">After a quick reboot, Lightdm should automatically start then drop you into Openbox. If Lightdm still doesn&#8217;t run at startup, the following command fixed the issue for me (<a href="https://unix.stackexchange.com/questions/33813/lightdm-wont-start-automatically-on-boot" target="_blank" rel="noreferrer noopener">Credit</a>):</p>



<pre class="wp-block-code"><code>sudo systemctl set-default graphical.target</code></pre>



<p class="wp-block-paragraph">The decade-old StackExchange thread also has a few other solutions if the above command didn&#8217;t fix the problem.</p>



<h4 class="wp-block-heading">Installing Firefox</h4>



<p class="wp-block-paragraph">Now that you have an OS and a window manager, now you need something to actually display that Grafana dashboard. There&#8217;s probably better and more efficient ways, but I personally use Firefox since it works well enough. Most importantly, it has a built in kiosk mode that can be activated through the command line.</p>



<p class="wp-block-paragraph">First, install Firefox:</p>



<pre class="wp-block-code"><code>sudo apt install firefox-esr</code></pre>



<p class="wp-block-paragraph">Launch Firefox through the right-click menu, and go into settings and disable everything that you can. By disabling everything, it helps to reduce writes to the SD card since Firefox won&#8217;t need to save anything, and it might even free up a bit of memory. A more adventurous user might be interested in <a href="https://github.com/arkenfox/user.js" target="_blank" rel="noreferrer noopener">Arkenfox</a>, which will allow you to disable more stuff beyond the GUI. To run Firefox at startup, create the following file <code>~/.config/openbox/autostart</code> with a text editor, and add the following line:</p>



<pre class="wp-block-code"><code>firefox --kiosk "<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">dashboard-link</mark>"</code></pre>



<p class="wp-block-paragraph">If you haven&#8217;t created a dashboard yet, skip this step for now and come back to it later. If you did, then you should be able to reboot your Pi, and have it automatically display your Grafana dashboard.</p>



<h3 class="wp-block-heading">Grafana</h3>



<p class="wp-block-paragraph">Before you can display your dashboard on your Pi, there&#8217;s a few steps that you need to do to enable anonymous access. You can sign in on your Pi, but I discovered during testing that it likes to sign me out every so often, so it&#8217;s important to enable anonymous access.</p>



<h4 class="wp-block-heading">Anonymous Access</h4>



<p class="wp-block-paragraph">In order to enable anonymous access, open <code>/etc/grafana/grafana.ini</code> in a text editor, and locate the following lines:</p>



<pre class="wp-block-code"><code>#################################### Anonymous Auth ######################
&#91;auth.anonymous]
# enable anonymous access
;enabled = false

# specify organization name that should be used for unauthenticated users
;org_name = Main Org.

# specify role for unauthenticated users
;org_role = Viewer</code></pre>



<p class="wp-block-paragraph">Remove the ;&#8217;s before the lines to uncomment them. For the organization specified in <code>org_name</code>, anonymous users will be able to view all dashboards created in it, so you might want to use a separate one for anonymous access, especially since the default organization specified is the default one. After uncommenting the <code>enabled</code> line, change <code>false</code> to <code>true</code>:</p>



<pre class="wp-block-code"><code>#################################### Anonymous Auth ######################
&#91;auth.anonymous]
# enable anonymous access
enabled = <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">true</mark>

# specify organization name that should be used for unauthenticated users
org_name = <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">Main Org.</mark>

# specify role for unauthenticated users
org_role = Viewer</code></pre>



<p class="wp-block-paragraph">Restart your Grafana server, and try to access it logged out. It should now look similar to how it looked while logged in.</p>



<h4 class="wp-block-heading">Installing and Configuring a JSON Plugin</h4>



<p class="wp-block-paragraph">As far as I&#8217;m aware, there doesn&#8217;t seem to be a plugin for the Openweathermap API, so we&#8217;ll have to do this the manual way. First navigate to the plugins screen:</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="438" height="596" src="https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-11-at-5.36.29-PM.png" alt="" class="wp-image-622" style="width:219px;height:298px" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-11-at-5.36.29-PM.png 438w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-11-at-5.36.29-PM-220x300.png 220w" sizes="auto, (max-width: 438px) 100vw, 438px" /></figure>



<p class="wp-block-paragraph">By default, it might only be showing your installed plugins, so click All:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="54" src="https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-11-at-5.38.03-PM-1-1024x54.png" alt="" class="wp-image-624" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-11-at-5.38.03-PM-1-1024x54.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-11-at-5.38.03-PM-1-300x16.png 300w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-11-at-5.38.03-PM-1-768x41.png 768w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-11-at-5.38.03-PM-1-1536x81.png 1536w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-11-at-5.38.03-PM-1-1568x83.png 1568w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-11-at-5.38.03-PM-1.png 1666w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">Next, type &#8220;json&#8221; into the search bar, and install the plugin that looks like this:</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="624" height="352" src="https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-11-at-5.40.41-PM.png" alt="" class="wp-image-625" style="width:312px;height:176px" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-11-at-5.40.41-PM.png 624w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-11-at-5.40.41-PM-300x169.png 300w" sizes="auto, (max-width: 624px) 100vw, 624px" /></figure>



<p class="wp-block-paragraph">After you&#8217;ve installed the plugin, navigate to the Data Sources tab, click Add data source, then locate JSON API from the list of options:</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="880" height="202" src="https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-11-at-5.41.44-PM.png" alt="" class="wp-image-626" style="width:440px;height:101px" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-11-at-5.41.44-PM.png 880w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-11-at-5.41.44-PM-300x69.png 300w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-11-at-5.41.44-PM-768x176.png 768w" sizes="auto, (max-width: 880px) 100vw, 880px" /></figure>



<p class="wp-block-paragraph">Copy and paste the URL for the Openweathermap API, paste it in URL, and delete everything after the ?. The URL that you paste in should look something like this:</p>



<pre class="wp-block-code"><code>https:&#47;&#47;api.openweathermap.org/data/3.0/onecall?</code></pre>



<p class="wp-block-paragraph">Next, scroll down to Misc, and paste everything after the ? in Query string. The part of the URL that you paste should look something like this:</p>



<pre class="wp-block-code"><code>lat=notmylat&amp;lon=notmylon&amp;units=imperial&amp;appid=notmyapikey</code></pre>



<p class="wp-block-paragraph">The configuration should look something like this:</p>



<figure class="wp-block-image size-large is-resized"><img loading="lazy" decoding="async" width="944" height="1024" src="https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-11-at-5.48.56-PM-944x1024.png" alt="" class="wp-image-627" style="width:472px;height:512px" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-11-at-5.48.56-PM-944x1024.png 944w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-11-at-5.48.56-PM-277x300.png 277w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-11-at-5.48.56-PM-768x833.png 768w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-11-at-5.48.56-PM.png 1208w" sizes="auto, (max-width: 944px) 100vw, 944px" /></figure>



<p class="wp-block-paragraph">Now click Save &amp; Test to save your settings. If everything is working correctly, you should see a green check mark that says Success.</p>



<p class="wp-block-paragraph">Before creating your dashboard, I would recommend messing around in the Explore screen. To actually query data, you&#8217;ll enter what data you want to get by using JSONPath. As an example, if you want to get the current temp and your API response looks something like this:</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="678" height="810" src="https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-7.15.56-PM.png" alt="" class="wp-image-629" style="width:339px;height:405px" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-7.15.56-PM.png 678w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-7.15.56-PM-251x300.png 251w" sizes="auto, (max-width: 678px) 100vw, 678px" /></figure>



<p class="wp-block-paragraph">You&#8217;ll want your JSONPath to look something like this:</p>



<pre class="wp-block-code"><code>$.current.temp</code></pre>



<p class="wp-block-paragraph">The same concept applies if you want to get the content of the <code>description</code> field under the weather field:</p>



<pre class="wp-block-code"><code>$.current.weather.0.description</code></pre>



<p class="wp-block-paragraph">As another example, if you have an API response that looks something like this:</p>



<figure class="wp-block-image size-large is-resized"><img loading="lazy" decoding="async" width="458" height="1024" src="https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-7.18.41-PM-458x1024.png" alt="" class="wp-image-630" style="width:229px;height:512px" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-7.18.41-PM-458x1024.png 458w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-7.18.41-PM-134x300.png 134w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-7.18.41-PM.png 558w" sizes="auto, (max-width: 458px) 100vw, 458px" /></figure>



<p class="wp-block-paragraph">And you want to get all of the values of the <code>precipitation</code> field, your JSONPath would look something like this:</p>



<pre class="wp-block-code"><code>$.minutely.&#91;*].precipitation</code></pre>



<p class="wp-block-paragraph">Here&#8217;s what the JSONPath for one of my panels looks like:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="699" src="https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-7.28.28-PM-1024x699.png" alt="" class="wp-image-631" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-7.28.28-PM-1024x699.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-7.28.28-PM-300x205.png 300w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-7.28.28-PM-768x524.png 768w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-7.28.28-PM-1536x1049.png 1536w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-7.28.28-PM-1568x1070.png 1568w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-7.28.28-PM.png 1998w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">You can define a custom name under alias</figcaption></figure>



<p class="wp-block-paragraph">You probably get the idea, so experiment, and see what you discover and break.</p>



<h4 class="wp-block-heading">Tips with Creating a Grafana Dashboard</h4>



<p class="wp-block-paragraph">Before you create your dashboard, I do have a few tips and tricks I&#8217;ve discovered, and they might even save you a few hours of troubleshooting. Here&#8217;s all of my tips in no particular order:</p>



<h5 class="wp-block-heading">Correct Timestamps from Openweathermap API</h5>



<p class="wp-block-paragraph">Openweathermap returns all dates and times in Unix Epoch, but for whatever reason, having Type set to Auto will cause the time/date to display incorrectly. Set Type to Time to correct this:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="42" src="https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-7.39.23-PM-1024x42.png" alt="" class="wp-image-632" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-7.39.23-PM-1024x42.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-7.39.23-PM-300x12.png 300w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-7.39.23-PM-768x32.png 768w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-7.39.23-PM-1536x63.png 1536w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-7.39.23-PM-1568x65.png 1568w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-7.39.23-PM.png 1944w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<h5 class="wp-block-heading">Openweathermap API Decimal Weirdness</h5>



<p class="wp-block-paragraph">For whatever reason, the Openweathermap API will only display the precipitation probability as a decimal even though it seems to be a percentage. Every other percentage seems to be displayed as a regular number. This isn&#8217;t much of a problem, but it can create issues for panels like one of mine:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="316" src="https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-7.52.04-PM-1024x316.png" alt="" class="wp-image-633" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-7.52.04-PM-1024x316.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-7.52.04-PM-300x93.png 300w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-7.52.04-PM-768x237.png 768w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-7.52.04-PM-1536x474.png 1536w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-7.52.04-PM-1568x484.png 1568w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-7.52.04-PM.png 2010w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">This is how it should look</figcaption></figure>



<p class="wp-block-paragraph">You might want to try and create a field override under the Overrides tab:</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="790" height="562" src="https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-8.02.12-PM.png" alt="" class="wp-image-638" style="width:395px;height:281px" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-8.02.12-PM.png 790w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-8.02.12-PM-300x213.png 300w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-8.02.12-PM-768x546.png 768w" sizes="auto, (max-width: 790px) 100vw, 790px" /></figure>



<p class="wp-block-paragraph">But this is what you&#8217;ll end up with instead:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="317" src="https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-7.55.17-PM-1024x317.png" alt="" class="wp-image-634" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-7.55.17-PM-1024x317.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-7.55.17-PM-300x93.png 300w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-7.55.17-PM-768x238.png 768w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-7.55.17-PM-1536x476.png 1536w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-7.55.17-PM-1568x485.png 1568w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-7.55.17-PM.png 2022w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">This is how it shouldn&#8217;t look</figcaption></figure>



<p class="wp-block-paragraph">Luckily this issue is easily solved by creating a simple transform rule:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="245" src="https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-7.58.22-PM-1024x245.png" alt="" class="wp-image-636" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-7.58.22-PM-1024x245.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-7.58.22-PM-300x72.png 300w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-7.58.22-PM-768x183.png 768w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-7.58.22-PM-1536x367.png 1536w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-7.58.22-PM-1568x374.png 1568w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-7.58.22-PM.png 2010w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">This transform rule will add a new field that will represent the precipitation probability as a number like everything else. You can hide the old field by adding an override that looks something like this:</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="788" height="428" src="https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-8.00.37-PM.png" alt="" class="wp-image-637" style="width:394px;height:214px" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-8.00.37-PM.png 788w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-8.00.37-PM-300x163.png 300w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-12-at-8.00.37-PM-768x417.png 768w" sizes="auto, (max-width: 788px) 100vw, 788px" /></figure>



<h5 class="wp-block-heading">Automatic Grafana Dashboard Update and Kiosk Mode</h5>



<p class="wp-block-paragraph">To make your Grafana dashboard more useful, you&#8217;ll want it to automatically update. Plus, you probably don&#8217;t want to see the sidebar buttons and stuff like that. You could click the TV-looking icon in the top right corner and click the little dropdown next to the refresh button, but you probably don&#8217;t want to do that everytime your Pi reboots. A better solution is to use URL parameters. Simply set your settings to how you want them to be, then copy the URL. Your URL might look something like this:</p>



<pre class="wp-block-code"><code>http://10.0.1.183:3000/d/b7QDxVO4k/pi-dashboard?<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">refresh=15m&amp;kiosk</mark></code></pre>



<p class="wp-block-paragraph">Notice the chances to the URL as you change your settings. You can also use playlists to cycle between multiple dashboards. But keep in mind that they refresh everytime they cycle, so it might be a problem for metered APIs.</p>



<h5 class="wp-block-heading">Automatically Turn The Display On and Off</h5>



<p class="wp-block-paragraph">If you just simply want to disable screen blanking, this can be accomplished by running <code>sudo raspi-config</code>, and disable screen blanking under Display Options.</p>



<p class="wp-block-paragraph">However, if your Pi display is located in a place like your room, chances are you&#8217;ll want to turn the display off at certain hours. Simply run <code>sudo crontab -e</code>, and add the following lines:</p>



<pre class="wp-block-code"><code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">0 21 * * *</mark> sudo sh -c "echo 0 &gt; <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">/sys/class/backlight/10-0045/brightness</mark>"
<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">0 7 * * *</mark> sudo sh -c "echo <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">40</mark> &gt; <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">/sys/class/backlight/10-0045/brightness</mark>"</code></pre>



<p class="wp-block-paragraph">This will turn the display off at 9PM then turn it back on at 7AM. Use a website like <a href="https://crontab.guru/" target="_blank" rel="noreferrer noopener">crontab.guru</a> to create your own crontab expression. Replace 40 with your desired brightness between 0 and 255. <code>/sys/class/backlight/10-0045/brightness</code> was the file that set the brightness of my display, but it might be different on your own set up.</p>



<p class="wp-block-paragraph">Update 2/25/2023: For me at least, a recent update has seem to broken the <code>xset</code> commands for DPMS. Running them will result in nothing happening. From searching around online, other people seem to be complaining about the same problem. However, I haven&#8217;t found a properly working solution that will actually turn off the backlight and not just display a black screen. Your mileage may vary.</p>



<p class="wp-block-paragraph">It&#8217;s also possible to make the display to turn off after a certain period of inactivity instead of at certain times. First, run <code>sudo raspi-config</code>, go to Display Options, then enable screen blanking. You&#8217;ll also want to ensure that the <code>xscreensaver</code> package isn&#8217;t installed. Next, install some packages that you might need (At least for me):</p>



<pre class="wp-block-code"><code>sudo apt install x11-xserver-utils libxcb-dpms0</code></pre>



<p class="wp-block-paragraph">Disable the default screen blanking:</p>



<pre class="wp-block-code"><code>xset s off</code></pre>



<p class="wp-block-paragraph">Then set how long you want your screen to stay on for before turning off:</p>



<pre class="wp-block-code"><code>xset dpms <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">&lt;time in seconds&gt; &lt;time in seconds&gt; &lt;time in seconds&gt;</mark></code></pre>



<p class="wp-block-paragraph">After you&#8217;ve confirmed that these settings work for you, add those two commands to your <code>~/.config/openbox/autostart</code> file (These settings don&#8217;t seem to save on reboot). Here&#8217;s what mine looks like as an example:</p>



<pre class="wp-block-code"><code>xset s off
xset dpms 7200 7200 7200</code></pre>



<p class="wp-block-paragraph">You can also add <code>su username -c "xset -display :0 dpms force off"</code> to your crontab if you still want the screen to turn off at a certain time. Just keep in mind when scripting that these commands can only be run under the same user that your logged into your desktop environment as. </p>



<h5 class="wp-block-heading">Addressing Rate Limiting Issues</h5>



<p class="wp-block-paragraph">From what I can tell, each individual panel will make its own API call even when they&#8217;re all using the same data source. Throw in a 15 minute or so refresh with enough panels, then that&#8217;s a lot of API calls! If you were like me and didn&#8217;t know this then added a bunch of panels, you might&#8217;ve gotten an email that looked like this:</p>



<figure class="wp-block-image size-large is-resized"><img loading="lazy" decoding="async" width="924" height="1024" src="https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-18-at-5.32.05-PM-924x1024.png" alt="" class="wp-image-642" style="width:462px;height:512px" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-18-at-5.32.05-PM-924x1024.png 924w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-18-at-5.32.05-PM-271x300.png 271w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-18-at-5.32.05-PM-768x851.png 768w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-18-at-5.32.05-PM.png 1180w" sizes="auto, (max-width: 924px) 100vw, 924px" /></figure>



<p class="wp-block-paragraph">Then soon discover that your Grafana dashboard was flooded with errors like this one:</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="818" height="152" src="https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-01-08-at-9.29.00-AM.png" alt="" class="wp-image-643" style="width:409px;height:76px" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-01-08-at-9.29.00-AM.png 818w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-01-08-at-9.29.00-AM-300x56.png 300w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-01-08-at-9.29.00-AM-768x143.png 768w" sizes="auto, (max-width: 818px) 100vw, 818px" /></figure>



<p class="wp-block-paragraph">Fortunately, the solution is pretty simple (Besides paying for your API calls). Simply combine multiple similar panels into one:</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="896" height="292" src="https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-18-at-5.39.30-PM.png" alt="" class="wp-image-644" style="width:448px;height:146px" srcset="https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-18-at-5.39.30-PM.png 896w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-18-at-5.39.30-PM-300x98.png 300w, https://alexshomenetwork.com/wp-content/uploads/2023/02/Screen-Shot-2023-02-18-at-5.39.30-PM-768x250.png 768w" sizes="auto, (max-width: 896px) 100vw, 896px" /><figcaption class="wp-element-caption">Looks kinda weird, but it displays normally on my Pi display</figcaption></figure>



<p class="wp-block-paragraph">This should help reduce the amount of API calls that you use and eliminate those errors.</p>



<h3 class="wp-block-heading">Conclusion</h3>



<p class="wp-block-paragraph">This is my first proper blog post, so hopefully you&#8217;ve enjoyed it and learned something new. This was a project that I&#8217;ve completed a couple months before I&#8217;ve gotten around to completing this post. As a result, this blog post a way overdue. If you have any problems, suggestions, or complaints, feel free to leave a comment. I have at least one other blog post in mind, so hopefully it isn&#8217;t as overdue as this one (No guarantees).</p>



<h3 class="wp-block-heading">References</h3>



<p class="wp-block-paragraph">Various sections from Grafana&#8217;s documentation: <a href="https://grafana.com/docs/grafana/latest/" target="_blank" rel="noreferrer noopener">https://grafana.com/docs/grafana/latest/</a></p>



<p class="wp-block-paragraph">I&#8217;ve probably used my plugin&#8217;s docs at some point: <a href="https://grafana.github.io/grafana-json-datasource/" target="_blank" rel="noreferrer noopener">https://grafana.github.io/grafana-json-datasource/</a></p>



<p class="wp-block-paragraph">Since I&#8217;m bad at remembering things sometimes (Part of the reason why this blog post is so late), there&#8217;s probably some other resources that I&#8217;ve forgotten about.</p>
<p>The post <a href="https://alexshomenetwork.com/using-openweathermap-with-grafana-and-displaying-it-on-a-raspberry-pi/">Using Openweathermap with Grafana and Displaying it on a Raspberry Pi Touchscreen</a> appeared first on <a href="https://alexshomenetwork.com">Alex&#039;s Home Network</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://alexshomenetwork.com/using-openweathermap-with-grafana-and-displaying-it-on-a-raspberry-pi/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>Using Cloudflare and Fail2ban with WordPress &#8211; Building a WordPress Blog Part 4</title>
		<link>https://alexshomenetwork.com/using-cloudflare-and-fail2ban-with-wordpress/</link>
					<comments>https://alexshomenetwork.com/using-cloudflare-and-fail2ban-with-wordpress/#respond</comments>
		
		<dc:creator><![CDATA[Alex]]></dc:creator>
		<pubDate>Wed, 28 Dec 2022 01:56:58 +0000</pubDate>
				<category><![CDATA[Self-Hosting]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[Slef-Hosting]]></category>
		<guid isPermaLink="false">https://alexshomenetwork.com/?p=497</guid>

					<description><![CDATA[<p>Now that you&#8217;ve probably followed my last few posts, you should now have a WordPress site that&#8217;s ready to be launched. However, the last thing that you need to happen to your freshly built website is some kid with a bit of skills and a Kali VM or another kid&#8217;s automated script to take it<a class="more-link" href="https://alexshomenetwork.com/using-cloudflare-and-fail2ban-with-wordpress/">Continue reading <span class="screen-reader-text">"Using Cloudflare and Fail2ban with WordPress &#8211; Building a WordPress Blog Part 4"</span></a></p>
<p>The post <a href="https://alexshomenetwork.com/using-cloudflare-and-fail2ban-with-wordpress/">Using Cloudflare and Fail2ban with WordPress &#8211; Building a WordPress Blog Part 4</a> appeared first on <a href="https://alexshomenetwork.com">Alex&#039;s Home Network</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Now that you&#8217;ve probably followed my last few posts, you should now have a WordPress site that&#8217;s ready to be launched. However, the last thing that you need to happen to your freshly built website is some kid with a bit of skills and a Kali VM or another kid&#8217;s automated script to take it down. I&#8217;ve seen a surprising number of WordPress sites that don&#8217;t even have <code>/wp-admin</code> or <code>/wp-login.php</code> firewalled off, let alone how poorly the rest of the website is locked down. Unfortunately you can&#8217;t completely stop the master hacker teenagers, but I&#8217;ll to you how tell mitigate against some common WordPress attacks. I&#8217;m not a security expert, so the majority of what you&#8217;ll see in here is based off of my own findings and what I&#8217;ve heard online.</p>



<h3 class="wp-block-heading">This Post Has Been Replaced</h3>



<p class="wp-block-paragraph">Since this post is from 2022, and I frankly don&#8217;t really like it anymore, I have written an updated version of it. I&#8217;m keeping this post up for archival purposes and in case anyone happens to be curious. If you&#8217;re interested in following this post, please follow my newer one instead.</p>



<p class="wp-block-paragraph">New Post: <a href="https://alexshomenetwork.com/fail2ban-nginx-cloudflare-debian-13/" target="_blank" rel="noreferrer noopener">https://alexshomenetwork.com/fail2ban-nginx-cloudflare-debian-13/</a></p>



<h3 class="wp-block-heading">Prerequisites</h3>



<p class="wp-block-paragraph">There really isn&#8217;t much you need, but make sure that you have the following:</p>



<ul class="wp-block-list">
<li>Full admin access to your WordPress site and full root access to your server. There&#8217;s a few steps that assume that you&#8217;ve already followed my previous posts. All steps assume that you&#8217;re running Debian, but most of them should be applicable to most popular distros.</li>



<li>If you&#8217;re using Cloudflare, then some knowledge of how to use it is required. Also, make sure that the Proxy status is set to Proxied for your DNS records.</li>
</ul>



<h3 class="wp-block-heading">Locking Down /wp-admin and /wp-login.php (And other endpoints)</h3>



<p class="wp-block-paragraph">Despite it being pretty trivial and there being various methods of doing so, it seems to be pretty common for people to leave <code>/wp-admin</code> and <code>/wp-login.php</code> open to the internet. Not only does this give someone the ability to brute force your login, but it&#8217;s also another way for a potential zero-day to be exploited. I&#8217;ll be showing two ways of locking down <code>/wp-admin</code> and <code>/wp-login.php</code> to a specific IP address, but there&#8217;s many different methods. Regardless of what method you use, you&#8217;ll want to whitelist <code>/wp-admin/admin-ajax.php</code> <a href="https://wordpress.stackexchange.com/questions/77407/how-does-admin-ajax-php-work" target="_blank" rel="noreferrer noopener">since it&#8217;s used for WordPress&#8217;s AJAX API</a>, which might cause some issues if it&#8217;s blocked.</p>



<p class="wp-block-paragraph">There&#8217;s also a few different endpoints that you might want to block depending on what you&#8217;re using your website for.  </p>



<h4 class="wp-block-heading">The Cloudflare Way</h4>



<p class="wp-block-paragraph">This is the method that I personally use, and it&#8217;s also easier than the Nginx way if you&#8217;re using Cloudflare. Simply navigate to Cloudflare, click on your website, Security, WAF, and then finally click Create firewall rule. Your rule should look something like this:</p>



<figure class="wp-block-image size-large is-resized"><img loading="lazy" decoding="async" width="1024" height="570" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-21-at-4.56.41-PM-1024x570.png" alt="" class="wp-image-505" style="width:512px;height:285px" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-21-at-4.56.41-PM-1024x570.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-21-at-4.56.41-PM-300x167.png 300w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-21-at-4.56.41-PM-768x428.png 768w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-21-at-4.56.41-PM-1536x856.png 1536w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-21-at-4.56.41-PM-2048x1141.png 2048w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-21-at-4.56.41-PM-1568x873.png 1568w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">You can also click the blue Edit expression link, copy and paste everything in the below code block, and replace the IP addresses with yours:</p>



<pre class="wp-block-code"><code>(http.request.uri contains "wp-admin" and ip.src ne <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">12.34.56.78</mark> and not http.request.uri contains "/wp-admin/admin-ajax.php") or (http.request.uri contains "wp-login.php" and ip.src ne <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">12.34.56.78</mark> and not http.request.uri contains "/wp-admin/admin-ajax.php")</code></pre>



<p class="wp-block-paragraph">Since Cloudflare firewall rules seem to take a bit to update, I would recommend waiting a minute after clicking Save before testing it. To test that your firewall rule works, navigate to <code>/wp-admin</code> and <code>/wp-login.php</code>. Once you&#8217;ve verified that you can still access it, do the same thing on a device with a different IP address. If everything is correct, you&#8217;ll see a screen that looks something like this:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="865" height="163" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-2.44.37-PM.png" alt="" class="wp-image-515" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-2.44.37-PM.png 865w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-2.44.37-PM-300x57.png 300w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-2.44.37-PM-768x145.png 768w" sizes="auto, (max-width: 865px) 100vw, 865px" /></figure>



<h4 class="wp-block-heading">The Nginx Way</h4>



<p class="wp-block-paragraph">Even though using Nginx is a little bit harder, you don&#8217;t need to be using Cloudflare for this step to apply to you. Locate your Nginx server block for your WordPress site (If you&#8217;ve followed my previous posts, then it should be in <code>/etc/nginx/conf.d/wordpress.conf</code>), then add the following lines above the very last <code>}</code> (Replace the IP addresses with yours):</p>



<pre class="wp-block-code"><code>  # wp-admin access
  location /wp-admin/admin-ajax.php {
      allow all;
  } 
  location /wp-admin {
      allow <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">12.34.56.78</mark>;
      deny all;
  }
  location = /wp-login.php {
      allow <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">12.34.56.78</mark>;
      deny all;
  }</code></pre>



<p class="wp-block-paragraph">Test your server block to ensure that it&#8217;s correct:</p>



<pre class="wp-block-code"><code>sudo nginx -t</code></pre>



<p class="wp-block-paragraph">And finally, restart Nginx:</p>



<pre class="wp-block-code"><code>sudo systemctl restart nginx</code></pre>



<p class="wp-block-paragraph">Like with the Cloudflare method, you&#8217;ll want to verify that <code>/wp-admin</code> and <code>/wp-login.php</code> is still accessible for only you, but blocked for everyone else. Try to navigate to <code>/wp-admin</code> and <code>/wp-login.php</code>, and you should still be able to access it. If you can still access it, try to navigate to <code>/wp-admin</code> and <code>/wp-login.php</code> with a device that has a different IP address. That device should be presented with a screen that looks like this:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="265" height="124" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-2.39.33-PM.png" alt="" class="wp-image-514"/></figure>



<h4 class="wp-block-heading">Unable to Block /wp-login.php</h4>



<p class="wp-block-paragraph">If you were (un)lucky like me, then you&#8217;ll quickly notice that instead of your whitelisted IP address getting brought to a WordPress login screen, this will happen instead:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="468" height="59" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-4.08.59-PM.png" alt="" class="wp-image-520" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-4.08.59-PM.png 468w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-4.08.59-PM-300x38.png 300w" sizes="auto, (max-width: 468px) 100vw, 468px" /></figure>



<p class="wp-block-paragraph">What appears to be happening is that Nginx is unable to execute the PHP code for whatever reason, so it&#8217;s just downloading it instead (Not sure if I described the issue correctly, please let me know in the comments if I was wrong).</p>



<p class="wp-block-paragraph">The first thing that I tried was to remove the <code>=</code> sign since I noticed that removing it gave me different results when troubleshooting a different problem:</p>



<pre class="wp-block-code"><code>location /wp-login.php {
      allow <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">12.34.56.78</mark>;
      deny all;
  }</code></pre>



<p class="wp-block-paragraph">The good thing was that my login screen was working again, but the bad thing was that it wasn&#8217;t blocking anything.</p>



<p class="wp-block-paragraph">I also gave up on trying to navigate Nginx&#8217;s documentation, but after searching online and trying many different things, I found <a href="https://wpbeaches.com/block-xmlrpc-php-and-wp-login-php-via-nginx/" target="_blank" rel="noreferrer noopener">this random article</a> that actually worked. Armed with the knowledge from that random article, I looked for the following code in my server block:</p>



<pre class="wp-block-code"><code> }
  location ~ \.php$ {
    fastcgi_pass unix:/run/php/php7.4-fpm.sock;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;
    include snippets/fastcgi-php.conf;

    # Add headers to serve security related headers
    add_header X-Content-Type-Options nosniff;
    add_header X-XSS-Protection "1; mode=block";
    add_header X-Permitted-Cross-Domain-Policies none;
    add_header X-Frame-Options "SAMEORIGIN";
  }</code></pre>



<p class="wp-block-paragraph">And made it look like this:</p>



<pre class="wp-block-code"><code> }
  location ~ \.php$ {
    location ~ \wp-login.php$ {
        allow <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">12.34.56.78</mark>;
        deny all;
        fastcgi_pass unix:/run/php/php7.4-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
        include snippets/fastcgi-php.conf;
    }
    fastcgi_pass unix:/run/php/php7.4-fpm.sock;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;
    include snippets/fastcgi-php.conf;

    # Add headers to serve security related headers
    add_header X-Content-Type-Options nosniff;
    add_header X-XSS-Protection "1; mode=block";
    add_header X-Permitted-Cross-Domain-Policies none;
    add_header X-Frame-Options "SAMEORIGIN";
  }</code></pre>



<p class="wp-block-paragraph">And to my surprise and relief, that actually worked. I don&#8217;t know how it works, so please don&#8217;t ask me to explain it. In the unlikely chance that you came here from a search engine looking to solve the same seemingly strange and obscure problem and I helped you, then you&#8217;re welcome internet stranger ;). If I didn&#8217;t, well I guess good luck on your journey.</p>



<h4 class="wp-block-heading">Blocking xmlrpc.php</h4>



<p class="wp-block-paragraph"><code>xmlrpc.php</code> is used for an old API used to interact with WordPress. Since many API&#8217;s and features have taken its place and it&#8217;s commonly used for exploits, it&#8217;s best to disable it. You can either use a plugin, or firewall it off.</p>



<h4 class="wp-block-heading">Cloudflare</h4>



<p class="wp-block-paragraph">To block this endpoint using Cloudflare, create a new firewall rule that looks something like this:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="145" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-22-at-1.58.09-PM-1024x145.png" alt="" class="wp-image-510" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-22-at-1.58.09-PM-1024x145.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-22-at-1.58.09-PM-300x43.png 300w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-22-at-1.58.09-PM-768x109.png 768w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-22-at-1.58.09-PM.png 1049w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">Like earlier, you&#8217;ll want to wait a minute to let the firewall rule update after clicking Save. After you&#8217;ve waited, try to navigate to <code>/xmlrpc.php</code>, and you should see an Access Denied screen like I showed you earlier.</p>



<h4 class="wp-block-heading">Nginx</h4>



<p class="wp-block-paragraph">Like with blocking <code>/wp-admin</code> and <code>/wp-login.php</code>, all you need to do is locate your Nginx server block, and add the following lines:</p>



<pre class="wp-block-code"><code># Block xmlrpc.php
  location = /xmlrpc.php {
      deny all;
  }</code></pre>



<p class="wp-block-paragraph">Test the server block:</p>



<pre class="wp-block-code"><code>sudo nginx -t</code></pre>



<p class="wp-block-paragraph">Then restart Nginx:</p>



<pre class="wp-block-code"><code>sudo systemctl restart nginx</code></pre>



<p class="wp-block-paragraph">Try to navigate to <code>/xmlrpc.php</code>, and you should get a 403 Forbidden screen like I showed you earlier.</p>



<h4 class="wp-block-heading">Other Endpoints to Block</h4>



<p class="wp-block-paragraph">There&#8217;s a few other endpoints that I would recommend blocking. However, blocking certain ones might cause WordPress to break or not work properly. I&#8217;ll tell you what ones might cause WordPress to break by blocking them.</p>



<ul class="wp-block-list">
<li><code>/feed</code>: This is a list of all of your posts in RSS format. It&#8217;s useful if you&#8217;re making a blog because users can easily add it to an RSS feed reader. It also reveals some information about your website, so if you don&#8217;t need it, then disable it.</li>



<li><code>/wp-json</code>: This appears to be some sort of WordPress JSON API. From what I can tell by looking at logs, it can reveal quite a bit of information about your website. Since there&#8217;s legitimate uses for it, I whitelist it based on IP address like with <code>/wp-admin</code> and <code>/wp-login.php</code>. However, even though I haven&#8217;t had any problems, it doesn&#8217;t mean that doing what I did won&#8217;t cause problems for you. Experiment with firewall rules before doing this on a production website and come to your own conclusions.</li>
</ul>



<p class="wp-block-paragraph">Besides blocking endpoints, you should also disable features that you don&#8217;t need, like comments for example. Usually you&#8217;ll be able to find a plugin that disables what you don&#8217;t need.</p>



<h3 class="wp-block-heading">Correcting IP Addresses in Logs when Behind Cloudflare</h3>



<p class="wp-block-paragraph">If you&#8217;re using Cloudflare, you&#8217;ve probably discovered that the source IP addresses in your Nginx logs are Cloudflare&#8217;s IP address, not your visitors IP address. This can be a problem when running security measures on your server like Fail2ban since they won&#8217;t be able to get the actual IP address. Luckily, this is an easy problem to fix.</p>



<p class="wp-block-paragraph">Open <code>/etc/nginx/nginx.conf</code> in a text editor, and add the following lines below line 37. This will create a new log file called <code>wordpress.log</code>, which will be identical to the default <code>access.log</code>, but it will include your visitors actual IP address:</p>



<pre class="wp-block-code"><code>log_format  wordpress  '$remote_addr - $remote_user &#91;$time_local] "$request" '
                '$status $body_bytes_sent "$http_referer" '
                '"$http_user_agent" "$http_x_forwarded_for" "$http_cf_connecting_ip"';
    access_log /var/log/nginx/wordpress.log wordpress;</code></pre>



<p class="wp-block-paragraph">Next, add a new line under line 66, and paste the following lines below. These are the lines that will get the actual IP address from Cloudflare (By the time you&#8217;re reading this, Cloudflare might have changed their IP address slightly, so check <a href="https://www.cloudflare.com/ips/" target="_blank" rel="noreferrer noopener">here</a>):</p>



<pre class="wp-block-code"><code># Get actual IP address from Cloudflare
    set_real_ip_from 103.21.244.0/22;
    set_real_ip_from 103.22.200.0/22;
    set_real_ip_from 103.31.4.0/22;
    set_real_ip_from 104.16.0.0/12;
    set_real_ip_from 104.24.0.0/14;
    set_real_ip_from 108.162.192.0/18;
    set_real_ip_from 131.0.72.0/22;
    set_real_ip_from 141.101.64.0/18;
    set_real_ip_from 162.158.0.0/15;
    set_real_ip_from 172.64.0.0/13;
    set_real_ip_from 173.245.48.0/20;
    set_real_ip_from 188.114.96.0/20;
    set_real_ip_from 190.93.240.0/20;
    set_real_ip_from 197.234.240.0/22;
    set_real_ip_from 198.41.128.0/17;
    set_real_ip_from 2400:cb00::/32;
    set_real_ip_from 2606:4700::/32;
    set_real_ip_from 2803:f800::/32;
    set_real_ip_from 2405:b500::/32;
    set_real_ip_from 2405:8100::/32;
    set_real_ip_from 2c0f:f248::/32;
    set_real_ip_from 2a06:98c0::/29;
    set_real_ip_from 2c0f:f248::/32;
    real_ip_header X-Forwarded-For;</code></pre>



<p class="wp-block-paragraph">When you&#8217;re done, make sure to test the configuration file and restart Nginx. After that, you should start seeing your visitors IP address in <code>wordpress.log</code>.</p>



<h3 class="wp-block-heading">Sucuri Security</h3>



<p class="wp-block-paragraph">Sucuri Security is a WordPress security plugin that can do stuff like audit logins, scan your website for malicious code, and many other things. I&#8217;ll be showing you how to configure some of the features. I recommend that you look through all of the settings yourself and configure everything to your specific needs. </p>



<h4 class="wp-block-heading">Enable The WordPress Integrity Diff Utility</h4>



<p class="wp-block-paragraph">This feature will show the differences between WordPress files stored on your web server and ones provided by WordPress. After you install the plugin, select Sucuri Security, then Settings:</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="320" height="324" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.12.42-PM.png" alt="" class="wp-image-524" style="width:240px;height:243px" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.12.42-PM.png 320w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.12.42-PM-296x300.png 296w" sizes="auto, (max-width: 320px) 100vw, 320px" /></figure>



<p class="wp-block-paragraph">Select the Scanner tab:</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="878" height="320" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.12.52-PM.png" alt="" class="wp-image-525" style="width:439px;height:160px" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.12.52-PM.png 878w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.12.52-PM-300x109.png 300w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.12.52-PM-768x280.png 768w" sizes="auto, (max-width: 878px) 100vw, 878px" /></figure>



<p class="wp-block-paragraph">And finally, scroll down to WordPress Integrity Diff Utility, and click Enable:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="197" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.13.37-PM-1024x197.png" alt="" class="wp-image-526" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.13.37-PM-1024x197.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.13.37-PM-300x58.png 300w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.13.37-PM-768x148.png 768w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.13.37-PM-1536x295.png 1536w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.13.37-PM-2048x394.png 2048w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.13.37-PM-1568x301.png 1568w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<h4 class="wp-block-heading">Apply Hardening Options</h4>



<p class="wp-block-paragraph">There&#8217;s a few options under here that will make your WordPress site a little bit more secure by doing stuff like removing unnecessary files. Assuming that you&#8217;re still at the same screen as the previous step, click the Hardening tab:</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="938" height="286" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.18.16-PM.png" alt="" class="wp-image-528" style="width:469px;height:143px" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.18.16-PM.png 938w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.18.16-PM-300x91.png 300w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.18.16-PM-768x234.png 768w" sizes="auto, (max-width: 938px) 100vw, 938px" /></figure>



<p class="wp-block-paragraph">Then under hardening options, select the options that you see fit (I still want the theme and plugin editor):</p>



<figure class="wp-block-image size-large is-resized"><img loading="lazy" decoding="async" width="1024" height="595" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.18.36-PM-1024x595.png" alt="" class="wp-image-529" style="width:512px;height:298px" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.18.36-PM-1024x595.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.18.36-PM-300x174.png 300w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.18.36-PM-768x446.png 768w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.18.36-PM-1536x893.png 1536w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.18.36-PM-2048x1190.png 2048w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.18.36-PM-1568x911.png 1568w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">If you want to change how often the secret keys are updated (Determines how often you&#8217;ll need to log in again), select the Post-Hack tab:</p>



<figure class="wp-block-image size-large is-resized"><img loading="lazy" decoding="async" width="1024" height="282" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.28.27-PM-1024x282.png" alt="" class="wp-image-531" style="width:512px;height:141px" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.28.27-PM-1024x282.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.28.27-PM-300x82.png 300w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.28.27-PM-768x211.png 768w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.28.27-PM.png 1084w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">Then from the dropdown, choose an option that you see fit:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="114" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.29.35-PM-1024x114.png" alt="" class="wp-image-530" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.29.35-PM-1024x114.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.29.35-PM-300x33.png 300w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.29.35-PM-768x86.png 768w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.29.35-PM-1536x171.png 1536w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.29.35-PM-2048x228.png 2048w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.29.35-PM-1568x175.png 1568w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<h4 class="wp-block-heading">Enable Email Alerts</h4>



<p class="wp-block-paragraph">To enable email alerts, select the Alerts tab:</p>



<figure class="wp-block-image size-large is-resized"><img loading="lazy" decoding="async" width="1024" height="262" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.36.56-PM-1024x262.png" alt="" class="wp-image-534" style="width:512px;height:131px" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.36.56-PM-1024x262.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.36.56-PM-300x77.png 300w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.36.56-PM-768x197.png 768w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.36.56-PM.png 1156w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">Enter an email address, then click submit (Remove email@example.com first):</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="282" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.37.10-PM-1024x282.png" alt="" class="wp-image-535" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.37.10-PM-1024x282.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.37.10-PM-300x83.png 300w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.37.10-PM-768x212.png 768w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.37.10-PM-1536x424.png 1536w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.37.10-PM-2048x565.png 2048w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-23-at-6.37.10-PM-1568x433.png 1568w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">Then finally, scroll through all of the options on that page and configure them as you see fit.</p>



<h3 class="wp-block-heading">Fail2ban</h3>



<p class="wp-block-paragraph">Fail2ban is a neat little program that runs on your server that will check your logs, and if a certain IP address keeps matching a specific configured pattern within a certain amount of time, then it will block it. This only scratches the surface of what it can do. I&#8217;ll be showing you how to use Fail2ban to block IP addresses that are causing too many 4xx errors. There&#8217;s many automated scripts scanning websites on the internet, and since they&#8217;re trying to probe your website for vulnerabilities, naturally they&#8217;ll cause a lot of 4xx and other similar errors. </p>



<h4 class="wp-block-heading">Installation</h4>



<p class="wp-block-paragraph">First, install Fail2ban, and select yes on all of the prompts:</p>



<pre class="wp-block-code"><code>sudo apt install fail2ban iptables iptables-persistent</code></pre>



<p class="wp-block-paragraph">Start Fail2ban:</p>



<pre class="wp-block-code"><code>sudo systemctl start fail2ban</code></pre>



<p class="wp-block-paragraph">And verify it&#8217;s running by using one of the two commands:</p>



<pre class="wp-block-code"><code>sudo systemctl status fail2ban</code></pre>



<p class="wp-block-paragraph">Or:</p>



<pre class="wp-block-code"><code>sudo fail2ban-client status</code></pre>



<p class="wp-block-paragraph">Once you&#8217;ve verified that Fail2ban is running correctly, allow it to run at startup:</p>



<pre class="wp-block-code"><code>sudo systemctl enable fail2ban</code></pre>



<p class="wp-block-paragraph">After you install Fail2ban, open <code>/etc/fail2ban/fail2ban.conf</code> in a text editor, and look for line 69 (Nice). Chances are you won&#8217;t want it to wipe the database after a single day, so change it to something longer like 99 years (Or shorter if you want it to wipe it at some point):</p>



<pre class="wp-block-code"><code>dbpurgeage = <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">99y</mark></code></pre>



<p class="wp-block-paragraph">Save the file, then restart Fail2ban:</p>



<pre class="wp-block-code"><code>sudo systemctl restart fail2ban</code></pre>



<h4 class="wp-block-heading">Jail Configuration</h4>



<p class="wp-block-paragraph">By default, Fail2ban doesn&#8217;t have a filter for matching Nginx 4xx errors, so we&#8217;ll have to create one ourselves. Create a new file in <code>/etc/fail2ban/filter.d/</code>, and name it <code>nginx-4xx.conf</code>, then add the following lines (<a href="https://gist.github.com/AysadKozanoglu/1335735272fb3b00a03bd3eea22af818" target="_blank" rel="noreferrer noopener">Regex I used, I slightly modified it</a>):</p>



<pre class="wp-block-code"><code>&#91;Definition]
failregex = ^&lt;HOST&gt;.*"(GET|POST).*" (401|403|404|444) .*$
ignoreregex = </code></pre>



<p class="wp-block-paragraph">Next, open <code>/etc/fail2ban/jail.conf</code> in a text editor, and go to line 47. Uncomment <code>bantime.rndtime</code>, and add a value that you see fit:</p>



<pre class="wp-block-code"><code># "bantime.rndtime" is the max number of seconds using for mixing with random time 
# to prevent "clever" botnets calculate exact time IP can be unbanned again:
bantime.rndtime = <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">24h</mark></code></pre>



<p class="wp-block-paragraph">Paste the following code block starting at line 274. Change the highlighted values as you see fit, and also experiment with these settings first so you don&#8217;t ban legitimate users. If you you didn&#8217;t follow my steps for correcting IP addresses when behind Cloudflare, <code>logpath</code> should be <code>/var/log/nginx/access.log</code>:</p>



<pre class="wp-block-code"><code>&#91;nginx-4xx]
enabled = true
port = http,https
logpath = <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">/var/log/nginx/wordpress.log</mark>
maxretry = <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">5</mark>
findtime = <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">10m</mark>
bantime = <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">30m</mark>
action = iptables-allports</code></pre>



<p class="wp-block-paragraph">After you&#8217;ve saved the file and restarted Fail2ban, test it out. It might not seem like that it&#8217;s working at first since Fail2ban checks the log every few seconds (At least from what I can tell, not sure how often it actually gets checked). If you&#8217;re using Cloudflare, skip to the Cloudflare section since there&#8217;s additional steps that you need to do.</p>



<p class="wp-block-paragraph">After you&#8217;ve verified that your IP was banned, unban it:</p>



<pre class="wp-block-code"><code>sudo fail2ban-client unban <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">12.34.56.78</mark></code></pre>



<p class="wp-block-paragraph">And so you don&#8217;t accidentally ban your own IP like I&#8217;ve down multiple times, look for line 92 in <code>/etc/fail2ban/jail.conf</code>, uncomment it, and add your IP address:</p>



<pre class="wp-block-code"><code>ignoreip = 127.0.0.1/8 ::1 <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">12.34.56.78</mark></code></pre>



<h4 class="wp-block-heading">Cloudflare</h4>



<p class="wp-block-paragraph">If you tried to have Fail2ban ban your IP address, you&#8217;ll probably notice that your IP address wasn&#8217;t banned (Or in my case, IPv6 IP&#8217;s weren&#8217;t getting banned, but IPv4 IP&#8217;s were) despite <code>sudo iptables -L </code>or <code>sudo ip6tables -L</code> showing your IP address getting blocked. Luckily the solution is easy.</p>



<p class="wp-block-paragraph">First, log into your Cloudflare dashboard, click the person icon in the top right corner, then click My Profile:</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="788" height="732" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-24-at-3.45.10-PM.png" alt="" class="wp-image-545" style="width:394px;height:366px" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-24-at-3.45.10-PM.png 788w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-24-at-3.45.10-PM-300x279.png 300w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-24-at-3.45.10-PM-768x713.png 768w" sizes="auto, (max-width: 788px) 100vw, 788px" /></figure>



<p class="wp-block-paragraph">Select API Tokens from the sidebar:</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="522" height="520" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-24-at-4.49.14-PM.png" alt="" class="wp-image-546" style="width:392px;height:390px" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-24-at-4.49.14-PM.png 522w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-24-at-4.49.14-PM-300x300.png 300w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-24-at-4.49.14-PM-150x150.png 150w" sizes="auto, (max-width: 522px) 100vw, 522px" /></figure>



<p class="wp-block-paragraph">Scroll down to API Keys, then click the View button by Global API Key:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="269" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-24-at-3.45.56-PM-1024x269.png" alt="" class="wp-image-547" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-24-at-3.45.56-PM-1024x269.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-24-at-3.45.56-PM-300x79.png 300w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-24-at-3.45.56-PM-768x202.png 768w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-24-at-3.45.56-PM-1536x404.png 1536w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-24-at-3.45.56-PM-2048x539.png 2048w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-24-at-3.45.56-PM-1568x413.png 1568w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">After you&#8217;ve entered your password, copy this API key and save it somewhere secure. You&#8217;ll need it later:</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="970" height="614" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-24-at-3.53.18-PM.png" alt="" class="wp-image-548" style="width:485px;height:307px" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-24-at-3.53.18-PM.png 970w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-24-at-3.53.18-PM-300x190.png 300w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-24-at-3.53.18-PM-768x486.png 768w" sizes="auto, (max-width: 970px) 100vw, 970px" /><figcaption class="wp-element-caption">It&#8217;s a fake API key, don&#8217;t bother trying it</figcaption></figure>



<p class="wp-block-paragraph">Go back to your server, open <code>/etc/fail2ban/action.d/cloudflare.conf</code>, and scroll down to line 81. You&#8217;ll paste your API key next to <code>cftoken</code>, and enter the email address associated with your Cloudflare account next to <code>cfuser</code>. It should look something like the example below:</p>



<pre class="wp-block-code"><code>cftoken = <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">4655434b594f554e49434b554b4e4f5757484f55415245</mark>

cfuser = <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">email@example.com</mark></code></pre>



<p class="wp-block-paragraph">Open up <code>jail.conf</code> again, scroll down to where you&#8217;ve added the jail, and add <code>cloudflare</code> to the action line:</p>



<pre class="wp-block-code"><code>action = iptables-allports <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">cloudflare</mark></code></pre>



<p class="wp-block-paragraph">Before testing, just be aware that banning an IP through Cloudflare might take a little bit. This is because not only do you have to wait for Fail2ban to check your Nginx logs, but you also have to wait for Cloudflare to ban the IP as well, which seem to take at least 10 seconds.</p>



<p class="wp-block-paragraph">Once your IP address has been banned, you can view the ban in the WAF settings under the Tools tab and IP Access Rules, and it should look something like this:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="86" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-24-at-4.44.30-PM-1024x86.png" alt="" class="wp-image-549" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-24-at-4.44.30-PM-1024x86.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-24-at-4.44.30-PM-300x25.png 300w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-24-at-4.44.30-PM-768x65.png 768w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-24-at-4.44.30-PM-1536x130.png 1536w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-24-at-4.44.30-PM-1568x132.png 1568w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-24-at-4.44.30-PM.png 2040w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">You can unban your IP by either clicking the X button, or use the <code>fail2ban-client</code> command I showed you earlier. Don&#8217;t forget to add your IP address under <code>ignoreip</code> in <code>jail.conf</code> so you don&#8217;t ban yourself by accident.</p>



<h4 class="wp-block-heading">Making the Fail2ban Service Apart of the Nginx Service</h4>



<p class="wp-block-paragraph">If the Fail2ban service happens to crash, then you&#8217;ll loose the benefits of Fail2ban. However, if you wanted to, you can make it so if Fail2ban crashes, then it takes Nginx down with it. This also means that your website will be down until Fail2ban and Nginx is restarted, so only do this if you don&#8217;t mind potentially loosing uptime.</p>



<p class="wp-block-paragraph">All you need to do is edit <code>/lib/systemd/system/nginx.service</code>, and add the highlighted line:</p>



<pre class="wp-block-code"><code>&#91;Unit]
Description=A high performance web server and a reverse proxy server
Documentation=man:nginx(8)
<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">BindsTo=fail2ban.service</mark>
After=network.target nss-lookup.target</code></pre>



<p class="wp-block-paragraph">Run the following command to make systemd pick up the changes you made:</p>



<pre class="wp-block-code"><code>sudo systemctl daemon-reload</code></pre>



<p class="wp-block-paragraph">Then to test this, kill Fail2ban:</p>



<pre class="wp-block-code"><code>sudo pkill fail2ban</code></pre>



<p class="wp-block-paragraph">Check the status of Fail2ban to ensure that it&#8217;s not running:</p>



<pre class="wp-block-code"><code>sudo systemctl status fail2ban</code></pre>



<p class="wp-block-paragraph">Then check to see if Nginx is also stopped:</p>



<pre class="wp-block-code"><code>sudo systemctl status fail2ban</code></pre>



<p class="wp-block-paragraph">Both services should be stopped, and you should be able to restart both services.</p>



<h3 class="wp-block-heading">Cloudflare Settings</h3>



<p class="wp-block-paragraph">If you&#8217;re using Cloudflare, there&#8217;s some settings that you might want to look at or change. I&#8217;ll be showing what settings I personally use on both of my websites.</p>



<h4 class="wp-block-heading">SSL/TLS Settings</h4>



<p class="wp-block-paragraph">To access these settings, simply click the SSL/TLS button after clicking your website when you log in:</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="520" height="440" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-27-at-4.34.24-PM.png" alt="" class="wp-image-568" style="width:260px;height:220px" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-27-at-4.34.24-PM.png 520w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-27-at-4.34.24-PM-300x254.png 300w" sizes="auto, (max-width: 520px) 100vw, 520px" /></figure>



<p class="wp-block-paragraph">Under Overview, there really isn&#8217;t a whole lot to change. I recommend selecting Full (Strict) for the SSL/TLS mode. If you can&#8217;t choose Full (Strict), you can also enable the SSL/TLS Recommender if you want Cloudflare to check if your website can use a more secure SSL/TLS mode.</p>



<p class="wp-block-paragraph">Next, select Edge Certificates in the sidebar: </p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="514" height="494" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-27-at-4.55.40-PM.png" alt="" class="wp-image-570" style="width:257px;height:247px" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-27-at-4.55.40-PM.png 514w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-27-at-4.55.40-PM-300x288.png 300w" sizes="auto, (max-width: 514px) 100vw, 514px" /></figure>



<p class="wp-block-paragraph">I have all of the options under here enabled, and I keep the Minimum TLS Version at the default. I also have HSTS enabled, but make sure to read the warning first before enabling it.</p>



<h4 class="wp-block-heading">Security Settings</h4>



<p class="wp-block-paragraph">Accessing these settings as just as easy as accessing the SSL/TLS settings. All you need to do is just click the Security then WAF button:</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="512" height="574" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-27-at-5.13.55-PM.png" alt="" class="wp-image-571" style="width:256px;height:287px" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-27-at-5.13.55-PM.png 512w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-27-at-5.13.55-PM-268x300.png 268w" sizes="auto, (max-width: 512px) 100vw, 512px" /></figure>



<p class="wp-block-paragraph">Create a rate limiting rule to help mitigate against DDoS attacks. If you&#8217;re using a crappy server like me, then this is especially important. Simply click on the Rate limiting rules tab, then Create rule:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="346" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-27-at-5.14.33-PM-1024x346.png" alt="" class="wp-image-572" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-27-at-5.14.33-PM-1024x346.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-27-at-5.14.33-PM-300x101.png 300w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-27-at-5.14.33-PM-768x259.png 768w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-27-at-5.14.33-PM-1536x519.png 1536w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-27-at-5.14.33-PM-2048x692.png 2048w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-27-at-5.14.33-PM-1568x530.png 1568w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">If you want it to match everything, then set it to if URI path contains /. Then for the rest of the settings, choose them as you see fit. I originally had it set to 100 requests within 10 seconds, but I had problems with it being too strict.</p>



<p class="wp-block-paragraph">After you&#8217;ve configured rate limiting, select Settings in the sidebar:</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="516" height="580" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-27-at-5.14.57-PM.png" alt="" class="wp-image-573" style="width:258px;height:290px" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-27-at-5.14.57-PM.png 516w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-27-at-5.14.57-PM-267x300.png 267w" sizes="auto, (max-width: 516px) 100vw, 516px" /></figure>



<p class="wp-block-paragraph">I have everything turned on here. I have Security Level set to High, and I have Challenge Passage set to 1 day. The default security level isn&#8217;t strict enough, and if a visitor had completed a Cloudflare challenge, then they won&#8217;t have to do it again for 1 day.</p>



<h4 class="wp-block-heading">Caching Settings</h4>



<p class="wp-block-paragraph">To access these settings, simply click Caching in the sidebar, then Configuration:</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="516" height="492" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-27-at-5.15.05-PM.png" alt="" class="wp-image-574" style="width:258px;height:246px" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-27-at-5.15.05-PM.png 516w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-27-at-5.15.05-PM-300x286.png 300w" sizes="auto, (max-width: 516px) 100vw, 516px" /></figure>



<p class="wp-block-paragraph">I only changed three settings in this menu. I have both Always Online and Crawler hints enabled, and I have Browser Cache TTL set to 1 month. Always Online is an especially neat feature because if your server goes down, then it will display a copy from the Wayback Machine instead. If you&#8217;re not changing stuff all that often on your website, then a longer browser cache TTL can help speed up your website and reduce bandwidth for repeat visitors.</p>



<p class="wp-block-paragraph">Click Tiered Cache in the sidebar, and then enable Argo Tiered Cache. According to Cloudflare, this does some fancy magic routing to help improve performance and reduce bandwidth on your server.</p>



<h4 class="wp-block-heading">Page Rules</h4>



<p class="wp-block-paragraph">Since some of Cloudflare&#8217;s features like caching can cause issues on <code>/wp-admin</code>, it&#8217;s best to disable them. This is easily possible thanks to Page Rules. From the sidebar, select Rules:</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="528" height="582" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-27-at-5.15.22-PM.png" alt="" class="wp-image-575" style="width:264px;height:291px" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-27-at-5.15.22-PM.png 528w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-27-at-5.15.22-PM-272x300.png 272w" sizes="auto, (max-width: 528px) 100vw, 528px" /></figure>



<p class="wp-block-paragraph">Click Create Page Rule to create a new rule:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="283" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-27-at-5.15.47-PM-1024x283.png" alt="" class="wp-image-576" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-27-at-5.15.47-PM-1024x283.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-27-at-5.15.47-PM-300x83.png 300w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-27-at-5.15.47-PM-768x212.png 768w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-27-at-5.15.47-PM-1536x424.png 1536w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-27-at-5.15.47-PM-2048x566.png 2048w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-27-at-5.15.47-PM-1568x433.png 1568w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">Your page rule should look something like this, and replace example.com with your domain name:</p>



<figure class="wp-block-image size-large is-resized"><img loading="lazy" decoding="async" width="1024" height="708" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-27-at-5.17.11-PM-1024x708.png" alt="" class="wp-image-577" style="width:512px;height:354px" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-27-at-5.17.11-PM-1024x708.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-27-at-5.17.11-PM-300x207.png 300w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-27-at-5.17.11-PM-768x531.png 768w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-27-at-5.17.11-PM-1536x1062.png 1536w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-27-at-5.17.11-PM.png 1554w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">After clicking Save Page Rule, this will disable Cloudflare&#8217;s features just on <code>/wp-admin</code> while leaving them enabled for everywhere else on your website.</p>



<h3 class="wp-block-heading">Conclusion</h3>



<p class="wp-block-paragraph">I hope you enjoyed reading this post and this series in general, and maybe learned something new in the process. I definitely learned a lot about writing blog posts, which is why I decided to include a dedicated heading section. If you&#8217;ve read through all of my posts in their entirety, I bet that there&#8217;s probably some minor differences that I haven&#8217;t even noticed. If you&#8217;re getting tired of this series, don&#8217;t worry, since I have plans to write actually interesting stuff. Hell even I&#8217;m getting tired of writing posts for a series that people probably don&#8217;t want to read, so I&#8217;m glad that I stuck to writing only four parts. </p>



<p class="wp-block-paragraph">Like usual, if you have a suggestion, problem, or complaint, then leave a comment, and I&#8217;ll try my best to address it.</p>



<h3 class="wp-block-heading">References</h3>



<p class="wp-block-paragraph">A lot of my information is from looking at configuration files since I&#8217;ve forgotten how I did some stuff and what tutorials I followed.</p>



<p class="wp-block-paragraph">These random tutorials did a better job of telling me how to block paths in Nginx than Nginx&#8217;s own documentation: <a href="https://www.linuxshelltips.com/block-access-wp-admin-and-wp-login/" target="_blank" rel="noreferrer noopener">https://www.linuxshelltips.com/block-access-wp-admin-and-wp-login/</a>, <a href="https://www.linuxshelltips.com/block-xml-rpc-in-wordpress/" target="_blank" rel="noreferrer noopener">https://www.linuxshelltips.com/block-xml-rpc-in-wordpress/</a></p>



<p class="wp-block-paragraph">Using Fail2ban with Cloudflare: <a href="https://gridpane.com/kb/using-fail2ban-with-cloudflare/" target="_blank" rel="noreferrer noopener">https://gridpane.com/kb/using-fail2ban-with-cloudflare/</a></p>
<p>The post <a href="https://alexshomenetwork.com/using-cloudflare-and-fail2ban-with-wordpress/">Using Cloudflare and Fail2ban with WordPress &#8211; Building a WordPress Blog Part 4</a> appeared first on <a href="https://alexshomenetwork.com">Alex&#039;s Home Network</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://alexshomenetwork.com/using-cloudflare-and-fail2ban-with-wordpress/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>My Top Picks for WordPress Plugins (Comments, Security, Email) &#8211; Building a WordPress Blog Part 3</title>
		<link>https://alexshomenetwork.com/my-top-picks-for-wordpress-plugins/</link>
					<comments>https://alexshomenetwork.com/my-top-picks-for-wordpress-plugins/#comments</comments>
		
		<dc:creator><![CDATA[Alex]]></dc:creator>
		<pubDate>Mon, 19 Dec 2022 21:28:29 +0000</pubDate>
				<category><![CDATA[Self-Hosting]]></category>
		<category><![CDATA[WordPress]]></category>
		<guid isPermaLink="false">https://alexshomenetwork.com/?p=428</guid>

					<description><![CDATA[<p>After following my previous post, you should now have a fully working WordPress install ready for you to build your own website. When you first tried to build your website, you were probably thinking to yourself something along the lines of, &#8220;Man, this WordPress thing doesn&#8217;t have a lot of features. It would be nice<a class="more-link" href="https://alexshomenetwork.com/my-top-picks-for-wordpress-plugins/">Continue reading <span class="screen-reader-text">"My Top Picks for WordPress Plugins (Comments, Security, Email) &#8211; Building a WordPress Blog Part 3"</span></a></p>
<p>The post <a href="https://alexshomenetwork.com/my-top-picks-for-wordpress-plugins/">My Top Picks for WordPress Plugins (Comments, Security, Email) &#8211; Building a WordPress Blog Part 3</a> appeared first on <a href="https://alexshomenetwork.com">Alex&#039;s Home Network</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">After following my <a href="https://alexshomenetwork.com/installing-wordpress-on-lemp-stack/" target="_blank" rel="noreferrer noopener">previous post</a>, you should now have a fully working WordPress install ready for you to build your own website. When you first tried to build your website, you were probably thinking to yourself something along the lines of, &#8220;Man, this WordPress thing doesn&#8217;t have a lot of features. It would be nice to have at least some functionality.&#8221; You&#8217;re definitely not alone, so here&#8217;s the WordPress plugins that I personally use on this blog and on <a href="https://mostepicwebsite.com/" target="_blank" rel="noreferrer noopener">mostepicwebsite.com</a>. They might not be the best plugins in the world, but I&#8217;m using the free version of all of them, and they work well enough despite half of them begging me to pay for them. Let me know in the comments if you have any more suggestions for plugins.</p>



<h3 class="wp-block-heading">Comments</h3>



<p class="wp-block-paragraph">It may seem trivial, but this was actually pretty difficult for me when building this blog. I ran into various roadblocks like fighting off spam bots, or if I should require users to create an account. It didn&#8217;t help that by default, WordPress had basically no customization options for the comment box. After trying out many different WordPress plugins and lots of experimenting, but in the end, I settled on allowing users to comment anonymously, and a WordPress plugin for the comment box so I get the features I want.</p>



<h4 class="wp-block-heading">wpDiscuz</h4>



<p class="wp-block-paragraph">That WordPress plugin I decided to use was wpDiscuz. What I like about this plugin is that it has lots of customization features, and most importantly, it has support for reCAPTCHA and email notifications (Although they didn&#8217;t seem to work in testing). There&#8217;s a few minor issues that I have with it like the formatting in the comment box looking different than what is displayed after you click &#8220;Post Comment&#8221;, and there&#8217;s some weird UX issues (Users don&#8217;t have the ability to delete comments, which is something I wanted), but overall it seems to get the job done just fine.</p>



<figure class="wp-block-image size-large is-resized"><img loading="lazy" decoding="async" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-15-at-5.09.43-PM-1024x1002.png" alt="" class="wp-image-437" width="512" height="501" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-15-at-5.09.43-PM-1024x1002.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-15-at-5.09.43-PM-300x293.png 300w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-15-at-5.09.43-PM-768x751.png 768w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-15-at-5.09.43-PM-1536x1502.png 1536w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-15-at-5.09.43-PM.png 1548w" sizes="auto, (max-width: 512px) 100vw, 512px" /><figcaption class="wp-element-caption">This comment was from a friend of mine.</figcaption></figure>



<p class="wp-block-paragraph"><a href="https://wordpress.org/plugins/wpdiscuz/" target="_blank" rel="noreferrer noopener">Details on wordpress.org</a></p>



<h4 class="wp-block-heading">Akismet Anti-Spam</h4>



<p class="wp-block-paragraph">As it&#8217;s name implies, this plugin is a simple anti-spam plugin already included with every WordPress installation. All you need to do is create an Akismet account, enter your API key, then you&#8217;re basically all set. There&#8217;s a few simple options, but the defaults will be just fine for most people.</p>



<figure class="wp-block-image size-large is-resized"><img loading="lazy" decoding="async" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-15-at-5.29.48-PM-1024x938.png" alt="" class="wp-image-445" width="512" height="469" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-15-at-5.29.48-PM-1024x938.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-15-at-5.29.48-PM-300x275.png 300w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-15-at-5.29.48-PM-768x704.png 768w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-15-at-5.29.48-PM.png 1458w" sizes="auto, (max-width: 512px) 100vw, 512px" /><figcaption class="wp-element-caption">Not a real API key, obviously</figcaption></figure>



<p class="wp-block-paragraph"><a href="https://wordpress.org/plugins/akismet/" target="_blank" rel="noreferrer noopener">Details on wordpress.org</a></p>



<h3 class="wp-block-heading">Email Notifications and Newsletter</h3>



<p class="wp-block-paragraph">This was another seemingly trivial thing that took a lot of experimenting a deciding (More specifically, newsletters). In the end, I decided to do everything through WordPress, mainly because it&#8217;s more convenient, and I can more easily switch email providers if I find a better one. </p>



<h4 class="wp-block-heading">WP Mail SMTP</h4>



<p class="wp-block-paragraph">It might not have a very catchy name, but as its name also implies, this is a WordPress plugin for sending emails. By default, WordPress will use PHP to send emails, however, it&#8217;s not nearly as reliable as using a service like Sendinblue (What I&#8217;m currently using, no affiliate plug this time), and also most hosting providers block SMTP port 25. This will result in your emails having a much greater chance of not being delivered or going to spam. They do have a pro version with more features and customization, but the free version is good enough.</p>



<figure class="wp-block-image size-large is-resized"><img loading="lazy" decoding="async" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-17-at-5.05.59-PM-1024x861.png" alt="" class="wp-image-449" width="512" height="431" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-17-at-5.05.59-PM-1024x861.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-17-at-5.05.59-PM-300x252.png 300w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-17-at-5.05.59-PM-768x646.png 768w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-17-at-5.05.59-PM-1536x1292.png 1536w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-17-at-5.05.59-PM-1568x1319.png 1568w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-17-at-5.05.59-PM.png 1712w" sizes="auto, (max-width: 512px) 100vw, 512px" /></figure>



<p class="wp-block-paragraph"><a href="https://wordpress.org/plugins/wp-mail-smtp/" target="_blank" rel="noreferrer noopener">Details on wordpress.org</a></p>



<h4 class="wp-block-heading">FluentCRM and Fluent Forms</h4>



<p class="wp-block-paragraph">After trying out various plugins and what Sendinblue has to offer, I decided to FluentCRM with Fluent Forms. Like every WordPress plugin, they beg you to pay for it, but luckily the free version has a decent amount of features. The main features that I wanted were mandating that users click on a link in a confirmation email to be subscribed, and also reCAPTCHA support. There was a surprising number of plugins that either lacked at least one of these features, or had the features I wanted behind a paywall, so it was relieving seeing that these plugins had those features for free. </p>



<p class="wp-block-paragraph">FluentCRM:</p>



<figure class="wp-block-image size-large is-resized"><img loading="lazy" decoding="async" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-17-at-5.32.34-PM-1024x811.png" alt="" class="wp-image-452" width="512" height="406" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-17-at-5.32.34-PM-1024x811.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-17-at-5.32.34-PM-300x238.png 300w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-17-at-5.32.34-PM-768x608.png 768w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-17-at-5.32.34-PM-1536x1217.png 1536w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-17-at-5.32.34-PM-1568x1242.png 1568w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-17-at-5.32.34-PM.png 1914w" sizes="auto, (max-width: 512px) 100vw, 512px" /><figcaption class="wp-element-caption">Look at all of those subscribers</figcaption></figure>



<p class="wp-block-paragraph"><a href="https://wordpress.org/plugins/fluent-crm/" target="_blank" rel="noreferrer noopener">Details on wordpress.org</a></p>



<p class="wp-block-paragraph">Fluent Forms:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="282" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-17-at-5.33.32-PM-1024x282.png" alt="" class="wp-image-453" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-17-at-5.33.32-PM-1024x282.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-17-at-5.33.32-PM-300x83.png 300w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-17-at-5.33.32-PM-768x212.png 768w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-17-at-5.33.32-PM-1536x423.png 1536w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-17-at-5.33.32-PM-2048x564.png 2048w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-17-at-5.33.32-PM-1568x432.png 1568w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">And look at that &#8220;amazing&#8221; conversion rate</figcaption></figure>



<p class="wp-block-paragraph"><a href="https://wordpress.org/plugins/fluentform/" target="_blank" rel="noreferrer noopener">Details on wordpress.org</a></p>



<h3 class="wp-block-heading">Optimization and Caching</h3>



<p class="wp-block-paragraph">If you want your website to run well, you&#8217;ll want at least some caching. Combined with Cloudflare, this can help your website load faster, which is especially important for users with poor internet, or are physically located far away from your server. I&#8217;ll be going over how to setup your WordPress install behind Cloudflare and what settings I chose for the WordPress plugins I&#8217;m about to list in a future post, so you can look forward to that and <a href="https://alexshomenetwork.com/newsletter/" target="_blank" rel="noreferrer noopener">subscribe to my newsletter</a> to get a notification right in your inbox.</p>



<p class="wp-block-paragraph">Before installing any of these plugins, make sure that you get everything set up first. Otherwise, you&#8217;ll end up like me trying to figure out why changes aren&#8217;t behaving properly or saving just to find out that it was a caching plugin.</p>



<h4 class="wp-block-heading">WP Fastest Cache</h4>



<p class="wp-block-paragraph">Like many WordPress plugins, it has a descriptive yet not so catchy name. But as its name implies, this is a plugin for caching. There&#8217;s a decent amount of features, but like every WordPress plugin, if you want more advanced features including statistics on your caching and stuff, you&#8217;ll have to fork up some cash. </p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-10.30.58-AM.png" alt="" class="wp-image-459" width="394" height="391" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-10.30.58-AM.png 787w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-10.30.58-AM-300x298.png 300w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-10.30.58-AM-150x150.png 150w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-10.30.58-AM-768x763.png 768w" sizes="auto, (max-width: 394px) 100vw, 394px" /><figcaption class="wp-element-caption">Here&#8217;s the settings I use. I&#8217;ll go over what other things I do in more detail to optimize my website in my aforementioned future post.</figcaption></figure>



<p class="wp-block-paragraph"><a href="https://wordpress.org/plugins/wp-fastest-cache/" target="_blank" rel="noreferrer noopener">Details on wordpress.org</a></p>



<h4 class="wp-block-heading">Smush</h4>



<p class="wp-block-paragraph">Unlike most WordPress plugins, this one has a both catchy and somewhat descriptive name. This is a WordPress plugin for optimizing the images on your website. Not only does this plugin compress all of the images on your website without sacrificing quality, but it also includes features like lazy load. If you don&#8217;t know, lazy load is a neat thing that won&#8217;t display an image on your website until a user scrolls to it. This can save bandwidth by not pointlessly displaying images.</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-10.52.17-AM.png" alt="" class="wp-image-464" width="430" height="454" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-10.52.17-AM.png 859w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-10.52.17-AM-284x300.png 284w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-10.52.17-AM-768x812.png 768w" sizes="auto, (max-width: 430px) 100vw, 430px" /></figure>



<p class="wp-block-paragraph"><a href="https://wordpress.org/plugins/remove-footer-credit/" target="_blank" rel="noreferrer noopener">Details on wordpress.org</a></p>



<h4 class="wp-block-heading">OMGF (Optimize My Google Fonts)</h4>



<p class="wp-block-paragraph">If you use Google Fonts on your website, then this is the plugin for you. This is a WordPress plugin that will download Google Fonts locally to your server. This will both improve privacy and performance for your visitors. Unlike a lot of WordPress plugins, the majority of features are free, and it doesn&#8217;t beg you to pay.</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-10.52.49-AM.png" alt="" class="wp-image-466" width="437" height="451" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-10.52.49-AM.png 873w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-10.52.49-AM-290x300.png 290w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-10.52.49-AM-768x794.png 768w" sizes="auto, (max-width: 437px) 100vw, 437px" /></figure>



<p class="wp-block-paragraph"><a href="https://wordpress.org/plugins/host-webfonts-local/" target="_blank" rel="noreferrer noopener">Details on wordpress.org</a></p>



<h4 class="wp-block-heading">Presto Player</h4>



<p class="wp-block-paragraph">By default, WordPress doesn&#8217;t seem to handle videos very well. What seems to happen is that WordPress will use whatever video player your web browser has built in, and it&#8217;ll also load the entire video by default. This uses a lot of bandwidth and slows down your website for visitors, especially on a website like <a href="https://mostepicwebsite.com/" target="_blank" rel="noreferrer noopener">mostepicwebsite.com</a>. With Presto Player, it lazy loads videos, and it will buffer them like how YouTube works instead of serving the entire video file. It also gives you the ability to customize the video player (More advanced customizations are paywalled), and use Google Analytics (Also paywalled, I guess they really want you to upgrade).</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-11.11.05-AM.png" alt="" class="wp-image-467" width="414" height="460" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-11.11.05-AM.png 827w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-11.11.05-AM-270x300.png 270w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-11.11.05-AM-768x853.png 768w" sizes="auto, (max-width: 414px) 100vw, 414px" /></figure>



<p class="wp-block-paragraph"><a href="https://wordpress.org/plugins/presto-player/" target="_blank" rel="noreferrer noopener">Details on wordpress.org</a></p>



<h3 class="wp-block-heading">Forms</h3>



<p class="wp-block-paragraph">You probably already know what a form does and why you would want one, so without wasting anymore time, I&#8217;ll just jump right into my recommendation.</p>



<h4 class="wp-block-heading">Forminator</h4>



<p class="wp-block-paragraph">You probably already guessed what this plugin does from its catchy, descriptive, and distinctive name, but this is a plugin for creating forms and stuff like that. This plugin is probably made redundant by Fluent Forms, but I don&#8217;t feel like comparing the features, so it&#8217;s staying. I picked this plugin not only because it has a lot of features, but the free version is also really good, and there&#8217;s only a handful of features that are paywalled. It also doesn&#8217;t feel pushy about paying for the premium version, which is something that I can&#8217;t say about the majority of WordPress plugins.</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-11.29.46-AM.png" alt="" class="wp-image-471" width="432" height="373" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-11.29.46-AM.png 863w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-11.29.46-AM-300x259.png 300w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-11.29.46-AM-768x663.png 768w" sizes="auto, (max-width: 432px) 100vw, 432px" /></figure>



<p class="wp-block-paragraph"><a href="https://wordpress.org/plugins/forminator/" target="_blank" rel="noreferrer noopener">Details on wordpress.org</a></p>



<h3 class="wp-block-heading">SEO</h3>



<p class="wp-block-paragraph">Since WordPress by default doesn&#8217;t offer many options in terms of SEO, you&#8217;ll probably want to install an SEO WordPress plugin to help with that. This way you can ensure that your website shows up in Google search properly and you actually get visitors.</p>



<h4 class="wp-block-heading">Yoast SEO</h4>



<p class="wp-block-paragraph">I didn&#8217;t look too much into SEO WordPress plugins if I&#8217;m being honest, but I chose Yoast SEO mainly because it was recommended by a lot of people, and the free version had a good amount of features (Although they do like to beg you to upgrade). They also have a lot of helpful tutorials in articles that you can access simply by clicking the question mark icon.</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-3.03.41-PM.png" alt="" class="wp-image-474" width="442" height="366" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-3.03.41-PM.png 883w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-3.03.41-PM-300x249.png 300w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-3.03.41-PM-768x637.png 768w" sizes="auto, (max-width: 442px) 100vw, 442px" /></figure>



<p class="wp-block-paragraph"><a href="https://wordpress.org/plugins/wordpress-seo/" target="_blank" rel="noreferrer noopener">Details on wordpress.org</a></p>



<h3 class="wp-block-heading">Security and Backups</h3>



<p class="wp-block-paragraph">The last thing that you want when running a website is to have it get hacked, or loose all of your data because someone decided to use RAID 0. No matter how you lost your data this time, luckily WordPress plugin developers have thought of some solutions. Depending on your setup, there might be additional plugins that you need to install, but I&#8217;ll be covering security in my next post.</p>



<h4 class="wp-block-heading">Sucuri Security</h4>



<p class="wp-block-paragraph">This is a security plugin that has various features, like audit logging, email alerts, website scanning, and more. This plugin also gives you tips on how you can improve the security of your website. Another thing that&#8217;s nice about this plugin is that it doesn&#8217;t seem to beg you for money.</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-3.11.06-PM.png" alt="" class="wp-image-475" width="433" height="276" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-3.11.06-PM.png 865w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-3.11.06-PM-300x191.png 300w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-3.11.06-PM-768x490.png 768w" sizes="auto, (max-width: 433px) 100vw, 433px" /></figure>



<p class="wp-block-paragraph"><a href="https://wordpress.org/plugins/sucuri-scanner/" target="_blank" rel="noreferrer noopener">Details on wordpress.org</a></p>



<h4 class="wp-block-heading">UpdraftPlus</h4>



<p class="wp-block-paragraph">I personally use UpdraftPlus for backing up both of my websites. Even though it loves to beg you to buy the premium version, the free version has a decent amount of features, and it works well enough. I even used it to migrate <a href="https://mostepicwebsite.com" target="_blank" rel="noreferrer noopener">mostepicwebsite.com</a> and this blog from my testing environment (Although I did a backup and restore instead of using the migrate feature). There&#8217;s many different locations that you can backup to (Although almost half of them are paywalled).</p>



<figure class="wp-block-image size-large is-resized"><img loading="lazy" decoding="async" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-5.53.25-PM-1024x849.png" alt="" class="wp-image-483" width="512" height="425" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-5.53.25-PM-1024x849.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-5.53.25-PM-300x249.png 300w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-5.53.25-PM-768x637.png 768w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-5.53.25-PM-1536x1274.png 1536w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-5.53.25-PM-1568x1301.png 1568w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-5.53.25-PM.png 1772w" sizes="auto, (max-width: 512px) 100vw, 512px" /></figure>



<p class="wp-block-paragraph"><a href="https://wordpress.org/plugins/updraftplus/" target="_blank" rel="noreferrer noopener">Details on wordpress.org</a></p>



<h3 class="wp-block-heading">The Little Things</h3>



<p class="wp-block-paragraph">There&#8217;s many fancy WordPress plugins out there, but there&#8217;s also many simple and very useful plugins that arguably should be features built into WordPress. For the most part, these plugins also have a very good free version and don&#8217;t beg you for money every 5 seconds.</p>



<h4 class="wp-block-heading">Easy Table of Contents</h4>



<p class="wp-block-paragraph">As its simple name implies, this is a simple WordPress plugin for generation a table of contents on any post, page, or whatever you want. The vast majority of the features are free with very few of them being paywalled. Overall, it does exactly as it advertises, so no complaints. This is something that I wish was included with WordPress by default.</p>



<figure class="wp-block-image size-large is-resized"><img loading="lazy" decoding="async" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-4.40.17-PM-965x1024.png" alt="" class="wp-image-477" width="483" height="512" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-4.40.17-PM-965x1024.png 965w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-4.40.17-PM-283x300.png 283w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-4.40.17-PM-768x815.png 768w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-4.40.17-PM.png 1396w" sizes="auto, (max-width: 483px) 100vw, 483px" /></figure>



<p class="wp-block-paragraph"><a href="https://wordpress.org/plugins/easy-table-of-contents/" target="_blank" rel="noreferrer noopener">Details on wordpress.org</a></p>



<h4 class="wp-block-heading">Remove Footer Credit</h4>



<p class="wp-block-paragraph">Another feature that isn&#8217;t included with WordPress but should be is the ability to disable footer credit. Luckily this very simple WordPress plugin solves that issue for you, and all it takes is a bit of skill with inspect element. </p>



<figure class="wp-block-image size-large is-resized"><img loading="lazy" decoding="async" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-4.45.18-PM-1024x700.png" alt="" class="wp-image-478" width="512" height="350" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-4.45.18-PM-1024x700.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-4.45.18-PM-300x205.png 300w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-4.45.18-PM-768x525.png 768w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-4.45.18-PM-1536x1050.png 1536w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-4.45.18-PM-2048x1400.png 2048w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-4.45.18-PM-1568x1072.png 1568w" sizes="auto, (max-width: 512px) 100vw, 512px" /></figure>



<p class="wp-block-paragraph"><a href="https://wordpress.org/plugins/remove-footer-credit/" target="_blank" rel="noreferrer noopener">Details on wordpress.org</a></p>



<h4 class="wp-block-heading">Velvet Blues Update URLs</h4>



<p class="wp-block-paragraph">If you&#8217;re migrating a WordPress website from one domain to another, then this another very simple but useful WordPress plugin. I&#8217;ve used this when migrating <a href="https://mostepicwebsite.com" target="_blank" rel="noreferrer noopener">mostepicwebsite.com</a> and this blog from my testing environment to my cloud server. This plugin allowed me to easily update all of the URLs on my websites so everything worked perfectly. Unfortunately it doesn&#8217;t seem to be maintained anymore, but since this plugin is so simple, it shouldn&#8217;t be prone to breakage or security issues.</p>



<figure class="wp-block-image size-large is-resized"><img loading="lazy" decoding="async" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-4.51.18-PM-1024x921.png" alt="" class="wp-image-479" width="512" height="461" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-4.51.18-PM-1024x921.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-4.51.18-PM-300x270.png 300w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-4.51.18-PM-768x691.png 768w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-4.51.18-PM.png 1314w" sizes="auto, (max-width: 512px) 100vw, 512px" /></figure>



<p class="wp-block-paragraph"><a href="https://wordpress.org/plugins/velvet-blues-update-urls/" target="_blank" rel="noreferrer noopener">Details on wordpress.org</a></p>



<h4 class="wp-block-heading">Add From Server</h4>



<p class="wp-block-paragraph">If you&#8217;re using Cloudflare, then you probably know that Cloudflare limits the file size of your uploads. Luckily you can work around this by using FTP or something like that and upload the file directly to your server. Unfortunately you might discover that the file doesn&#8217;t appear in your media library despite it being in the correct directory and format. This simple WordPress plugin will come to the rescue by allowing you to select the file and manually add it to your media library. Like some other plugins here, unfortunately it&#8217;s not maintained anymore as far as I can tell. But because of it&#8217;s simplicity, you shouldn&#8217;t need to worry about any issues.</p>



<figure class="wp-block-image size-large is-resized"><img loading="lazy" decoding="async" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-4.53.55-PM-760x1024.png" alt="" class="wp-image-480" width="380" height="512" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-4.53.55-PM-760x1024.png 760w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-4.53.55-PM-223x300.png 223w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-4.53.55-PM-768x1035.png 768w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-4.53.55-PM.png 794w" sizes="auto, (max-width: 380px) 100vw, 380px" /></figure>



<p class="wp-block-paragraph"><a href="https://wordpress.org/plugins/add-from-server/" target="_blank" rel="noreferrer noopener">Details on wordpress.org</a></p>



<h4 class="wp-block-heading">WP Dark Mode</h4>



<p class="wp-block-paragraph">Who doesn&#8217;t like having a dark mode on their website, especially on a website that looks like mine? This WordPress plugin allows your visitors to toggle between light and dark mode with a flip of a switch. They&#8217;re pretty pushy about paying for the premium version, but the free version works well enough, and I also can&#8217;t find a better free replacement. </p>



<figure class="wp-block-image size-large is-resized"><img loading="lazy" decoding="async" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-6.41.28-PM-1024x791.png" alt="" class="wp-image-485" width="512" height="396" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-6.41.28-PM-1024x791.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-6.41.28-PM-300x232.png 300w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-6.41.28-PM-768x593.png 768w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-6.41.28-PM-1536x1186.png 1536w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-6.41.28-PM-1568x1211.png 1568w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-6.41.28-PM.png 1740w" sizes="auto, (max-width: 512px) 100vw, 512px" /></figure>



<p class="wp-block-paragraph"><a href="https://wordpress.org/plugins/wp-dark-mode" target="_blank" rel="noreferrer noopener">Details on wordpress.org</a></p>



<h4 class="wp-block-heading">Media Cleaner</h4>



<p class="wp-block-paragraph">A very useful WordPress plugin that helped me migrate <a href="https://mostepicwebsite.com" target="_blank" rel="noreferrer noopener">mostepicwebsite.com</a> from my testing environment was Media Cleaner. Somehow I ended up with a bunch of duplicates, but luckily this WordPress plugin made it very easy to remove all of them. Unlike a lot of WordPress plugins, it also doesn&#8217;t seem very pushy about its premium version.</p>



<figure class="wp-block-image size-large is-resized"><img loading="lazy" decoding="async" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-6.48.29-PM-1024x817.png" alt="" class="wp-image-486" width="512" height="409" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-6.48.29-PM-1024x817.png 1024w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-6.48.29-PM-300x239.png 300w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-6.48.29-PM-768x613.png 768w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-6.48.29-PM-1536x1226.png 1536w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-6.48.29-PM-1568x1251.png 1568w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-18-at-6.48.29-PM.png 1832w" sizes="auto, (max-width: 512px) 100vw, 512px" /></figure>



<p class="wp-block-paragraph"><a href="https://wordpress.org/plugins/media-cleaner/" target="_blank" rel="noreferrer noopener">Details on wordpress.org</a></p>



<p class="wp-block-paragraph">I don&#8217;t have anything interesting for the conclusion for this post, but I hope that you enjoyed reading it and maybe was helpful. If you have any suggestions, comments, or complaints, then feel free to leave a comment. Also, stay tuned for part 4 (The final post in this series), where I&#8217;ll talk about using WordPress with Cloudflare and Fail2ban along with some other optimization and security tips.</p>



<p class="wp-block-paragraph">Part 4: Coming Soon</p>
<p>The post <a href="https://alexshomenetwork.com/my-top-picks-for-wordpress-plugins/">My Top Picks for WordPress Plugins (Comments, Security, Email) &#8211; Building a WordPress Blog Part 3</a> appeared first on <a href="https://alexshomenetwork.com">Alex&#039;s Home Network</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://alexshomenetwork.com/my-top-picks-for-wordpress-plugins/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Installing WordPress with Nginx, MariaDB, and PHP7.4 (LEMP Stack) on Debian &#8211; Building a WordPress Blog Part 2</title>
		<link>https://alexshomenetwork.com/installing-wordpress-on-lemp-stack/</link>
					<comments>https://alexshomenetwork.com/installing-wordpress-on-lemp-stack/#comments</comments>
		
		<dc:creator><![CDATA[Alex]]></dc:creator>
		<pubDate>Wed, 07 Dec 2022 00:47:06 +0000</pubDate>
				<category><![CDATA[Self-Hosting]]></category>
		<category><![CDATA[WordPress]]></category>
		<guid isPermaLink="false">https://alexshomenetwork.com/?p=381</guid>

					<description><![CDATA[<p>This Guide Has Been Replaced I have written an updated and much better version of this guide. I&#8217;m primarily keeping this post up for archival purposes, and if anyone wants to reference it for whatever reason. If you&#8217;re looking to follow this guide, follow the one I linked below instead. New guide: https://alexshomenetwork.com/installing-wordpress-on-debian-13/ Old Post<a class="more-link" href="https://alexshomenetwork.com/installing-wordpress-on-lemp-stack/">Continue reading <span class="screen-reader-text">"Installing WordPress with Nginx, MariaDB, and PHP7.4 (LEMP Stack) on Debian &#8211; Building a WordPress Blog Part 2"</span></a></p>
<p>The post <a href="https://alexshomenetwork.com/installing-wordpress-on-lemp-stack/">Installing WordPress with Nginx, MariaDB, and PHP7.4 (LEMP Stack) on Debian &#8211; Building a WordPress Blog Part 2</a> appeared first on <a href="https://alexshomenetwork.com">Alex&#039;s Home Network</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h3 class="wp-block-heading">This Guide Has Been Replaced</h3>



<p class="wp-block-paragraph">I have written an updated and much better version of this guide. I&#8217;m primarily keeping this post up for archival purposes, and if anyone wants to reference it for whatever reason. If you&#8217;re looking to follow this guide, follow the one I linked below instead.</p>



<p class="wp-block-paragraph">New guide: <a href="https://alexshomenetwork.com/installing-wordpress-on-debian-13/">https://alexshomenetwork.com/installing-wordpress-on-debian-13/</a></p>



<h3 class="wp-block-heading">Old Post</h3>



<p class="wp-block-paragraph">If you&#8217;ve read my <a href="https://alexshomenetwork.com/installing-nginx-mariadb-and-php74-on-debian/" target="_blank" rel="noreferrer noopener">previous post</a> and followed along, you should have a working LEMP stack. You&#8217;re probably thinking to yourself, now what? Well, today I&#8217;ll be showing you what I did with mine, which is installing WordPress. WordPress is an extremely popular CMS (Content Management System) that many of your favorite websites are based off of. Hell, even this arguably kinda crappy blog uses WordPress. A CMS allows someone to easily build websites of various types without needing any sort of programming knowledge.</p>



<h3 class="wp-block-heading">Prerequisites</h3>



<p class="wp-block-paragraph">If you&#8217;re going to follow along, the prerequisites are basically identical to my previous post:</p>



<ul class="wp-block-list">
<li>An up to date Debian 11 install that has a LEMP stack installed, and you have full root access to. Regardless of your hardware/software, you&#8217;ll want at least 512MB of free RAM. You&#8217;ll also want to use something like SSH so you can copy and paste commands.</li>



<li>Some Linux command line experience.</li>



<li>I&#8217;m going to assume that you&#8217;ll want to put your WordPress instance on the internet for people to visit, so you&#8217;ll also need access to whatever firewalls your server is behind, and information like your public IP address. You&#8217;ll also want a domain name (Unless if you want to make your visitors remember an IP address for whatever reason).</li>
</ul>



<p class="wp-block-paragraph">Like I said in my previous post, I would recommend using a VPS (Virtual Private Server) as opposed to opening up a server at your home to the internet. If you&#8217;re looking for a VPS, there&#8217;s many good and cheap options, but I personally use Vultr (<a href="https://www.vultr.com/?ref=9008431" target="_blank" rel="noreferrer noopener sponsored nofollow">Referral plug because why not?</a>). There&#8217;s a lot of security risks involved with exposing parts of your network to the internet, especially if your server isn&#8217;t properly patched, or if you misconfigure your firewalls. You also might run into roadblocks with stuff like CGNAT (Carrier Grade NAT) or your ISP blocking ports, which makes it difficult or impossible to port forward. Plus if you have crappy internet, it can make a pretty poor experience for your visitors.</p>



<h3 class="wp-block-heading">Downloading WordPress</h3>



<p class="wp-block-paragraph">There&#8217;s a few different ways of downloading WordPress to your server, but I prefer using the command line since it&#8217;s more convenient in my opinion. </p>



<p class="wp-block-paragraph">First, install wget and unzip:</p>



<pre class="wp-block-code"><code>sudo apt install wget unzip</code></pre>



<p class="wp-block-paragraph">Download the WordPress zip file:</p>



<pre class="wp-block-code"><code>wget https://wordpress.org/latest.zip</code></pre>



<p class="wp-block-paragraph">Unzip the file to <code>/usr/share/nginx</code>:</p>



<pre class="wp-block-code"><code>sudo unzip latest.zip -d /usr/share/nginx</code></pre>



<p class="wp-block-paragraph">And finally, change the owner of <code>/usr/share/nginx/wordpress</code> to the Nginx user (Don&#8217;t be like me and forget this step then wonder why doing anything gives me access denied errors):</p>



<pre class="wp-block-code"><code>sudo chown -R www-data:www-data /usr/share/nginx/wordpress</code></pre>



<p class="wp-block-paragraph">Don&#8217;t forget to remove the downloaded ZIP file so it doesn&#8217;t take up space on your server:</p>



<pre class="wp-block-code"><code>rm latest.zip</code></pre>



<h3 class="wp-block-heading">Connecting WordPress to MariaDB</h3>



<p class="wp-block-paragraph">You&#8217;ll need to create a dedicated database and database user for WordPress. Since I&#8217;m not familiar with MySQL commands, I&#8217;ll show you how to do it through phpMyAdmin.</p>



<p class="wp-block-paragraph">Once you&#8217;ve logged in as a root user, click the New button in the left side bar:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="240" height="225" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-03-at-12.00.49-PM.png" alt="" class="wp-image-387"/></figure>



<p class="wp-block-paragraph">Enter a database name, and then click Create:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="504" height="361" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-04-at-9.29.09-AM.png" alt="" class="wp-image-388" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-04-at-9.29.09-AM.png 504w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-04-at-9.29.09-AM-300x215.png 300w" sizes="auto, (max-width: 504px) 100vw, 504px" /></figure>



<p class="wp-block-paragraph">Click the phpMyAdmin logo in the top left corner to return to the main screen, then select the User accounts tab:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="691" height="134" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-04-at-9.29.58-AM.png" alt="" class="wp-image-389" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-04-at-9.29.58-AM.png 691w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-04-at-9.29.58-AM-300x58.png 300w" sizes="auto, (max-width: 691px) 100vw, 691px" /></figure>



<p class="wp-block-paragraph">Under new, click Add user account:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="719" height="322" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-04-at-9.30.06-AM.png" alt="" class="wp-image-390" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-04-at-9.30.06-AM.png 719w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-04-at-9.30.06-AM-300x134.png 300w" sizes="auto, (max-width: 719px) 100vw, 719px" /></figure>



<p class="wp-block-paragraph">Enter a username and password, and click Go on the bottom right side of the page. Make sure to take note of this information since you&#8217;ll need this for creating <code>wp-config.php</code>:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="723" height="422" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-04-at-9.31.04-AM.png" alt="" class="wp-image-391" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-04-at-9.31.04-AM.png 723w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-04-at-9.31.04-AM-300x175.png 300w" sizes="auto, (max-width: 723px) 100vw, 723px" /></figure>



<p class="wp-block-paragraph">After the user has been created, select the Database tab, and under Database-specific privileges, enter the name of the database that you&#8217;ve created (The name of mine is wordpress), then click Go:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="590" height="322" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-04-at-9.32.18-AM.png" alt="" class="wp-image-392" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-04-at-9.32.18-AM.png 590w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-04-at-9.32.18-AM-300x164.png 300w" sizes="auto, (max-width: 590px) 100vw, 590px" /></figure>



<p class="wp-block-paragraph">Select the Check all checkbox next to Database-specific privileges, then click go:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="632" height="539" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-04-at-9.32.43-AM.png" alt="" class="wp-image-393" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-04-at-9.32.43-AM.png 632w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-04-at-9.32.43-AM-300x256.png 300w" sizes="auto, (max-width: 632px) 100vw, 632px" /></figure>



<p class="wp-block-paragraph">After that, you should now have a MariaDB database and user for WordPress, and you can also modify WordPress&#8217;s databases directly by logging into the WordPress user (This has saved me a few times when I&#8217;ve changed the wrong setting and locked myself out).</p>



<h4 class="wp-block-heading">Creating and Editing wp-config.php</h4>



<p class="wp-block-paragraph">Now that you&#8217;ve set up a MariaDB database and user for WordPress, it&#8217;s now time to make WordPress use them. Navigate to <code>/usr/share/nginx/wordpress</code> and rename <code>wp-config-sample.php</code> to <code>wp-config.php</code>.</p>



<p class="wp-block-paragraph">Navigate to the following lines (Starting line 22), and replace the database name, username, and password with the one&#8217;s that you&#8217;ve just created:</p>



<pre class="wp-block-code"><code>/** The name of the database for WordPress */
define( 'DB_NAME', '<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">database_name_here</mark>' );

/** Database username */
define( 'DB_USER', '<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">username_here</mark>' );

/** Database password */
define( 'DB_PASSWORD', '<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">password_here</mark>' );</code></pre>



<p class="wp-block-paragraph">There are many other options in this file, but these should be the only changes that you need to make.</p>



<h3 class="wp-block-heading">Creating an Nginx Server Block</h3>



<p class="wp-block-paragraph">Save the below server block in <code>/etc/nginx/conf.d</code> as <code>wordpress.conf</code>. This also happens to be the same server block that I use. For testing purposes, use your servers IP address for <code>server_name</code>, but you&#8217;ll be changing it to your domain name later:</p>



<pre class="wp-block-code"><code>server {
  listen 80;
# You can safely remove the below line if your server doesn't support IPv6
  listen &#91;::]:80;
  server_name <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">12.34.56.78</mark><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color"></mark>;
  root /usr/share/nginx/wordpress/;
  index index.php index.html index.htm index.nginx-debian.html;

  location / {
    try_files $uri $uri/ /index.php;
  }

   location ~ ^/wp-json/ {
     rewrite ^/wp-json/(.*?)$ /?rest_route=/$1 last;
   }

  location ~* /wp-sitemap.*\.xml {
    try_files $uri $uri/ /index.php$is_args$args;
  }

  error_page 404 /404.html;
  error_page 500 502 503 504 /50x.html;

  client_max_body_size 999G;

  location = /50x.html {
    root /usr/share/nginx/html;
  }

  location ~ \.php$ {
    fastcgi_pass unix:/run/php/php7.4-fpm.sock;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;
    include snippets/fastcgi-php.conf;

    # Add headers to serve security related headers
    add_header X-Content-Type-Options nosniff;
    add_header X-XSS-Protection "1; mode=block";
    add_header X-Permitted-Cross-Domain-Policies none;
    add_header X-Frame-Options "SAMEORIGIN";
  }

  #enable gzip compression
  gzip on;
  gzip_vary on;
  gzip_min_length 1000;
  gzip_comp_level 5;
  gzip_types application/json text/css application/x-javascript application/javascript image/svg+xml;
  gzip_proxied any;

  # A long browser cache lifetime can speed up repeat visits to your page
  location ~* \.(jpg|jpeg|gif|png|webp|svg|woff|woff2|ttf|css|js|ico|xml)$ {
       access_log        off;
       log_not_found     off;
       expires           30d;
  }

  # disable access to hidden files
  location ~ /\.ht {
      access_log off;
      log_not_found off;
      deny all;
  }

}</code></pre>



<p class="wp-block-paragraph">Once you&#8217;ve created the file, run the following command to test it:</p>



<pre class="wp-block-code"><code>sudo nginx -t</code></pre>



<p class="wp-block-paragraph">If there&#8217;s no errors, restart nginx so it can pick up the new server block:</p>



<pre class="wp-block-code"><code>sudo systemctl restart nginx</code></pre>



<h4 class="wp-block-heading">Change Max Upload Size</h4>



<p class="wp-block-paragraph">Since the max upload size by default is only 2MB, chances are you&#8217;ll want to increase it. Open <code>/etc/php/7.4/fpm/php.ini</code> in a text editor.</p>



<p class="wp-block-paragraph">Scroll down to line 694, and change it to something larger. I personally have mine set to 999G so I don&#8217;t have to worry about any sort of limits, but if you&#8217;re going to allow users to upload content, you probably want to change it to something smaller:</p>



<pre class="wp-block-code"><code>post_max_size = <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">8M</mark></code></pre>



<p class="wp-block-paragraph">Scroll down to line 846, and change it to something bigger. I also have this set to 999G, but like I said, you might want to keep it smaller if you&#8217;re allowing users to upload content:</p>



<pre class="wp-block-code"><code>upload_max_filesize = <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">2M</mark></code></pre>



<p class="wp-block-paragraph">After you&#8217;re done making your changes, restart PHP:</p>



<pre class="wp-block-code"><code>sudo systemctl restart php7.4-fpm</code></pre>



<h3 class="wp-block-heading">Basic WordPress setup</h3>



<p class="wp-block-paragraph">I don&#8217;t plan on going into detail, but I&#8217;ll be showing the basics. Navigate to your servers IP address, and you should be redirected to the WordPress setup screen.</p>



<h4 class="wp-block-heading">Getting an Nginx Welcome Screen</h4>



<p class="wp-block-paragraph">A problem that you might run into (At least one that I&#8217;ve run into a few times) is getting the Nginx welcome screen instead of being redirected to the WordPress install like in the screenshot. As a temporary workaround to get WordPress installed, you might be able to navigate to <code>your_ip_address/wp-admin/install.php</code> just to get WordPress installed, but you&#8217;ll still get the Nginx welcome screen if you just go to your servers IP address without a path:</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="832" height="372" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-11-24-at-9.32.03-AM.png" alt="" class="wp-image-396" style="width:624px;height:279px" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-11-24-at-9.32.03-AM.png 832w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-11-24-at-9.32.03-AM-300x134.png 300w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-11-24-at-9.32.03-AM-768x343.png 768w" sizes="auto, (max-width: 832px) 100vw, 832px" /></figure>



<p class="wp-block-paragraph">First, try just simply rebooting your server. Rebooting my server has fixed this issue after I&#8217;ve determined that everything was setup correctly.</p>



<p class="wp-block-paragraph">Next, check <code>/etc/nginx/conf.d</code> to see if there&#8217;s any server blocks that you don&#8217;t need, or one&#8217;s that are also using port 80. Remove any unneeded server blocks or change the ports that they&#8217;re using then run <code>sudo systemctl restart nginx</code>. You can also remove the welcome page from <code>/usr/share/nginx/html</code> to see what happens.</p>



<p class="wp-block-paragraph">Lastly, check the logs for PHP and Nginx by running <code>sudo systemctl status nginx</code> and <code>sudo systemctl status php7.4-fpm</code>, or by checking their log files in <code>/var/log</code>. Usually they&#8217;ll tell you if something weird is going on.</p>



<p class="wp-block-paragraph">After running through these steps, I would recommend rebooting your server again to ensure that everything has been restarted.</p>



<p class="wp-block-paragraph">Once you&#8217;ve gotten to the WordPress install screen, select your language, and click Continue:</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="375" height="744" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-04-at-10.50.53-AM.png" alt="" class="wp-image-404" style="width:281px;height:558px" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-04-at-10.50.53-AM.png 375w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-04-at-10.50.53-AM-151x300.png 151w" sizes="auto, (max-width: 375px) 100vw, 375px" /></figure>



<p class="wp-block-paragraph">Enter a website name, username, password, and email address. I would also recommend checking the box to discourage search engines from indexing your website, then unchecking it once you&#8217;re ready to launch it. Click Install WordPress:</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="747" height="762" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-04-at-10.52.47-AM.png" alt="" class="wp-image-405" style="width:374px;height:381px" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-04-at-10.52.47-AM.png 747w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-04-at-10.52.47-AM-294x300.png 294w" sizes="auto, (max-width: 747px) 100vw, 747px" /></figure>



<p class="wp-block-paragraph">Once WordPress has been installed (Which should happen very quickly), click Log In to be redirected to the login page, then login using the login information that you entered during the install process:</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="748" height="305" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-04-at-10.55.10-AM.png" alt="" class="wp-image-406" style="width:561px;height:229px" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-04-at-10.55.10-AM.png 748w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-04-at-10.55.10-AM-300x122.png 300w" sizes="auto, (max-width: 748px) 100vw, 748px" /></figure>



<h4 class="wp-block-heading">Updating and Configuring WordPress</h4>



<p class="wp-block-paragraph">Before using WordPress, I would recommend installing updates. Under Dashboard in the left side bar, click Updates:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="160" height="296" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-04-at-11.00.12-AM.png" alt="" class="wp-image-407"/></figure>



<p class="wp-block-paragraph">Depending on how long ago you download WordPress, there might be a few updates. But for me I only needed to update one plugin. Click the checkbox next to Select All, and then click update (Do this for themes as well if there&#8217;s updates available):</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="744" height="341" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-04-at-11.00.31-AM.png" alt="" class="wp-image-408" style="width:558px;height:256px" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-04-at-11.00.31-AM.png 744w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-04-at-11.00.31-AM-300x138.png 300w" sizes="auto, (max-width: 744px) 100vw, 744px" /></figure>



<p class="wp-block-paragraph">I would also recommend switching to security updates only for better stability, and also so your WordPress install doesn&#8217;t decide to randomly update to a new major version and cause a mess (<em>cough</em> Windows <em>cough</em>):</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="513" height="146" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-04-at-11.00.43-AM.png" alt="" class="wp-image-409" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-04-at-11.00.43-AM.png 513w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-04-at-11.00.43-AM-300x85.png 300w" sizes="auto, (max-width: 513px) 100vw, 513px" /></figure>



<h3 class="wp-block-heading">DNS and HTTPS</h3>



<p class="wp-block-paragraph">Just as a disclaimer, in this section my knowledge and experience is a little thin in some spots, so some stuff may not be explained all that well or correctly, but I&#8217;m open to feedback in the comments.</p>



<p class="wp-block-paragraph">If you&#8217;ve made it this far, then congratulations! You&#8217;ve got yourself a mostly working WordPress install. However, it&#8217;s not all that secure because there&#8217;s no HTTPS, and you probably have a domain name that you want to use. Before doing this, make sure that your server is accessible to the internet by opening the necessary ports (80 and 443) on your firewalls, and also port forward if needed. I highly recommended doing some trial and error to ensure that your server is accessible while being secure, and I&#8217;ll be covering security in more detail in a future post. If you&#8217;re behind Cloudflare, you only need to open those ports to <a href="https://www.cloudflare.com/ips/" target="_blank" rel="noreferrer noopener">Cloudflare&#8217;s IP ranges</a> once everything is set up.</p>



<p class="wp-block-paragraph">First, select settings in the left side bar, and change WordPress Address and Site Address to <code>https://your_domain__name.com</code> like in the screenshot:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="588" height="118" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-04-at-11.04.40-AM.png" alt="" class="wp-image-411" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-04-at-11.04.40-AM.png 588w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-04-at-11.04.40-AM-300x60.png 300w" sizes="auto, (max-width: 588px) 100vw, 588px" /></figure>



<p class="wp-block-paragraph">Just note that once you click Save Changes at the bottom of the screen, you will be locked out of your site because WordPress will only allow you to access your site from your domain name, and since you don&#8217;t have that set up yet, your site isn&#8217;t accessible. If you do need to change the URLs back for whatever reason, log into MariaDB with your WordPress user, open the WordPress database, open the <code>wp_options</code> table, and change <code>siteurl</code> and <code>home</code> to the previous values. You can also do this through phpMyAdmin.</p>



<h4 class="wp-block-heading">DNS Records</h4>



<p class="wp-block-paragraph">The first thing that you&#8217;ll want to do is create a DNS record for your web server. This will vary depending on the domain registrar, so check their documentation before proceeding. You&#8217;ll most likely need an A DNS record for your server, a CNAME record so if someone types in <code>www.your_domain.com</code>, it will resolve to <code>your_domain.com</code>, and a AAAA record if your server supports IPv6. Here&#8217;s what my records look like in Cloudflare for example:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="1006" height="77" src="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-04-at-11.10.07-AM.png" alt="" class="wp-image-402" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-04-at-11.10.07-AM.png 1006w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-04-at-11.10.07-AM-300x23.png 300w, https://alexshomenetwork.com/wp-content/uploads/2022/12/Screen-Shot-2022-12-04-at-11.10.07-AM-768x59.png 768w" sizes="auto, (max-width: 1006px) 100vw, 1006px" /><figcaption class="wp-element-caption">In case you couldn&#8217;t tell, the IP address is fake</figcaption></figure>



<p class="wp-block-paragraph">If your server is proxied behind Cloudflare like mine is, you don&#8217;t need an AAAA record. This is because your domain will resolve to Cloudflare&#8217;s IP addresses instead, and Cloudflare will forward the requests to your server.</p>



<p class="wp-block-paragraph">It may take a while for your DNS records to propagate, so don&#8217;t panic if your browser fails to resolve your domain and <code>nslookup</code> or <code>dig</code> don&#8217;t return anything. I recommend waiting a few hours and turning the TTL down, then turning it back up once your domain resolves.</p>



<h4 class="wp-block-heading">HTTPS</h4>



<p class="wp-block-paragraph">Once your DNS records have propagated and your domain name resolves, it&#8217;s now time to set up HTTPS. If you try visiting your website now, you&#8217;ll probably get a different error. This is because even though WordPress is listening for HTTPS visitors and you typed <code>https</code> into your browser, your server doesn&#8217;t have a certificate installed, and Nginx isn&#8217;t listening on port 443.</p>



<p class="wp-block-paragraph">First, open <code>/etc/nginx/conf.d/wordpress.conf</code> in a text editor, go to that same <code>server_name</code> line from earlier, and and change it to the following (Replacing <code>example.com</code> with your actual domain name):</p>



<pre class="wp-block-code"><code>server_name <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">example.com </mark>www.<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">example.com</mark>;</code></pre>



<p class="wp-block-paragraph">Next, test the configuration file:</p>



<pre class="wp-block-code"><code>sudo nginx -t</code></pre>



<p class="wp-block-paragraph">And finally, restart Nginx:</p>



<pre class="wp-block-code"><code>sudo systemctl restart nginx</code></pre>



<p class="wp-block-paragraph">To generate an HTTPS certificate, first you&#8217;ll install Certbot:</p>



<pre class="wp-block-code"><code>sudo apt install certbot python3-certbot-nginx</code></pre>



<p class="wp-block-paragraph">Next, generate a certificate by running the following command, replacing the example domains with yours, and the email address that you used to register the domains:</p>



<pre class="wp-block-code"><code>sudo certbot --agree-tos --nginx --redirect --hsts --staple-oscp --email <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">email@example.com</mark> -d <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">example.com</mark>,www.<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">example.com</mark></code></pre>



<p class="wp-block-paragraph">And finally, now your website should hopefully be accessible. If it is, then that means I wrote this section correctly (And you correctly followed the instructions). You might need to restart your server or Nginx before your website is accessible over HTTPS.</p>



<p class="wp-block-paragraph">If you followed this post correctly (And I didn&#8217;t screw anything up), then congratulations! You should now have a fully working WordPress website that&#8217;s ready for you to start building. In a couple of upcoming posts, I&#8217;ll be going over my personal choices for WordPress plugins, and also how to take advantage of Cloudflare&#8217;s features and Fail2ban with WordPress. Feel free to leave a comment if you have any problems or suggestions, and I&#8217;ll try my best to help.</p>



<p class="wp-block-paragraph">Part 3: <a href="https://alexshomenetwork.com/my-top-picks-for-wordpress-plugins/" target="_blank" rel="noreferrer noopener">My Top Picks for WordPress Plugins (Comments, Security, Email) &#8211; Building a WordPress Blog Part 3</a></p>



<h3 class="wp-block-heading">References</h3>



<p class="wp-block-paragraph">Most of the content in this post is from my own knowledge or experience, but I did still reference some documentation and tutorials. These are the only ones that I can think of off of the top of my head.</p>



<p class="wp-block-paragraph"><a href="https://wordpress.org/support/article/how-to-install-wordpress/" target="_blank" rel="noreferrer noopener">WordPress&#8217;s Documentation</a></p>



<p class="wp-block-paragraph"><a href="https://www.linuxbabe.com/ubuntu/install-wordpress-ubuntu-20-04-nginx-mariadb-php7-4-lemp" target="_blank" rel="noreferrer noopener">LinuxBabe&#8217;s Tutorial</a></p>
<p>The post <a href="https://alexshomenetwork.com/installing-wordpress-on-lemp-stack/">Installing WordPress with Nginx, MariaDB, and PHP7.4 (LEMP Stack) on Debian &#8211; Building a WordPress Blog Part 2</a> appeared first on <a href="https://alexshomenetwork.com">Alex&#039;s Home Network</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://alexshomenetwork.com/installing-wordpress-on-lemp-stack/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>Installing Nginx, MariaDB, and PHP7.4 (LEMP Stack) on Debian – Building a WordPress Blog Part 1</title>
		<link>https://alexshomenetwork.com/installing-nginx-mariadb-and-php74-on-debian/</link>
					<comments>https://alexshomenetwork.com/installing-nginx-mariadb-and-php74-on-debian/#respond</comments>
		
		<dc:creator><![CDATA[Alex]]></dc:creator>
		<pubDate>Sat, 26 Nov 2022 18:33:28 +0000</pubDate>
				<category><![CDATA[Self-Hosting]]></category>
		<category><![CDATA[WordPress]]></category>
		<guid isPermaLink="false">https://alexshomenetwork.com/?p=320</guid>

					<description><![CDATA[<p>This Guide Has Been Replaced I have written an updated and much better version of this guide. I&#8217;m primarily keeping this post up for archival purposes, and if anyone wants to reference it for whatever reason. If you&#8217;re looking to follow this guide, follow the one I linked below instead. New guide: https://alexshomenetwork.com/installing-wordpress-on-debian-13/ Old Post<a class="more-link" href="https://alexshomenetwork.com/installing-nginx-mariadb-and-php74-on-debian/">Continue reading <span class="screen-reader-text">"Installing Nginx, MariaDB, and PHP7.4 (LEMP Stack) on Debian – Building a WordPress Blog Part 1"</span></a></p>
<p>The post <a href="https://alexshomenetwork.com/installing-nginx-mariadb-and-php74-on-debian/">Installing Nginx, MariaDB, and PHP7.4 (LEMP Stack) on Debian – Building a WordPress Blog Part 1</a> appeared first on <a href="https://alexshomenetwork.com">Alex&#039;s Home Network</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h3 class="wp-block-heading">This Guide Has Been Replaced</h3>



<p class="wp-block-paragraph">I have written an updated and much better version of this guide. I&#8217;m primarily keeping this post up for archival purposes, and if anyone wants to reference it for whatever reason. If you&#8217;re looking to follow this guide, follow the one I linked below instead.</p>



<p class="wp-block-paragraph">New guide: <a href="https://alexshomenetwork.com/installing-wordpress-on-debian-13/">https://alexshomenetwork.com/installing-wordpress-on-debian-13/</a></p>



<h3 class="wp-block-heading">Old Post</h3>



<p class="wp-block-paragraph">In this blog post I&#8217;ll show you how I installed a LEMP stack on Debian 11, but this post should apply to most distros based on Debian. I won&#8217;t go too much into detail about what these services do, but in a nutshell, Nginx is a web server, MariaDB is a database, PHP is a server-side scripting language, and it all comes together to power dynamic websites, including CMS&#8217;s (Content Management Systems) like WordPress. LEMP stands for Linux, Nginx, MariaDB or MySQL, and PHP. I&#8217;ll also show how to install phpMyAdmin, which will allow you to manage MariaDB through a web interface.</p>



<h3 class="wp-block-heading">Prerequisites</h3>



<p class="wp-block-paragraph">If you plan on following along, you&#8217;ll need the following:</p>



<ul class="wp-block-list">
<li>An up to date Debian 11 install running on your hardware/software of choice with full root access (You don&#8217;t need many resources, but I would recommend at least 512MB of available RAM). </li>



<li>Some Linux command line experience.</li>



<li>If you plan on putting it on the internet, then you&#8217;ll also need access to your firewall, your public IP address, and a domain name.</li>



<li>I would recommend enabling SSH since you&#8217;ll be able to copy-paste commands, and it&#8217;ll make managing your server easier. However, do not do this if you don&#8217;t know how to firewall a server off. If you open SSH to the internet and an attacker guesses your login, then they will have full root access to your server.</li>
</ul>



<p class="wp-block-paragraph">You really don&#8217;t need much for this project, however, I would recommend using a VPS (Virtual Private Server) instead of directly exposing parts of your network to the internet. Not only is it more secure, but you don&#8217;t have to worry about stuff like CGNAT (Carrier-Grade NAT) or poor upload speeds (Like I do, thanks Xfinity). I personally use Vultr (<a href="https://www.vultr.com/?ref=9008431" target="_blank" rel="noreferrer noopener sponsored nofollow">What&#8217;s a good blog post without a referral plug?</a><a href="https://www.vultr.com/?ref=9008431" target="_blank" rel="noreferrer noopener sponsored nofollow"></a>), but there&#8217;s plenty of good options out there.</p>



<h4 class="wp-block-heading">Installing Filebrowser (Optional)</h4>



<p class="wp-block-paragraph">I cannot stress this enough, but if you don&#8217;t know how to properly firewall off a server, skip this step. If it&#8217;s not properly firewalled off, an attacker could guess your login info and gain full access to your server&#8217;s filesystem. If you do know what you&#8217;re doing, a web-based file manager like Filebrowser makes life a lot easier when editing config files.</p>



<p class="wp-block-paragraph">However, if you&#8217;re using SSH on your server, you can also skip this step (Unless if you want to manage config files through a web interface) since you can leverage SFTP (SSH File Transfer Protocol) through <a href="https://filezilla-project.org/" target="_blank" rel="noreferrer noopener nofollow">FileZilla</a>. It might not be as user friendly, but this will eliminate the need of having more services running and ports open on your server.</p>



<p class="wp-block-paragraph">To install Filebrowser, simply copy-paste the following command (Make sure you install curl first):</p>



<pre class="wp-block-code"><code>curl -fsSL https://raw.githubusercontent.com/filebrowser/get/master/get.sh | sudo bash</code></pre>



<p class="wp-block-paragraph">Filebrowser has various options, but to run Filebrowser and give it full access to your filesystem, replace the example IP address and the port number with yours (If you don&#8217;t specify it, then port 8080 will be used), and run the following command:</p>



<pre class="wp-block-code"><code>sudo filebrowser -r / -a <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">12.34.56.78</mark> -p <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">1234</mark></code></pre>



<p class="wp-block-paragraph">You should now be able to access Filebrowser by typing in <code>your_ip_address:your_port_number</code> in to your web browser. If you can&#8217;t access it, check to make sure that the IP address you entered is correct (Or try entering 0.0.0.0, but I&#8217;ve found that it doesn&#8217;t always work), and make sure that any firewall that your server is behind is allowing the port you specified. Some Linux distros may include a firewall like ufw or iptables by default, but Debian does not.</p>



<h5 class="wp-block-heading">Securing Filebrowser</h5>



<p class="wp-block-paragraph">Once you&#8217;ve accessed the login page, use <code>admin</code> for the username and password. You&#8217;ll want to change this from the defaults.</p>



<p class="wp-block-paragraph">Over on the left side of the screen, select Settings:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="272" height="376" src="https://alexshomenetwork.com/wp-content/uploads/2022/11/Screen-Shot-2022-11-24-at-4.06.52-PM.png" alt="" class="wp-image-351" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/11/Screen-Shot-2022-11-24-at-4.06.52-PM.png 272w, https://alexshomenetwork.com/wp-content/uploads/2022/11/Screen-Shot-2022-11-24-at-4.06.52-PM-217x300.png 217w" sizes="auto, (max-width: 272px) 100vw, 272px" /></figure>



<p class="wp-block-paragraph">Select User Management:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="643" height="145" src="https://alexshomenetwork.com/wp-content/uploads/2022/11/Screen-Shot-2022-11-24-at-4.07.03-PM.png" alt="" class="wp-image-352" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/11/Screen-Shot-2022-11-24-at-4.07.03-PM.png 643w, https://alexshomenetwork.com/wp-content/uploads/2022/11/Screen-Shot-2022-11-24-at-4.07.03-PM-300x68.png 300w" sizes="auto, (max-width: 643px) 100vw, 643px" /></figure>



<p class="wp-block-paragraph">Select the pencil icon:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="849" height="212" src="https://alexshomenetwork.com/wp-content/uploads/2022/11/Screen-Shot-2022-11-24-at-4.07.23-PM.png" alt="" class="wp-image-353" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/11/Screen-Shot-2022-11-24-at-4.07.23-PM.png 849w, https://alexshomenetwork.com/wp-content/uploads/2022/11/Screen-Shot-2022-11-24-at-4.07.23-PM-300x75.png 300w, https://alexshomenetwork.com/wp-content/uploads/2022/11/Screen-Shot-2022-11-24-at-4.07.23-PM-768x192.png 768w" sizes="auto, (max-width: 849px) 100vw, 849px" /></figure>



<p class="wp-block-paragraph">Enter a new username and password of your choice:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="839" height="255" src="https://alexshomenetwork.com/wp-content/uploads/2022/11/Screen-Shot-2022-11-24-at-4.07.48-PM.png" alt="" class="wp-image-354" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/11/Screen-Shot-2022-11-24-at-4.07.48-PM.png 839w, https://alexshomenetwork.com/wp-content/uploads/2022/11/Screen-Shot-2022-11-24-at-4.07.48-PM-300x91.png 300w, https://alexshomenetwork.com/wp-content/uploads/2022/11/Screen-Shot-2022-11-24-at-4.07.48-PM-768x233.png 768w" sizes="auto, (max-width: 839px) 100vw, 839px" /></figure>



<p class="wp-block-paragraph">Then finally, select Save at the bottom of the page:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="801" height="229" src="https://alexshomenetwork.com/wp-content/uploads/2022/11/Screen-Shot-2022-11-24-at-4.07.56-PM.png" alt="" class="wp-image-355" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/11/Screen-Shot-2022-11-24-at-4.07.56-PM.png 801w, https://alexshomenetwork.com/wp-content/uploads/2022/11/Screen-Shot-2022-11-24-at-4.07.56-PM-300x86.png 300w, https://alexshomenetwork.com/wp-content/uploads/2022/11/Screen-Shot-2022-11-24-at-4.07.56-PM-768x220.png 768w" sizes="auto, (max-width: 801px) 100vw, 801px" /></figure>



<h5 class="wp-block-heading">Making Filebrowser a Service</h5>



<p class="wp-block-paragraph">Since remembering the command for Filebrowser can be difficult and you might want it to run in the background, it&#8217;s possible to make it a systemd service by creating a file in <code>/etc/systemd/system/filebrowser.service</code> with your favorite text editor, and adding the following lines (Replacing Filebrowser Command with your Filebrowser command, obviously):</p>



<pre class="wp-block-code"><code>&#91;Unit]
Descirption=Filebrowser

&#91;Service]
ExecStart=<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">Filebrowser Command</mark>

&#91;Install]
WantedBy=multi-user.target</code></pre>



<p class="wp-block-paragraph">Now you can run Filebrowser in the background simply by typing in <code>sudo systemctl start filebrowser</code>, or allow it to run at startup by typing in <code>sudo systemctl enable filebrowser</code>.</p>



<h3 class="wp-block-heading">Installing Nginx</h3>



<p class="wp-block-paragraph">To install Nginx, run the following command</p>



<pre class="wp-block-code"><code>sudo apt install nginx</code></pre>



<p class="wp-block-paragraph">Start Nginx by running the following command:</p>



<pre class="wp-block-code"><code>sudo systemctl start nginx</code></pre>



<p class="wp-block-paragraph">And then check its status:</p>



<pre class="wp-block-code"><code>sudo systemctl status nginx</code></pre>



<p class="wp-block-paragraph">If Nginx appears to be running, press q on your keyboard if the command didn&#8217;t quit, then type the IP address of your server into your web browser&#8217;s address bar. You should see a screen that looks like this:</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="832" height="372" src="https://alexshomenetwork.com/wp-content/uploads/2022/11/Screen-Shot-2022-11-24-at-9.32.03-AM.png" alt="" class="wp-image-337" style="width:498px;height:222px" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/11/Screen-Shot-2022-11-24-at-9.32.03-AM.png 832w, https://alexshomenetwork.com/wp-content/uploads/2022/11/Screen-Shot-2022-11-24-at-9.32.03-AM-300x134.png 300w, https://alexshomenetwork.com/wp-content/uploads/2022/11/Screen-Shot-2022-11-24-at-9.32.03-AM-768x343.png 768w" sizes="auto, (max-width: 832px) 100vw, 832px" /></figure>



<p class="wp-block-paragraph">Run the following command to allow Nginx to run at startup:</p>



<pre class="wp-block-code"><code>sudo systemctl enable nginx</code></pre>



<p class="wp-block-paragraph">Then make the Nginx user (www-data) the owner of the web directory:</p>



<pre class="wp-block-code"><code>sudo chown -R www-data:www-data /usr/share/nginx/html</code></pre>



<h4 class="wp-block-heading">Nginx Automatic Restart</h4>



<p class="wp-block-paragraph">If Nginx is killed, you&#8217;ll need to manually run <code>sudo systemctl restart nginx</code>, but it&#8217;s possible to automate this process. First create the following directory:</p>



<pre class="wp-block-code"><code>sudo mkdir -p /etc/systemd/system/nginx.service.d/</code></pre>



<p class="wp-block-paragraph">Create and open the following file with your favorite text editor:</p>



<pre class="wp-block-code"><code>/etc/systemd/system/nginx.service.d/restart.conf</code></pre>



<p class="wp-block-paragraph">Add the following lines (You can replace the highlighted text with whatever time you want, but don&#8217;t make it too short):</p>



<pre class="wp-block-code"><code>&#91;Service]
Restart=always
RestartSec=<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">5s</mark></code></pre>



<p class="wp-block-paragraph">Then finally run the following command so systemd will pick up the changes:</p>



<pre class="wp-block-code"><code>sudo systemctl daemon-reload</code></pre>



<p class="wp-block-paragraph">You can test that Nginx will be automatically restarted by running <code>sudo pkill nginx</code>, wait 5 seconds (Or however long you specified), and then run <code>sudo systemctl status nginx</code> to see if Nginx was restarted.</p>



<h4 class="wp-block-heading">Troubleshooting</h4>



<p class="wp-block-paragraph">If Nginx fails to start, the output of <code>sudo systemctl status nginx</code> should show some sort of error. If it doesn&#8217;t, then check the error log under <code>/var/log/nginx/error.log</code>.</p>



<p class="wp-block-paragraph">If Nginx appears to be running just fine, but you&#8217;re still unable to connect, check to make sure that port 80 is permitted in your firewall.</p>



<h3 class="wp-block-heading">Installing MariaDB</h3>



<p class="wp-block-paragraph">Run the following command to install the MariaDB client and server:</p>



<pre class="wp-block-code"><code>sudo apt install mariadb-server mariadb-client</code></pre>



<p class="wp-block-paragraph">Start MariaDB:</p>



<pre class="wp-block-code"><code>sudo systemctl start mariadb</code></pre>



<p class="wp-block-paragraph">Check its status:</p>



<pre class="wp-block-code"><code>sudo systemctl status mariadb</code></pre>



<p class="wp-block-paragraph">And if it&#8217;s running and there&#8217;s no errors, run the post installation security script:</p>



<pre class="wp-block-code"><code>sudo mysql_secure_installation</code></pre>



<p class="wp-block-paragraph">Select yes (Or just press enter) for all of the steps and follow the prompts.</p>



<p class="wp-block-paragraph">Finally, allow MariaDB to run at startup:</p>



<pre class="wp-block-code"><code>sudo systemctl enable mariadb</code></pre>



<h3 class="wp-block-heading">Installing PHP7.4</h3>



<p class="wp-block-paragraph">Depending on what you&#8217;re trying to run, you might need different PHP extensions than what I&#8217;ll list. The following command will install PHP7.4 along with the extensions that I use for WordPress:</p>



<pre class="wp-block-code"><code>sudo apt install php7.4 php7.4-bz2 php7.4-cli php7.4-common php7.4-curl php7.4-fpm php7.4-gd php7.4-intl php7.4-json php7.4-mbstring php7.4-mysql php7.4-opcache php7.4-readline php7.4-xml php7.4-zip php7.4-imagick</code></pre>



<p class="wp-block-paragraph">Start PHP:</p>



<pre class="wp-block-code"><code>sudo systemctl start php7.4-fpm</code></pre>



<p class="wp-block-paragraph">Check its status:</p>



<pre class="wp-block-code"><code>sudo systemctl status php7.4-fpm</code></pre>



<p class="wp-block-paragraph">And if it&#8217;s running, then enable it to run at startup:</p>



<pre class="wp-block-code"><code>sudo systemctl enable php7.4-fpm</code></pre>



<h3 class="wp-block-heading">Installing phpMyAdmin (Optional)</h3>



<p class="wp-block-paragraph">phpMyAdmin is very useful for managing MariaDB (Or any other compatible database), so I would recommend installing it. However, like some of the other tools I recommended, only do this if you can properly firewall it off. If it&#8217;s not properly firewalled off, than an attacker could easily gain access to your MariaDB database, thus the data of whatever relies on it.</p>



<p class="wp-block-paragraph">To start the installation process of phpMyAdmin, run the following command:</p>



<pre class="wp-block-code"><code>sudo apt install phpmyadmin</code></pre>



<p class="wp-block-paragraph">During installation, various prompts will be displayed. The first prompt will ask you what web server should automatically be configured, but if you&#8217;re using Nginx like me, press the tab key, then press enter:</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="562" height="339" src="https://alexshomenetwork.com/wp-content/uploads/2022/11/Screen-Shot-2022-11-25-at-3.36.28-PM.png" alt="" class="wp-image-357" style="width:562px;height:339px" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/11/Screen-Shot-2022-11-25-at-3.36.28-PM.png 562w, https://alexshomenetwork.com/wp-content/uploads/2022/11/Screen-Shot-2022-11-25-at-3.36.28-PM-300x181.png 300w" sizes="auto, (max-width: 562px) 100vw, 562px" /></figure>



<p class="wp-block-paragraph">The second prompt will ask you if you want to use dbconfig-common to automatically configure the database. Press enter to select yes:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="563" height="324" src="https://alexshomenetwork.com/wp-content/uploads/2022/11/Screen-Shot-2022-11-25-at-3.40.30-PM.png" alt="" class="wp-image-359" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/11/Screen-Shot-2022-11-25-at-3.40.30-PM.png 563w, https://alexshomenetwork.com/wp-content/uploads/2022/11/Screen-Shot-2022-11-25-at-3.40.30-PM-300x173.png 300w" sizes="auto, (max-width: 563px) 100vw, 563px" /></figure>



<p class="wp-block-paragraph">The last prompt will ask you to enter a password for the phpmyadmin user. Enter a password, then press enter. You&#8217;ll be prompted again to confirm your password:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="564" height="323" src="https://alexshomenetwork.com/wp-content/uploads/2022/11/Screen-Shot-2022-11-25-at-3.42.54-PM.png" alt="" class="wp-image-360" srcset="https://alexshomenetwork.com/wp-content/uploads/2022/11/Screen-Shot-2022-11-25-at-3.42.54-PM.png 564w, https://alexshomenetwork.com/wp-content/uploads/2022/11/Screen-Shot-2022-11-25-at-3.42.54-PM-300x172.png 300w" sizes="auto, (max-width: 564px) 100vw, 564px" /></figure>



<h4 class="wp-block-heading">Create an Nginx Server Block</h4>



<p class="wp-block-paragraph">Since the phpMyAdmin setup didn&#8217;t include an option to automatically configure Nginx, we&#8217;ll have to do it ourselves. Create a file in /etc/nginx/conf.d/phpmyadmin.conf using your favorite text editor, and add the following lines:</p>



<pre class="wp-block-code"><code>server {
  #Change the highlighted port numbers.
  listen <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">1234</mark>;
  #The line below is optional. You don't need it if your server doesn't support IPv6.
  listen &#91;::]:<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-secondary-color">1234</mark>;
  server_name _;
  root /usr/share/phpmyadmin/;
  index index.php index.html index.htm index.nginx-debian.html;

  access_log /var/log/nginx/phpmyadmin_access.log;
  error_log /var/log/nginx/phpmyadmin_error.log;

  location / {
    try_files $uri $uri/ /index.php;
  }

  location ~ ^/(doc|sql|setup)/ {
    deny all;
  }

  location ~ \.php$ {
    fastcgi_pass unix:/run/php/php7.4-fpm.sock;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;
    include snippets/fastcgi-php.conf;
  }

  location ~ /\.ht {
    deny all;
  }
}</code></pre>



<p class="wp-block-paragraph">Run the following command to have Nginx test your config file:</p>



<pre class="wp-block-code"><code>sudo nginx -t</code></pre>



<p class="wp-block-paragraph">If there&#8217;s no errors, restart Nginx:</p>



<pre class="wp-block-code"><code>sudo systemctl restart nginx</code></pre>



<p class="wp-block-paragraph">Access phpMyAdmin by typing in <code>your_ip_address:your_port_number</code> into your web browser. If everything works correctly, then you should see the phpMyAdmin login screen. You can either use <code>root</code> as the username with the password that you chose while installing MariaDB, or use <code>phpmyadmin</code> as the username and the password that you chose while installing phpmyadmin. You can also use the login of any other database user that you might have.</p>



<p class="wp-block-paragraph">If you&#8217;ve decided to follow this post and you&#8217;ve followed everything correctly (Or I didn&#8217;t screw up), then congratulations. You should now have Nginx, MariaDB, and PHP7.4 installed and ready to host your dynamic website. Read part 2 where I&#8217;ll show you how to install WordPress on top of this LEMP stack. I hope that you enjoyed reading this post, and hopefully you learned something too. If you have any problems, feel free to leave a comment, and I&#8217;ll try my best to help you (I can&#8217;t guarantee anything though).</p>



<p class="wp-block-paragraph">Part 2: <a href="https://alexshomenetwork.com/installing-wordpress-on-lemp-stack/" target="_blank" rel="noreferrer noopener">Installing WordPress with Nginx, MariaDB, and PHP7.4 (LEMP Stack) on Debian – Building a WordPress Blog Part 2</a></p>



<h3 class="wp-block-heading">References</h3>



<p class="wp-block-paragraph">Here&#8217;s all of the references I used, and two of them are arguably better tutorials.</p>



<p class="wp-block-paragraph"><a href="https://www.linuxbabe.com/ubuntu/install-lemp-stack-ubuntu-20-04-server-desktop" target="_blank" rel="noreferrer noopener">LinuxBabe&#8217;s tutorial on how to install a LEMP stack on Ubuntu</a></p>



<p class="wp-block-paragraph"><a href="https://www.linuxbabe.com/ubuntu/install-phpmyadmin-nginx-lemp-ubuntu-20-04" target="_blank" rel="noreferrer noopener">LinuxBabe&#8217;s Tutorial on How to Install phpMyAdmin</a></p>



<p class="wp-block-paragraph"><a href="https://filebrowser.org/installation/" target="_blank" rel="noreferrer noopener">Filebrowser installation and Documentation</a></p>
<p>The post <a href="https://alexshomenetwork.com/installing-nginx-mariadb-and-php74-on-debian/">Installing Nginx, MariaDB, and PHP7.4 (LEMP Stack) on Debian – Building a WordPress Blog Part 1</a> appeared first on <a href="https://alexshomenetwork.com">Alex&#039;s Home Network</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://alexshomenetwork.com/installing-nginx-mariadb-and-php74-on-debian/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
