<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mark Voorberg</title>
    <description>The latest articles on DEV Community by Mark Voorberg (@4umfreak).</description>
    <link>https://dev.to/4umfreak</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F180487%2F0503f250-d1e8-40a3-8eed-cb4b746ab995.jpg</url>
      <title>DEV Community: Mark Voorberg</title>
      <link>https://dev.to/4umfreak</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/4umfreak"/>
    <language>en</language>
    <item>
      <title>Connecting to remote MySql from Google AppEngine
</title>
      <dc:creator>Mark Voorberg</dc:creator>
      <pubDate>Sat, 17 Oct 2020 03:11:02 +0000</pubDate>
      <link>https://dev.to/4umfreak/connecting-to-remote-mysql-from-google-appengine-3jgk</link>
      <guid>https://dev.to/4umfreak/connecting-to-remote-mysql-from-google-appengine-3jgk</guid>
      <description>&lt;p&gt;You've built your app and it does everything you dreamed of and more. It connects to a local MySql database and does all the good things, but now it's time to publish it for the masses. You carefully evaluate your options, review the value proposition for each hosting provider and the estimated monthly cost for running your app. You've decided to use an existing MySql database and deploy the application itself on Google's AppEngine service.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;gcloud app deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You run the command from your terminal and it deploys perfectly... Oh, except the database won't connect. What the hell? It works perfectly from your local environment. &lt;/p&gt;

&lt;h3&gt;
  
  
  It's caught in the firewall!!
&lt;/h3&gt;

&lt;p&gt;The server that's hosting your MySql database wouldn't last long without a firewall in place and that's exactly what's tripping up your application.&lt;/p&gt;

&lt;p&gt;Assuming you have root access to the database server, you can add rules to the firewall to allow connections on port 3306, the default MySql port. That's all well and good, except the part where your new AppEngine service gets a new IP address every time you deploy it, or simply because it's a new day and you're busy running to fetch donuts or something equally important.&lt;/p&gt;

&lt;p&gt;On Linux, you're probably running &lt;em&gt;ConfigServer Security &amp;amp; Firewall&lt;/em&gt; or csf as your firewall. Rules are loaded from &lt;code&gt;/etc/csf/csf.allow&lt;/code&gt; and can be single IP addresses or a range of addresses using CIDR addressing. Additionally you can specify tcp vs udp and the specific port you want to allow.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hosting on a Static IP
&lt;/h3&gt;

&lt;p&gt;If your application needed to connect to MySql port 3306 from  a static IP address you could get away specifying just that one IP address, as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# My Application hosted on IP: 123.45.67.89
tcp|in|d=3306|s=123.45.67.89
tcp|out|s=3306|d=123.45.67.89
# End of My Application
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's pretty simple but hosting on AppEngine doesn't get a static IP.&lt;/p&gt;

&lt;h3&gt;
  
  
  What addresses do AppEngine use?
&lt;/h3&gt;

&lt;p&gt;Google provides a way to discover the range of IP addresses that could be used, but it ain't pretty. Using &lt;code&gt;dig&lt;/code&gt; a linux DNS lookup tool, we can work it backwards from the published DNS name:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;_cloud-netblocks.googleusercontent.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The following command tells us what names we need to look at for IP ranges.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dig TXT _cloud-netblocks.googleusercontent.com @ns1.google.com +short 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output is all munged together on one line and wrapped in double quotes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"v=spf1 &lt;/li&gt;
&lt;li&gt;include:_cloud-netblocks1.googleusercontent.com &lt;/li&gt;
&lt;li&gt;include:_cloud-netblocks2.googleusercontent.com &lt;/li&gt;
&lt;li&gt;include:_cloud-netblocks3.googleusercontent.com &lt;/li&gt;
&lt;li&gt;include:_cloud-netblocks4.googleusercontent.com &lt;/li&gt;
&lt;li&gt;include:_cloud-netblocks5.googleusercontent.com &lt;/li&gt;
&lt;li&gt;?all"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If we pick out each one of those domain names, we can get the IP subnets that each one represents.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; dig TXT _cloud-netblocks4.googleusercontent.com @ns1.google.com +short
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;"v=spf1 &lt;/li&gt;
&lt;li&gt;ip4:35.219.192.0/24 &lt;/li&gt;
&lt;li&gt;ip4:35.220.0.0/14 &lt;/li&gt;
&lt;li&gt;ip4:35.224.0.0/13&lt;/li&gt;
&lt;li&gt;?all"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using these ranges we can build rules to allow MySql Connections from any IP's within the possible IP address ranges for AppEngine services as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tcp|in|d=3306|s=35.219.192.0/24
tcp|out|s=3306|d=35.219.192.0/24
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's all well and good but there's a lot of them (100+ !) and they won't stay the same forever, so we need a better way to update them. &lt;/p&gt;

