Install PiHole With SSL On Apache Running Ubuntu Server 20 LTS

This is another quick post to serve as a general note. This post will cover the install of PiHole with SSL on Apache. The guide should work for most Debian-based Linux distributions. We are running PHP7.4 as it’s native to the OS and does not require any PPA addons. You can install PHP8/+ if you like.

Step 1: Bash Into root


1
     sudo bash

Enter your password.

Step 2: Install Apache2


1
     apt-get install apache2 -y

Step 3: Install PHP 7.4


1
2
     apt-get install php -y
     apt-get install php-common php-mysql php-xml php-curl php-cli php-imap php-mbstring php-opcache php-soap php-zip php-intl php-sqlite3 -y

Step 4: Install PiHole


1
     curl -sSL https://install.pi-hole.net | bash

During the course of the install, you will be prompted ~5 times. At the last prompt, you will be asked if you want to install the Lighttpd web server. At this point, you want to select no and complete the install process.

Once completed your PiHole setup should work. and should be accessible via ip/domain.com/admin/

Step 5 Cleanup:

As of today, I have noticed a rare glitch that will cause the folder structure to be odd after the pihole install. This can be easily fixed with the following details.

The default install will create folders like this:


1
2
     pihole folder: /var/www/html/pihole
     admin folder: /var/www/html/admin

Although not a big deal, this causes a problem when trying to access the admin dashboard from the default pihole URL (http://ip/pihole), the link on the page that is supposed to link to the admin page will be broken. At this point, you can update the page link manually in pihole/index.php to forward to the correct URL or you can change/move folders to your liking.

To fix this issue, as root, first we move the folder to the correct directory.


1
     mv /var/www/html/admin /var/www/html/pihole

Second, we update the default pihole root index file links


1
    vim /var/www/www/html/pihole/index.php

We want to edit three lines 77, 81, and 83 to reflect the new URL structure.


1
2
3
4
5
6
7
8
     Line 77:
     <link rel='shortcut icon' href='/pihole/admin/img/favicons/favicon.ico' type='image/x-icon'>

     Line 81:
     <img src='/pihole/admin/img/logo.svg' alt='Pi-hole logo' id="pihole_logo_splash" />

     Line 83:
     <a href='/pihole/admin/'>Did you mean to go to the admin panel?</a>

Once done you can consider the process complete.

Step S: Installing SSL on PiHole:

To keep things classy, if not already, bash into root:


1
     sudo bash

Let’s enable the PHP’s SSL module and make our SSL folder to house our certs.


1
2
     a2enmod ssl
     mkdir /etc/apache2/certs/pihole

Now let’s generate our self-signed cert:


1
     openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/apache2/certs/pihole/piholio.key -out /etc/apache2/certs/pihole/piholio.crt

Edit our default SSL virtual hosts config:


1
     vim /etc/apache2/sites-available/default-ssl.conf

Replace lines 32 and 33 with the following lines


1
2
     SSLCertificateFile /etc/apache2/certs/pihole/piholio.crt
     SSLCertificateKeyFile /etc/apache2/certs/pihole/piholio.key

Save and exit.

Next, enable SSL and restart the apache service:


1
     a2ensite default-ssl.conf && systemctl apache2 restart

At this point, you’ve successfully installed PiHole with SSL. We have another issue, by default apache does not reroute to SSL so you will still be able to visit the non-SSL URL. To fix this we need to enable the Rewrite module and enter our conditions into our domain’s virtual host configuration (or .htaccess).

Let’s enable that rewrite module:


1
2
     a2enmod rewrite
     systemctl apache2 restart

Let’s edit our default virtual host file:


1
     vim /etc/apache2/sites-available/000-default.conf

Add the following three lines of code before the </VirtualHost> closing tag. You can replace the * on the second line with your local IP or domain.


1
2
3
     RewriteEngine On
     RewriteCond %{SERVER_NAME} =*
     RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]

Save the file and restart Apache.


1
     systemctl apache2 restart

Your PiHole install should now be “running in SSL”. If anyone viewing my notes has questions feel free to leave a comment.

Install PHP8 on Ubuntu Server 18 & 20 LTS Running Apache