&lt;p&gt;If we can put them all into a single file, we can add them to the csf rules with an &lt;code&gt;include&lt;/code&gt; statement like the ones at the top of our &lt;code&gt;/etc/csf/csf.allow&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Include /etc/csf/appengine.allow
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using the &lt;code&gt;dig&lt;/code&gt; commands already covered and a bit of bash scripting, we can piece the whole thing together like so:&lt;br&gt;
&lt;/p&gt;

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

netblocks=$(dig TXT _cloud-netblocks.googleusercontent.com @ns1.google.com +short)

now=$(date)
printf "########################################\n"
printf "# GCP AppEngine Rules\n"
printf "# %s\n" "$now"
printf "########################################\n"

for block in $netblocks; do
    if [[ $block == include:* ]]; then
        printf "# ${block#include:}\n"
        ipblocks=$(dig TXT ${block#include:} @ns1.google.com +short)
        # Inbound rules
        for ipblock in $ipblocks; do
            if [[ $ipblock == ip4:* ]]; then
                printf "tcp|in|d=3306|s=${ipblock:4}\n"
            fi
        done
        printf "\n"

        # Outbound rules
        for ipblock in $ipblocks; do
            if [[ $ipblock == ip4:* ]]; then
                printf "tcp|out|s=3306|d=${ipblock:4}\n"
            fi
        done
        printf "\n"
    fi
done

printf "########################################\n"
printf "# End of GCP AppEngine Rules\n"
printf "########################################\n"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I put the above script in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/etc/csf/appengine.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Updated it with execute permissions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;chmod +x /etc/csf/appengine.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And added it to the bottom of my crontab:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Add the following line to schedule it to run every Monday morning at 4:10 am and restart csf. Any output should be discarded with &lt;code&gt;&amp;gt; /dev/null 2&amp;gt;&amp;amp;1&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;10 4 * * 1 /etc/csf/appengine.sh &amp;gt; /etc/csf/appengine.allow &amp;amp;&amp;amp; csf --restart &amp;gt; /dev/null 2&amp;gt;&amp;amp;1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That should update my allow file every week &amp;amp; restart the firewall to use the new rules.&lt;/p&gt;

&lt;p&gt;Now, when my AppEngine service get's a new IP address, or Google comes up with a new range of addresses - that may get assigned to my app, I don't need to worry about it. I can be assured that the new IP's will be allowed to connect to my database!&lt;/p&gt;

&lt;p&gt;Thanks for reading &amp;amp; good luck with your AppEngine project!&lt;/p&gt;

</description>
      <category>appengine</category>
      <category>cpanel</category>
      <category>mysql</category>
      <category>linux</category>
    </item>
    <item>
      <title>Socket.io with Apache on a CPanel VPS</title>
      <dc:creator>Mark Voorberg</dc:creator>
      <pubDate>Tue, 30 Jun 2020 23:45:58 +0000</pubDate>
      <link>https://dev.to/4umfreak/socket-io-with-apache-on-a-cpanel-vps-19cm</link>
      <guid>https://dev.to/4umfreak/socket-io-with-apache-on-a-cpanel-vps-19cm</guid>
      <description>&lt;p&gt;I've been running Node.js apps on my WHM/CPanel VPS for a little over a year now and proxying web requests through Apache has been working pretty well. &lt;/p&gt;

&lt;p&gt;However, with my latest project, I'm using Socket.io to send messages to the front-end in real-time. I had everything working locally, but after deploying both the API and my front-end, the websockets were unable to connect.&lt;/p&gt;

&lt;p&gt;After a bit of reading, it became clear that I need to use &lt;code&gt;ProxyPass&lt;/code&gt; which isn't allowed in a .htaccess file. On a typical deployment you'd add it to a configuration file under the &lt;code&gt;sites-available&lt;/code&gt; folder, but with WHM/CPanel, that option just isn't there.&lt;/p&gt;

&lt;p&gt;On a cPanel/WHM server, the Apache configuration file is an &lt;code&gt;httpd.conf&lt;/code&gt; that gets re-generated each time changes are made, so it's &lt;em&gt;really&lt;/em&gt; not recommended to make changes to it manually. &lt;/p&gt;

&lt;p&gt;Here's the notice at the bottom of the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
#   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
#   DO NOT EDIT. AUTOMATICALLY GENERATED.  USE INCLUDE FILES IF YOU NEED TO MAKE A CHANGE
#   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;That doesn't mean we can't override to the VirtualHost settings, we just need to make our changes in an include file.&lt;/p&gt;

&lt;p&gt;Have a look at your httpd.conf by printing it to the terminal with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cat /etc/httpd/conf/httpd.conf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Note the following lines after each VirtualHost, where &lt;code&gt;myuser&lt;/code&gt; and &lt;code&gt;mydomain.net&lt;/code&gt; match your CPanel account.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# To customize this VirtualHost use an include file at the following location
# Include "/etc/apache2/conf.d/userdata/ssl/2_4/myuser/api.mydomain.net/*.conf"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Notice that the path above includes ".../ssl/...". &lt;br&gt;
There's a corresponding ".../std/..." for services that&lt;br&gt;
don't require a secure connection. I won't recommend&lt;br&gt;
running any services without SSL, so I didn't even look&lt;br&gt;
at that configuration.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The folder listed above won't likely exist yet, but you can create it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /etc/apache2/conf.d/userdata/ssl/2_4/myuser/api.mydomain.net
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Then create a new config file with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /etc/apache2/conf.d/userdata/ssl/2_4/myuser/api.mydomain.net
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;touch &lt;/span&gt;custom.conf
&lt;span class="nv"&gt;$ &lt;/span&gt;nano custom.conf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The contents of the custom configuration will vary based on your need, but in my case, I needed to connect to a socket host running on port 7222 on the &lt;code&gt;api.mydomain.net&lt;/code&gt; subdomain. The same subdomain also hosts my Node.js REST api, so I needed to split out the websocket traffic and upgrade it as needed.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;FYI: I wasted a lot of time editing my &lt;code&gt;custom.conf&lt;/code&gt; file in the domain root ".../myuser/mydomain.net", where it should have been in the folder that corresponds to my subdomain ".../myuser/&lt;strong&gt;api.&lt;/strong&gt;mydomain.net".&lt;br&gt;
It was a huge waste of time as I fiddled with settings that were not applied to the subdomain where I was testing my application. If you're making edits that don't appear to have any effect, confirm that your config file is in the folder for the domain you're testing against.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In broad strokes, I need to proxy any websocket traffic to localhost:7222. The contents of my &lt;code&gt;custom.conf&lt;/code&gt; file is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ProxyPreserveHost On
RewriteEngine On

# Upgrade connections to WebSockets
RewriteCond %{HTTP:Upgrade} =websocket [NC]
RewriteRule /(.*) ws://localhost:7222/$1 [P,L]

# Redirect http to https
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

# Everything else forwards as HTTP to the node app.
ProxyPass / http://127.0.0.1:7222/
ProxyPassReverse / http://127.0.0.1:7222/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Once I felt that the rules were correct I saved the file and ran:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ /scripts/verify_vhost_includes
&amp;gt; Testing
&amp;gt; /etc/apache2/conf.d/userdata/ssl/2_4/myuser/api.mydomain.net/custom.conf...ok
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This confirmed that my changes weren't broken so badly that they'd prevent Apache from trying to load them. If that were to happen, and I didn't test it first, I could potentially prevent other websites on my host from being served.&lt;/p&gt;

&lt;p&gt;This is only one of two VirtualHosts with a custom config file on my machine so I was happy to make sure we use all the existing include files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ /scripts/ensure_vhost_includes --all-users
&amp;gt; Built /etc/apache2/conf/httpd.conf OK
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Alternatively, I could have used the following CPanel script to ensure that my &lt;code&gt;httpd.conf&lt;/code&gt; contained the necessary &lt;code&gt;Include&lt;/code&gt; statements.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ /usr/local/cpanel/scripts/rebuildhttpdconf
&amp;gt; Built /etc/apache2/conf/httpd.conf OK
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The only remaining step was to bounce Apache &amp;amp; test out my new VirtualHost Rewrite &amp;amp; ProxyPass rules.&lt;/p&gt;

&lt;p&gt;To restart Apache, run the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ /scripts/restartsrv_httpd
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This should do a soft restart, which simply means that it will restart after it finishes serving any active connections.&lt;/p&gt;

&lt;p&gt;After making these changes, my Angular app socket service was able to successfully connect to a Node.js app running behind my Apache webserver.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>node</category>
      <category>linux</category>
      <category>angular</category>
    </item>
  </channel>
</rss>