This post is a quick post to serve as a note, don’t expect long explanations of general LAMP stack design concepts. If you encounter any issues feel free to leave a comment below.

Step 1: Bash Into root User


1
2
    sudo bash
    ("sudo -su" if you prefer)

Enter your password to enter the root superuser account.

Step 2: Preparation

As root enter


1
     apt-get update -y && apt-get upgrade -y && apt-get dist-upgrade -y && apt-get autoremove -y && apt-get autoclean -y

Step 3: Adding PHP8 Repository


1
     apt-get install ca-certificates apt-transport-https software-properties-common -y

Once the command above completes its process:


1
     add-apt-repository ppa:ondrej/php -y && apt-get update -y

Step 4: Installing PHP8


1
     apt-get install php8.0 libapache2-mod-php8.0 -y && systemctl restart apache2

1
     apt-get install php8.0-fpm libapache2-mod-fcgid

Enable default PHP8 FastCGI manager module and config:


1
2
     a2enmod proxy_fcgi setenvif
     a2enconf php8.0-fpm

Restart Apache:


1
systemctl restart apache2

You might need these as well… MySQL, MBString, and MailParse


1
     apt-get install php8.0-mbstring php8.0-mailparse php8.0-mysql php8.0-xml php8.0-zip -y

WordPress Modules


1
     apt-get install php8.0-imagick -y

*****

To get jiggy with it… (installs all PHP modules, typically reserved for DevOps/Sandboxing)


1
     apt-get install php8.0-dev

*****

Once you’re done with installing any additional modules, although not required, it’s recommended you reboot your machine. Let’s do a little cleanup in case something unnecessary (like previous PHP7 packages) was left behind.


1
     apt-get update -y && apt-get upgrade -y && dist-upgrade -y && apt-get autoclean -y && apt-get autoremove -y && reboot

Step 5 (Optional): Additional Caching Modules

Memcached


1
     apt-get install php8.0-memcached

Redis


1
     apt-get install php8.0-redis

Solving the PHP Warning: fsockopen(): unable to connect (Connection timed out)

If you’ve worked with APIs you’ve probably gotten this error and know how annoying it is. All because the native function never returns any actionable error for its request timing out. The best way to detect if the fsockopen() function request is timing out is to use a error control operator. The idea is to suppress the timeout warning with a @ prefix, so the function only returns true if it completes its cycle/request. You can review the example PHP code below.

1
2
3
4
5
6
7
8
9
10
11
12
    if($fp = @://www.php.net/fsockopen">fsockopen($host, $port, $errno, $errstr, $timeout))
    {  

        return true;
                   
    }
    else
        {
         
            return false;

        }

Issues? leave your questions.

PHP CLI & Terminal Colors

A Simple PHP class for wrapping your console/terminal output text in color. Keep in mind that building a class for such projects will require customization as each terminal emulator will process colors a bit different. For the most part, the colors in this class work with any popular terminal emulator.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
    // Command Line Interface Class
    class CLI
    {

        // this function requires 1 variable, content. The color arguement is optional.
        function cout_color($content, $color=null)
        {
           
            // if a color is set use the color set.
            if(!://www.php.net/empty">empty($color))
            {
                // if our color string is not a numeric value
                if(!://www.php.net/is_numeric">is_numeric($color))
                {
                        //lowercase our string value.
                        $c = strtolower($color);
                   
                }
                else
                    {  
                        // chec if our color value is not empty.
                        if(!://www.php.net/empty">empty($color))
                        {
                           
                            $c = $color;
                       
                        }
                        else
                            {
                                // no color was set so lets pick a random one...
                                $c = rand(1,14);
                               
                            }
                       
                    }
                   
            }
            else    // no color @paramter was passed, so lets pick a random one...
                {
                   
                    $c = rand(1,14);
                               
                }
           
            $cheader = '';
            $cfooter = "\033[0m";
           
            // let check which color code was used so we can then wrap our content.
            switch($c)
            {
                       
                case 1:
                case 'red':
                   
                    // color code header.
                    $cheader .= "\033[31m";

                break;
               
                case 2:
                case 'green':
                   
                    // color code
                    $cheader .= "\033[32m";

                break;

                case 3:
                case 'yellow':
                   
                    // color code
                    $cheader .= "\033[33m";

                break;
               
                case 4:
                case 'blue':
                   
                    // color code
                    $cheader .= "\033[34m";

                break;
               
                case 5:
                case 'magenta':
                   
                    // color code
                    $cheader .= "\033[35m";

                break;
               
                case 6:
                case 'cyan':
                   
                    // color code
                    $cheader .= "\033[36m";

                break;
               
                case 7:
                case 'light grey':
                   
                    // color code
                    $cheader .= "\033[37m";

                break;
               
                case 8:
                case 'dark grey':
                   
                    // color code
                    $cheader .= "\033[90m";

                break;
               
                case 9:
                case 'light red':
                   
                    // color code
                    $cheader .= "\033[91m";

                break;
               
                case 10:
                case 'light green':
                   
                    // color code
                    $cheader .= "\033[92m";

                break;
               
                case 11:
                case 'light yellow':
                   
                    // color code
                    $cheader .= "\033[93m";

                break;
               
                case 12:
                case 'light blue':
                   
                    // color code
                    $cheader .= "\033[94m";

                break;
               
                case 13:
                case 'light magenta':
                   
                    // color code
                    $cheader .= "\033[95m";

                break;
               
                case 14:
                case 'light cyan':
                   
                    // color code
                    $cheader .= "\033[92m";

                break;
               
            }
             
            // wrap our content.
            $content = $cheader.$content.$cfooter;
           
            //return our new content.
            return $content;
           

        }
         
         

    }

Example Usage:

1
2
3
4
5
6
7
8
9
10
    $cli = new CLI();

    // echo a string using the class string color 'red'.
    echo $cli-&gt;cout_color('It Works!', 'red');

    // echo a string using the class color id 1.
    echo $cli-&gt;cout_color('It Works!', 1);

    // echo a string using a random color.
    echo $cli-&gt;cout_color('It Works!');

Add/Remove based on your project requirements.

Updating To PHP 5.4 On Ubuntu Server 12.04 LTS

If you use php web applications then your know a lot are now demanding to be updated to php 5.4 or higher. To do this in Ubuntu 12.04LTS simply do the following…

If you haven’t already used ppa then you will have to first install python software properties, make sure you’re the root user… ( sudo bash )

apt-get install python-software-properties

PHP 5.4.x run:

add-apt-repository ppa:ondrej/php5-oldstable

PHP 5.5.x run:

add-apt-repository ppa:ondrej/php5

Once you’ve added the repo simply update and upgrade current packages & distribution packages with one simple command :)

apt-get update && apt-get upgrade -y && apt-get dist-upgrade -y

Google Maps Error 610 Bad Key, Responsive HTML5 Google Map API V3

 

Getting a 610 error response from Google lately? Perhaps you have a bad API key? Not really it actually might be because Google deprecated support for their API V2…

 

Want to learn how to make a responsive google map for your site using PHP & HTML5 on API 3? here is how…

 

Note: In API V3 you do not require or use an api key.

 

Objectives:
Create a quick solution to produce responsive HTML5 Google Maps on the fly.

  1. write HTML
  2. write CSS
  3. write php/curl function
  4. example of use
  5. sample

First we will begin with a quick HTML wrapper and to place our iframe in…

1
class="wrapper">

 

Use CSS to control the iframe and wrapper, this will also keep iframe in widescreen/16:9

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
.wrapper

{
height: 0;
padding-bottom: 56.25%; /* 16: 9 */
position: relative;
width: 100%;
margin: 0;
overflow: hidden;
}
iframe

{
height: 100%;
left: 0;
position: absolute;
top: 0;
width: 100%;
border: 0;
overflow: hidden;
}

 

Now lets create the function that will generate a iframe tag on the fly by simply passing 1 value… an address

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# google map iframe generation
function gMap($a)
{
// setting up vars
$lat = '';
$lon = '';
$addr = $a;
$addr = urlencode($addr);
$u="http://maps.googleapis.com/maps/api/geocode/json?address=".$addr."&sensor=false"; // URL
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $u);
curl_setopt($ch, CURLOPT_HEADER,0);
curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER["HTTP_USER_AGENT"]);
// Comment out the line below if you receive an error on certain hosts that have security restrictions
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$d = curl_exec($ch);
curl_close($ch);
$g = json_decode($d, true);
// Debugging Purposes... or if you wanna use additional data...
//echo '
';
//print_r($g);
//echo '

';
// If the Json request was successful...
if ($g)
{
$lat = $g['
results'][0]['geometry']['location']['lat'];
$lon = $g['
results'][0]['geometry']['location']['lng'];
$m = '
';
echo $m;
} else {
echo "

No Map Available

";
}
}

 

Our php then goes inside the div

1
2
3
4
5
6
7
8
9
class="wrapper">

// you can insert a var instead of string if you wish ex: gMap($address)
gMap('48034 Rancho Way Temecula CA, 92592');

?>

 

An example of a running script

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

# google map iframe generation
function gMap($a)
{
// setting up vars
$lat = '';
$lon = '';
$addr = $a;
$addr = urlencode($addr);
$u="http://maps.googleapis.com/maps/api/geocode/json?address=".$addr."&sensor=false"; // URL
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $u);
curl_setopt($ch, CURLOPT_HEADER,0);
curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER["HTTP_USER_AGENT"]);
// Comment out the line below if you receive an error on certain hosts that have security restrictions
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$d = curl_exec($ch);
curl_close($ch);
$g = json_decode($d, true);

// Debugging Purposes... or if you wanna use additional data...
//echo '
';
//print_r($g);
//echo
;
// If the Json request was successful...

if ($g)
{
$lat = $g['
results'][0]['geometry']['location']['lat'];
$lon = $g['
results'][0]['geometry']['location']['lng'];
$m = '
';
echo $m;
} else {
echo "

No Map Available

";
}
}

?>



// you can insert a var instead of string if you wish ex: gMap($address)
gMap('48034 Rancho Way Temecula CA, 92592');
?>

Let me know if you have any questions. :)

PHP Startup: Unable to load dynamic library ‘/usr/lib/php5/20090626/mcrypt.so’ – libmcrypt.so.4: cannot open shared object file: No such file or directory in Unknown on line 0

Ok so I decided to quickly make this post because it was such a bitch to figure this out, all the information regarding missing dynamic libraries are in many cases unclear and could not find anything specific on the mcrypt library.

if you get the:
PHP Startup: Unable to load dynamic library ‘/usr/lib/php5/20090626/mcrypt.so’ – libmcrypt.so.4: cannot open shared object file: No such file or directory in Unknown on line 0

Here is whats going on…
you are missing files that are part of Apaches/PHP’s resources or you php.ini has the “entension_dir” value duplicated/actively pointing to the wrong location or php-cli is using the wrong php.ini config file. In my case it was due to a glitch with Ubuntu servers live OS update to 12.04.1 LTS which removed the old libraries and never re-installed them as part of the update.
Here is the checklist that will save you a long-ass headache, one that I unfortunately went through…

1) check your php.ini and make sure your “extension_dir” value (typically between line 805-809) is nulled out so its not processed (usually has a ; in front of it) in some cases the php.ini can be in multiple locations for apache/php-cli etc…
2) your mcrypt.so library is missing or corrupt.

first lets remove any possible installations of mcrypt libraries by running this in a shell, if you don’t have it installed skip this step (or you can still do it and if its not installed it will do nothing)…

1
2
sudo apt-get remove php5-mcrypt
sudo apt-get purge php5-mcrypt

then run this in a shell…

1
2
apt-get install php5-mcrypt
/etc/init.d/apache2 restart

(or you can sudo reboot too ;))

once this is done you should no longer get this error. If you have any issues please leave me a comment below :)

Using PHP To Pull Your Last Tweet Via Twitters Atom Timeline

Ok here is a simple script that will help you pull your latest feed from your twitter atom rss timeline without the use of cURL :)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# Enter your twitter username
$username = "websymantecs";

#page title (if you want one >:P)
$prefix = "<h2>Tweet Tweet</h2>";

# Suffix - some text you want display after your latest tweet. (Same rules as the page title.)
$suffix = "";

# Our prepared URL
$feed = "http://search.twitter.com/search.atom?q=from:" . $username . "&rpp=1";

# time to process our request
function parse_feed($feed) {
// time for our data parsing
$phase1 = explode("<content type="html">", $feed);
$phase2 = explode("</content>", $phase1[1]);
$tweet = $phase2[0];
$tweet = str_replace("&lt;", "<", $tweet);
$tweet = str_replace("&gt;", ">", $tweet);
$tweet = str_replace("&quot;", "", $tweet);
return $tweet;
}
# Parsed and echo to the screen.
$twitterFeed = file_get_contents($feed);
echo parse_feed($twitterFeed) . stripslashes($suffix);

Its that simple, enjoy! xD!

After a successful feed, you can use CSS to style the returned data.

Removing Login Fields From Justin Kliens WP-Facebook-Autoconnect

First of all I would like to say thanks to Justin for the plugin, it saved me some time :)
You can find his easy to use plugin at his personal blog site: http://www.justin-klein.com/projects/wp-fb-autoconnect/

This modification will work with Version 1.3.10

After about half an hour I was able to find the code that was causing a second duplicate login and password field. I am sure Justin was thinking ahead with the login fields but in some cases it actually interferes with the blog design/UI. The other problem was the welcome and edit profile links once logged in.

The block of code is found in 2 sections within Widget.php

The First NULLED section will remove the Welcome and Edit profile links once a user is logged in.
The Second NULLED section of code will remove the login fields.

Widget.php
Note: you can copy and past this entire code onto your Widget.php file to update it or download the file directly from the link at the bottom of this post.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200

/**

  * Sidebar LoginLogout widget with Facebook Connect button

  **/


class Widget_LoginLogout extends WP_Widget

{

    //////////////////////////////////////////////////////

    //Init the Widget

    function Widget_LoginLogout()

    {

        $this->WP_Widget( false, "WP-FB AutoConnect", array( 'description' => 'A sidebar Login/Logout form with Facebook Connect button' ) );

    }

     

    //////////////////////////////////////////////////////

    //Output the widget's content.

    function widget( $args, $instance )

    {

        //Get args and output the title

        extract( $args );

        echo $before_widget;

        $title = apply_filters('widget_title', $instance['title']);

        if( $title ) echo $before_title . $title . $after_title;

       

        //If logged in, show "Welcome, User!"

        $userdata = wp_get_current_user();

        if( $userdata->ID ):

        ?>

/*?>            
########################################################################
########################################################################
########################################################################
           
NULLED  TO PREVENT THE WELCOME MESSAGE ONCE THE USE IS LOGGED IN-->
           
           


              display_name?>!


             

                |

             


           

           
## END OF NULL <--
 */?>

       
        //Otherwise, show the login form (with Facebook Connect button)

        else:

        ?>

/*      

########################################################################
########################################################################
########################################################################
           
NULLED TO PREVENT THE WIDGETS LOGIN FIELDS-->
   
               
/wp-login.php' method='post'>

               


               


               


               

                ?


                ";?>

               

                ' />

           

           
##END OF NULL <--
*/?>
           
            global $opt_jfb_hide_button;

            if( !get_option($opt_jfb_hide_button) )

            {

                jfb_output_facebook_btn();

                jfb_output_facebook_init();

                jfb_output_facebook_callback();

            }

        endif;

        echo $after_widget;

    }

   

   

    //////////////////////////////////////////////////////

    //Update the widget settings

    function update( $new_instance, $old_instance )

    {

        $instance = $old_instance;

        $instance['title'] = $new_instance['title'];

        return $instance;

    }



    ////////////////////////////////////////////////////

    //Display the widget settings on the widgets admin panel

    function form( $instance )

    {

        ?>

       



           

            class="widefat" id="$this->get_field_id('title'); ?>" name="$this->get_field_name('title'); ?>" type="text" value="$instance['title']; ?>" />

       



       
    }

}





//Register the widget

add_action( 'widgets_init', 'register_jfbLogin' );

function register_jfbLogin() { register_widget( 'Widget_LoginLogout' ); }



?>

Once you have made the 2 listed changes your facebook button may be out of alignment from your theme, to simply fix this add some padding using css in the following file:

Main.php (lines 105-109)

1
2
3

If this too much code for you and you just want the login fields gone download the following files and replace the ones in your x:/wp-content/plugins/wp-fb-autoconnect folder.

Download Files