Blog

Get YouTube Refresh Token from OAuth 2.0 Playground

Getting a YouTube (or other Google product/service) refresh token using Google’s OAuth 2.0 Playground is easy. Just follow this brief tutorial.

Go to the OAuth 2.0 Playground. Within Step 1 (Select & authorize APIs), scroll down and click on YouTube Data API v3. Then click on https://www.googleapis.com/auth/youtube.upload. Then click Authorize APIs.

OAuth 2.0 Playground YouTube Data API v3

YouTube Data API v3 YouTube.Upload

You will now be taken to a screen that will inform you Google OAuth 2.0 Playground would like to Manage your YouTube videos. Click Allow.

Google OAuth 2.0 Playground Manage YouTube Videos

Make sure the checkbox is checked for Auto-refresh the token before it expires. Then click Exchange authorization code for tokens.

Exchange Authorization Code for Tokens Auto-Refresh

To the right, below Request / Response, copy the following code and save them to a file called token.txt.

{
"access_token": "bio3.afodsdsdfoidfdfiADFfdaiorgoeediodfdd.D_beQ-o7G2b_B4Q9BaTBNQAT",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "9/faioERi534oigf-H4bw-BER43Abmir4_3Qzj49Hsdi"
}

YouTube OAuth API Access Token

PHP YouTube Video Upload with Google API OAuth 2.0 V3

Uploading videos using Google’s OAuth 2.0 V3 YouTube API is easy. Just follow these steps, and you’ll be uploading videos to YouTube in no time.

Step 1: Make Sure You Have a YouTube Channel

Making sure you have a YouTube channel is the first step of this process. Otherwise, you won’t have a YouTube channel to upload your videos! If you don’t already have a YouTube channel, make one and continue to the next step below.

Step 2: New Google Developers Console Project

Create a new project at Google Developers Console. Click Enable and Manage APIs. Enter in any project name. Select Yes below “I agree that my use of any services and related APIs is subject to my compliance with the applicable Terms of Service.” Click Create.

Enable Manage APIs Google Developers Console

New Project Google Developers Console

Click YouTube Data API. Then click Enable API.

YouTube Data APIs Google OAuth 2.0 V3

Enable YouTube Data API v3

Click Credentials.

Google OAuth 2.0 V3 API Manager Credentials

Click OAuth consent screen. Enter in any value for product name shown to users (keep in mind this will show up to anyone accessing this API). Click Save.

OAuth Consent Screen YouTube Credentials

Click New credentials. Then click OAuth client ID.

New OAuth Client ID YouTube Credentials

Select Web application. Enter in any suitable name. Enter in the full URL of your Authorized redirect URIs. For this tutorial, I’ve used http://www.whitewareweb.com/api.php. Click Create.

YouTube Web Application Authorized Redirect URIs

Now you will be presented with your client ID and client secret. Copy these two values someplace safe for the upcoming steps and then click OK to dismiss the screen.

YouTube API OAuth Client ID Secret

Step 3: Install Composer & Google APIs Client Library for PHP

SSH into your server into the directory where you’ll have your script. For this example, I’m doing it on the root directory. Type in the following command to install composer:

php -r "readfile('https://getcomposer.org/installer');" | php

Then type in this command to install Google APIs Client Library for PHP:

php composer.phar require google/apiclient:^2.0.0@RC

Step 4: Get Access Token & Refresh Token

Create a file called token.php with the following code and upload it into your root directory or whichever directory you are using (make sure to change the values of $OAUTH2_CLIENT_ID and $OAUTH2_CLIENT_SECRET to the values you saved at the beginning of this tutorial):

<?php

require_once 'vendor/autoload.php';

session_start();

/*
 * You can acquire an OAuth 2.0 client ID and client secret from the
 * {{ Google Cloud Console }} <{{ https://cloud.google.com/console }}>
 * For more information about using OAuth 2.0 to access Google APIs, please see:
 * <https://developers.google.com/youtube/v3/guides/authentication>
 * Please ensure that you have enabled the YouTube Data API for your project.
 */
$OAUTH2_CLIENT_ID = '344faiofosfdiiSFdisoiifASFDfdsoi3498dfSD.apps.googleusercontent.com'; // Enter your Client ID here
$OAUTH2_CLIENT_SECRET = 'aoier98_4389AoifioRF4'; // Enter your Client Secret here
$REDIRECT = filter_var('http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'], FILTER_SANITIZE_URL);
$APPNAME = "WhiteWare Web";

$client = new Google_Client();
$client->setClientId($OAUTH2_CLIENT_ID);
$client->setClientSecret($OAUTH2_CLIENT_SECRET);
$client->setScopes('https://www.googleapis.com/auth/youtube');
$client->setRedirectUri($REDIRECT);
$client->setApplicationName($APPNAME);
$client->setAccessType('offline');
$client->setApprovalPrompt('force');
    
// Define an object that will be used to make all API requests.
$youtube = new Google_Service_YouTube($client);

if (isset($_GET['code'])) {
    if (strval($_SESSION['state']) !== strval($_GET['state'])) {
        die('The session state did not match.');
    }

    $client->authenticate($_GET['code']);
    $_SESSION['token'] = $client->getAccessToken();
}

if (isset($_SESSION['token'])) {
    $client->setAccessToken($_SESSION['token']);
    echo "Access Token: " . json_encode($_SESSION['token']);
}

// Check to ensure that the access token was successfully acquired.
if ($client->getAccessToken()) {
    try {
        // Call the channels.list method to retrieve information about the
        // currently authenticated user's channel.
        $channelsResponse = $youtube->channels->listChannels('contentDetails', array('mine' => 'true'));

        $htmlBody = '';
        foreach ($channelsResponse['items'] as $channel) {
            // Extract the unique playlist ID that identifies the list of videos
            // uploaded to the channel, and then call the playlistItems.list method
            // to retrieve that list.
            $uploadsListId = $channel['contentDetails']['relatedPlaylists']['uploads'];

            $playlistItemsResponse = $youtube->playlistItems->listPlaylistItems('snippet', array(
                'playlistId' => $uploadsListId,
                'maxResults' => 50
            ));

            $htmlBody .= "<h3>Videos in list $uploadsListId</h3><ul>";
            foreach ($playlistItemsResponse['items'] as $playlistItem) {
                $htmlBody .= sprintf('<li>%s (%s)</li>', $playlistItem['snippet']['title'],
                    $playlistItem['snippet']['resourceId']['videoId']);
            }
            $htmlBody .= '</ul>';
        }
    } catch (Google_ServiceException $e) {
        $htmlBody .= sprintf('<p>A service error occurred: <code>%s</code></p>',
            htmlspecialchars($e->getMessage()));
    } catch (Google_Exception $e) {
        $htmlBody .= sprintf('<p>An client error occurred: <code>%s</code></p>',
            htmlspecialchars($e->getMessage()));
    }

    $_SESSION['token'] = $client->getAccessToken();
} else {
    $state = mt_rand();
    $client->setState($state);
    $_SESSION['state'] = $state;

    $authUrl = $client->createAuthUrl();
    $htmlBody = <<<END
<h3>Authorization Required</h3>
<p>You need to <a href="$authUrl">authorise access</a> before proceeding.<p>
END;
}
?>
 
<!doctype html>
<html>
<head>
    <title>My Uploads</title>
</head>
<body>
<?php echo $htmlBody;?>
</body>
</html>

My Uploads

Now, navigate to this newly created page in your browser (e.g. http://www.whitewareweb.com/token.php). Make sure you are logged on to your Google/YouTube account and authorize access when prompted. After authorizing access, you will be returned to the token page where your access token will be displayed in JSON format like this:

{"access_token": "bio3.afodsdsdfoidfdfiADFfdaiorgoeediodfdd.D_beQ-o7G2b_B4Q9BaTBNQAT","token_type": "Bearer","expires_in": 3600,"refresh_token": "9/faioERi534oigf-H4bw-BER43Abmir4_3Qzj49Hsdi"}

Copy the JSON code and save it to a file called token.txt.

Step 5: Upload a YouTube Video!

Upload token.txt into your root directory (or whichever directory you are using) and apply permissions of 600 on that file. Then create a file called api.php with the following code and upload it to this same directory (make sure to change the values of $OAUTH2_CLIENT_ID and $OAUTH2_CLIENT_SECRET to the values you saved at the beginning of this tutorial):

<?php

$key = file_get_contents('token.txt');

require_once 'vendor/autoload.php';

$client_id = '344faiofosfdiiSFdisoiifASFDfdsoi3498dfSD.apps.googleusercontent.com'; // Enter your Client ID here
$client_secret = 'aoier98_4389AoifioRF4'; // Enter your Client Secret here

$videoPath = "videos/example.mkv";
$videoTitle = "Just an Example Title";
$videoDescription = "This is the YouTube video's description";
$videoCategory = "22";
$videoTags = array("first tag","second tag","third tag");

try{
    // Client init
    $client = new Google_Client();
    $client->setClientId($client_id);
    $client->setAccessType('offline');
    $client->setApprovalPrompt('force');
    $client->setAccessToken($key);
    $client->setClientSecret($client_secret);

    if ($client->getAccessToken()) {
        /**
         * Check to see if our access token has expired. If so, get a new one and save it to file for future use.
         */
        if($client->isAccessTokenExpired()) {
            $newToken = json_decode($client->getAccessToken());
            $client->refreshToken($newToken->refresh_token);
            file_put_contents($key, $client->getAccessToken());
        }
 
        $youtube = new Google_Service_YouTube($client);
 
        // Create a snipet with title, description, tags and category id
        $snippet = new Google_Service_YouTube_VideoSnippet();
        $snippet->setTitle($videoTitle);
        $snippet->setDescription($videoDescription);
        $snippet->setCategoryId($videoCategory);
        $snippet->setTags($videoTags);
        $snippet->setDefaultLanguage("en");
        $snippet->setDefaultAudioLanguage("en");

        $recordingDetails = new Google_Service_YouTube_VideoRecordingDetails();
        $recordingDetails->setLocationDescription("United States of America");
        $recordingDetails->setRecordingDate("2016-01-20T12:34:00.000Z");
        $locationdetails = new Google_Service_YouTube_GeoPoint();
        $locationdetails->setLatitude("38.8833");
        $locationdetails->setLongitude("77.0167");
        $recordingDetails->setLocation($locationdetails);

        // Create a video status with privacy status. Options are "public", "private" and "unlisted".
        $status = new Google_Service_YouTube_VideoStatus();
        $status->setPrivacyStatus("public");
        $status->setPublicStatsViewable(false);
        $status->setEmbeddable(false); // Google defect still not editable https://code.google.com/p/gdata-issues/issues/detail?id=4861
 
        // Create a YouTube video with snippet and status
        $video = new Google_Service_YouTube_Video();
        $video->setSnippet($snippet);
        $video->setRecordingDetails($recordingDetails);
        $video->setStatus($status);
 
        // Size of each chunk of data in bytes. Setting it higher leads faster upload (less chunks,
        // for reliable connections). Setting it lower leads better recovery (fine-grained chunks)
        $chunkSizeBytes = 1 * 1024 * 1024;

        // Setting the defer flag to true tells the client to return a request which can be called
        // with ->execute(); instead of making the API call immediately.
        $client->setDefer(true);

        // Create a request for the API's videos.insert method to create and upload the video.
        $insertRequest = $youtube->videos->insert("status,snippet,recordingDetails", $video);

        // Create a MediaFileUpload object for resumable uploads.
        $media = new Google_Http_MediaFileUpload(
            $client,
            $insertRequest,
            'video/*',
            null,
            true,
            $chunkSizeBytes
        );
        $media->setFileSize(filesize($videoPath));

        // Read the media file and upload it chunk by chunk.
        $status = false;
        $handle = fopen($videoPath, "rb");
        while (!$status && !feof($handle)) {
            $chunk = fread($handle, $chunkSizeBytes);
            $status = $media->nextChunk($chunk);
        }

        fclose($handle);

        /**
         * Video has successfully been uploaded, now lets perform some cleanup functions for this video
         */
        if ($status->status['uploadStatus'] == 'uploaded') {
            // Actions to perform for a successful upload
        }

        // If you want to make other calls after the file upload, set setDefer back to false
        $client->setDefer(true);

    } else{
        // @TODO Log error
        echo 'Problems creating the client';
    }

} catch(Google_Service_Exception $e) {
    print "Caught Google service Exception ".$e->getCode(). " message is ".$e->getMessage();
    print "Stack trace is ".$e->getTraceAsString();
}catch (Exception $e) {
    print "Caught Google service Exception ".$e->getCode(). " message is ".$e->getMessage();
    print "Stack trace is ".$e->getTraceAsString();
}

?>

Now, navigate to this newly created page in your browser (e.g. http://www.whitewareweb.com/api.php). Make sure you are logged on to your Google/YouTube account and authorize access if prompted. Your video will now be uploaded!

YouTube Video Uploaded via OAuth API

Congratulations on uploading your first YouTube video using the OAuth API!

Below is a list of available YouTube categories along with their corresponding ID’s (not all categories will be available for your channel, but here’s a list for your convenience):

YouTube Category Names & ID’s

Category Name Category ID
Film & Animation 1
Autos & Vehicles 2
Music 10
Pets & Animals 15
Sports 17
Short Movies 18
Travel & Events 19
Gaming 20
Videoblogging 21
People & Blogs 22
Comedy 23
Entertainment 24
News & Politics 25
Howto & Style 26
Education 27
Science & Technology 28
Movies 30
Anime/Animation 31
Action/Adventure 32
Classics 33
Comedy 34
Documentary 35
Drama 36
Family 37
Foreign 38
Horror 39
Sci-Fi/Fantasy 40
Thriller 41
Shorts 42
Shows 43
Trailers 44

Have fun, and please share any interesting things you come across with us below.

Troubleshooting

The session state did not match

In case you get the message, The session state did not match, you may try putting the following code immediately before die(‘The session state did not match.’);:

var_dump($_SESSION['state']);
var_dump($_GET['state']);

Access Token Issues

If you are having issues with your access token, try visiting this link for more clues: https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=[YOUR-ACCESS-TOKEN]

Caught Google service Exception 0

Are you getting this error?

PHP Warning: mkdir(): Permission denied in /../vendor/google/apiclient/src/Google/Cache/File.php on line 158
Caught Google service Exception 0 message is Could not create storage directory: /tmp/google-api-php-client/d4Stack trace is #0 /../vendor/google/apiclient/src/Google/Cache/File.php(146): Google_Cache_File->getCacheDir(”, true)

If so, try this code:
$client = new Google_Client();
$client->setCache(new Google_Cache_File('/path/to/shared/cache'));

Further reading:

Install FFmpeg on Ubuntu Linux Command Line

This quick tutorial will help you install FFmpeg if typing apt-get install ffmpeg via SSH is not installing FFmpeg for you, but instead giving you some message like:

Package ffmpeg is not available, but is referred to by another package. This may mean that the package is missing, has been obsoleted, or is only available from another source

E: Package ‘ffmpeg’ has no installation candidate

Let’s cut to the chase. Just type in these three commands to install FFmpeg on Ubuntu Linux 14.04 (Trusty) via SSH command line:

3-Step FFmpeg Ubuntu Installation Tutorial

  1. add-apt-repository ppa:mc3man/trusty-media
  2. apt-get update && apt-get dist-upgrade
  3. apt-get install ffmpeg

Further reading:

Change PHP memory_limit & PHP.ini Values in Ajenti

Ajenti V’s VPS web control panel has a nice, pretty interface, which attracts many users. It is easy to use, but certain settings may not always be intuitive for everyone. One such setting is changing PHP.ini settings. In this tutorial, we’ll PHP’s memory_limit. Let’s cut to the chase and begin the tutorial!

Step 1: Log in to Ajenti V Control Panel

Using your web browser, log in to your Ajenti V control panel. If you didn’t change the default port number of 8000, then you can log in to Ajenti V by going to https://123.123.123.123:8000 (substitute 123.123.123.123 with your VPS or Dedicated server’s IP address). If you did change Ajenti V’s default port number, then simply substitute 8000 with whatever port number you are using.

Ajenti Login Default Username & Password root admin

Ajenti V Default Dashboard

Step 2: Manage Website Configuration / Settings

Click MANAGE to the right of your newly created website.

Ajenti V Manage New PHP WordPress Website Configuration

Step 3: Content Settings Tab

Click on the Content tab. Select PHP. Then enter in memory_limit = 512M; in the PHP .ini values box. Scroll down and click APPLY CHANGES and then wait a moment for the changes to take effect.

Ajenti V Change PHP.ini Values Settings

Step 4: Reboot Server to Implement Change of PHP.ini Values

Click on the Dashboard. Then click the reboot button to reboot your web server. If you are prompted whether or not you want to reboot, click OK. Wait for your web server to reboot.

Ajenti V Dashboard Reboot Web Server

Install Postfix

When you are prompted to configure Postfix, push Enter.

Postfix Installation Ajenti Ubuntu Linux

Then make sure Internet Site is selected and push Enter.

Postfix Configuration Internet Site Ubuntu

For System mail name, put your server name without the subdomain and push Tab and then push Enter. For example, if your server’s name is john.example.com, put in example.com in this field.

Postfix Configuration System Mail Name

For Root and postmaster mail recipient, enter in the admin’s username. Push Tab and then push Enter.

Postfix Configuration Root and Postmaster Recipient

For Other destinations to accept mail for, ensure something like the following is entered in:

server1.example.com, example.com, localhost.example.com, localhost

Then push Tab and then push Enter.

Postfix Configuration Other Destinations to Accept Mail

For Force synchronous updates on mail queue, select No. Then push Tab and then push Enter.

Postfix Configuration Force Synchronous Updates Mail Queue

For Local networks, you may leave this blank to use the defaults or enter in 127.0.0.0/8. Then push Tab and then push Enter.

Postfix Configuration Local Networks Ubuntu

For Mailbox size limit (bytes), enter in 0, which means no limit. Then push Tab and then push Enter.

Postfix Configuration Mailbox Size Limit Bytes

For Local address extension character, put in a plus sign: +. Then push Tab and then push Enter.

Postfix Configuration Local Address Extension Character

For Internet protocols to use, select all. Then push Tab and then push Enter.

Postfix Configuration Internet Protocols to Use All

Postfix Configuration Finished Setup

You might see a warning like the following:

WARNING: /etc/aliases exists, but does not have a root alias

If so, type in the following:

postconf -e 'home_mailbox = Maildir/'

Then type this:

postconf -e 'mailbox_command ='

Now, we will configure Postfix to do SMTP AUTH using SASL (saslauthd). To do so, type in the following:

postconf -e 'smtpd_sasl_local_domain =' && postconf -e 'smtpd_sasl_auth_enable = yes' && postconf -e 'smtpd_sasl_security_options = noanonymous' && postconf -e 'broken_sasl_auth_clients = yes' && postconf -e 'smtpd_recipient_restrictions = permit_sasl_authenticated,permit_mynetworks,reject_unauth_destination' && postconf -e 'inet_interfaces = all'

Now, we will add two lines to /etc/postfix/sasl/smtpd.conf by typing in the following:

echo -e "pwcheck_method: saslauthd\nmech_list: plain login" >> /etc/postfix/sasl/smtpd.conf

Now, we will generate certificates to be used for TLS encryption and/or certificate Authentication by typing in the following set of commands, one at a time:

touch smtpd.key
chmod 600 smtpd.key
openssl genrsa 1024 > smtpd.key
openssl req -new -key smtpd.key -x509 -days 3650 -out smtpd.crt

When asked for a Country Name, put in the two-letter code for your country (e.g. US). For State or Province Name, enter in your state (e.g. DC). For Locality Name, enter in your city (e.g. Washington). For Organization Name, enter the name of your organization. For Organizational Unit Name, enter in anything. For the Common Name, enter in the domain name you want associated with your server (or your IP address if you don’t have a domain name). For Email Address, enter in the administrator’s email address.

Now type in the following:

openssl req -new -x509 -extensions v3_ca -keyout cakey.pem -out cacert.pem -days 3650

When asked for a PEM pass phrase, enter in a secure password. Then re-enter it when prompted. When asked for a Country Name, put in the two-letter code for your country (e.g. US). For State or Province Name, enter in your state (e.g. DC). For Locality Name, enter in your city (e.g. Washington). For Organization Name, enter the name of your organization. For Organizational Unit Name, enter in anything. For the Common Name, enter in the domain name you want associated with your server (or your IP address if you don’t have a domain name). For Email Address, enter in the administrator’s email address.

Now, enter in the following set of commands:

mv smtpd.key /etc/ssl/private/ && mv smtpd.crt /etc/ssl/certs/ && mv cakey.pem /etc/ssl/private/ && mv cacert.pem /etc/ssl/certs/

Next, enter in the following set of commands to configure Postfix to do TLS encryption for both incoming and outgoing mail:

postconf -e 'smtp_tls_security_level = may' && postconf -e 'smtpd_tls_security_level = may' && postconf -e 'smtpd_tls_auth_only = no' && postconf -e 'smtp_tls_note_starttls_offer = yes' && postconf -e 'smtpd_tls_key_file = /etc/ssl/private/smtpd.key' && postconf -e 'smtpd_tls_cert_file = /etc/ssl/certs/smtpd.crt' && postconf -e 'smtpd_tls_CAfile = /etc/ssl/certs/cacert.pem' && postconf -e 'smtpd_tls_loglevel = 1' && postconf -e 'smtpd_tls_received_header = yes' && postconf -e 'smtpd_tls_session_cache_timeout = 3600s' && postconf -e 'tls_random_source = dev:/dev/urandom' && postconf -e 'myhostname = server1.example.com'

In case you accidentally exit the Postfix configuration too early or do not see the Postfix configuration menu, simply type in the following to re-configure Postfix:

dpkg-reconfigure postfix

Piwik Import Nginx Server Monthly Access Logs

SSH into your server and type the following to import one Nginx (click here for Apache tutorial) access log file into your Piwik tracked website:

python /var/www/domain.com/web/misc/log-analytics/import_logs.py --idsite=1 --url=http://domain.com/piwik /var/log/nginx/websitetotrack.access.log.22.gz

http://domain.com/piwik: The http path of your Piwik installation

You can import different types of files including raw access log files as well as zipped log files.

Further reading:

Piwik Access Logs Analytics Tracking Apache Server

Follow these easy directions to set up Piwik to track the visitors for one of your websites using Apache server’s access log files. This easy to follow tutorial also shows how to import older Apache access log files to ensure you are tracking your previous, current, and future website visitors.

Step 1: Create a New Piwik Website

Create a new Piwik website. If you are already tracking your website with JavaScript tracking, it is important and highly recommended to add a separate Piwik website for log file tracking. Each method (JavaScript tracking and server log files tracking) has its pros and cons (I’ll try to write a different article about that, though), and ideally, you’ll want to use both methods of tracking in order to track your website visitors as comprehensively as possible so you can provide them with the optimum experience.

After logging in to Piwik, click the link for Administration at the top right.

Piwik Access Logs Analytics Tracking Apache Server 1

Then click Websites on the left side.

Piwik Access Logs Analytics Tracking Apache Server 2

Now click Add a new website.

Piwik Access Logs Analytics Tracking Apache Server 3

For the Name, put the name of your website you’d like to track with some kind of indication this is the version you are tracking from the Apache log files (opposed to JavaScript tracking). For example: Website to Track (log files)

For URLs, put the URL of the website: http://websitetotrack.com

Scroll down and click Save.

Piwik Access Logs Analytics Tracking Apache Server 4

Step 2: Import Old Apache Server Monthly Access Logs

Simply SSH into your server and type the following to import one log file into your Piwik tracked website:

python /home/username/public_html/piwik/misc/log-analytics/import_logs.py --idsite=1 --url=http://domain.com/piwik logs/domain.com-Jun-2015.gz

You can import different types of files including raw access log files as well as zipped log files.

Step 3: Set up Piwik to Import Apache Server Access Logs Hourly without Duplicates

Step 3a: Create a File to Store Commands

Create a new file called piwiklogimport.sh. Open it and type in the following:

eval $(awk '{ print "count="$1}' /home/username/public_html/piwik/numberoflines.txt) && python /home/username/public_html/piwik/misc/log-analytics/import_logs.py --token-auth=73952ab983b94872q2368q9ndu2ole6e --idsite=2 --skip=$count --url=http://domain.com/piwik /usr/local/apache/domlogs/username/domain.com && wc /usr/local/apache/domlogs/username/domain.com > /home/username/public_html/piwik/numberoflines.txt

Save it and upload it inside your Piwik directory. Change this file’s permissions to 400.

Cron File Import Piwik Apache Server Access Logs Permissions

Step 3b: Create a File to Track Imports

Create a new file called numberoflines.txt. Open it and type in 0. Save it and upload it inside your Piwik directory. Change this file’s permissions to 600.

Create File Import Piwik Apache Server Access Logs Permissions

Step 3c: Create a Cron Job for Importing Apache Access Logs

Create a new cron job. Set it to run on the 59 minute mark (for every hour) as such:

59 * * * *

For the cron command, use the following:

/bin/sh /home/username/public_html/piwik/domain.com/piwiklogimport.sh >/dev/null 2>&1

Go ahead and save this cron job.

Cron Job Import Piwik Apache Server Access Logs Automatically

Now the Apache access logs should be automatically imported at the 59-minute mark of every hour without importing previously imported lines of the log.

Import Piwik Apache Server Access Logs Automatically

That’s all! You should now have a newly tracked Piwik website that tracks your website visitors according to your Apache access server logs including the full history of everyone that has ever previously visited your website–assuming you haven’t deleted any old Apache access log files. If you have deleted old Apache access log files, then you’ll want to recover those old Apache access log files. You can do this by retrieving them from older backup files (you do regularly back up your server, right?) or perhaps doing some kind of file recovery (this is not a surefire method).

Best VPS Server Backup Strategy Tutorial

This backup method will back up your local VPS databases, files, and configuration settings to another (remote) server of yours. It will also back up your remote server’s files to your local VPS.

Step 1: Install Zip

We must first make sure the zip package is installed. To do so, type in the following via SSH:

dpkg -l zip

If you get something like dpkg-query: no packages found matching zip, then you do not have the zip package installed. However, if you get something that lists the name and version number of the zip package, this means you have the zip package installed.

If you do not have the zip package installed, type the following to install it:

apt-get install zip

When prompted whether or not you want to continue, type Y and then hit Enter.

Step 2: Generate SSH Keys

On your local server, via SSH, type in the following to generate SSH Keys:

ssh-keygen -t rsa -b 4096

When asked to “Enter file in which to save the key”, hit Enter.

When asked to “Enter passphrase (empty for no passphrase)”, hit Enter.

When asked to “Enter same passphrase again”, hit Enter.

Now, type in the following to copy the public key to the remote server using ssh-copy-id:

ssh-copy-id -i ~/.ssh/id_rsa.pub root@123.123.123.123

When asked “Are you sure you want to continue connecting”, type yes and hit Enter.

When prompted for the password of your remote server, type it in and hit Enter.

Now, test to make sure the SSH keys were properly added by trying to log in to the remote server by typing in the following:

ssh root@123.123.123.123

You should be granted access to your remote server without being prompted for a password.

Repeat these same steps on your remote server if you also want to back up your remote server to your local server.

Log on to your other server. Via SSH, type in the following to generate SSH Keys:

ssh-keygen -t rsa -b 4096

When asked to “Enter file in which to save the key”, hit Enter.

When asked to “Enter passphrase (empty for no passphrase)”, hit Enter.

When asked to “Enter same passphrase again”, hit Enter.

Now, type in the following to copy the public key to your other server using ssh-copy-id:

ssh-copy-id -i ~/.ssh/id_rsa.pub root@321.321.321.321

When asked “Are you sure you want to continue connecting”, type yes and hit Enter.

When prompted for the password of your remote server, type it in and hit Enter.

Now, test to make sure the SSH keys were properly added by trying to log in to the remote server by typing in the following:

ssh root@321.321.321.321

You should be granted access to your remote server without being prompted for a password.

Step 3: Create Backup Directory

We must first create a directory which will store the backups. On each of your servers, type in the following to create the directory which will store the backups:

mkdir /var/backups

Step 4: Create Configuration File for MySQL Database Dumps without using Password

On each of your servers, type in the following to create a new file (with restricted permissions) which will allow us to back up all databases without having to enter in a password each time. Substitute yourpassword with the actual password for your root MySQL user.

echo -e '[mysqldump]\npassword=yourpassword' > /etc/custom/.my.cnf && chmod 0440 /etc/custom/.my.cnf

Step 5: Back Up

On each of your servers you’d like to back up, type in the following to create a backup script:

rm -f /var/backups/firstserver.zip && echo "mysqldump --defaults-file=/etc/custom/.my.cnf --user='root' --all-databases --events --ignore-table=mysql.event > /var/backups/databases.sql && crontab -l > /var/backups/crontab && zip -r /var/backups/firstserver.zip /etc/hosts /etc/hostname /etc/apt/sources.list /etc/ajenti /etc/custom /etc/nginx /etc/nginx.custom.d /etc/ssl/private/pure-ftpd.pem /etc/pure-ftpd/conf/TLS /etc/fail2ban/jail.local /etc/network/if-pre-up.d/firewall /etc/sysctl.conf /etc/sudoers.d/my_sudoers /etc/rc.local /etc/mysql/my.cnf /etc/init/mysql.conf /etc/php5/fpm/php.ini /var/www /var/log /var/backups/databases.sql /var/backups/crontab && rm /var/backups/databases.sql && rm /var/backups/crontab && chmod 0440 /var/backups/firstserver.zip && rsync -avz --partial --delete /var/backups/firstserver.zip root@123.123.123.123:/var/backups/firstserver.zip" > /etc/custom/backup.sh

Type the following to apply proper permissions to the backup script file we just created:

chmod 0750 /etc/custom/backup.sh

Now, type in the following to run the backup script:

/etc/custom/backup.sh

Step 6: Enable Automatic Backups

To enable automatic backups every day, we must add our newly created backup script to the crontab. To do so, type in the following:

cat <(crontab -l) <(echo "@daily /etc/custom/backup.sh") | crontab -

Further Reading:

Fix phpList Error: IMAP is not included in your PHP Installation

It is hard to find a newsletter and email marketing software as nice as phpList. If you have installed this wonderful software on your own VPS/Dedicated server, and are getting the phpList error, Error: IMAP is not included in your PHP Installation, continue reading to learn how to easily fix this error.

phpList Process Bounces Error IMAP PHP not Installed

This error means you do not have the IMAP PHP extension installed. To install it, simply SSH into your server and type in the following:

apt-get install php5-imap

When asked if you want to continue, type Y and hit Enter.

Then, type in the following:

php5enmod imap

Now, restart your PHP processor by typing in the following:

service php5-fpm restart

Finally, restart your Nginx web server by typing in the following:

service nginx restart

If you are using an Apache web server, restart it by typing this instead:

service apache2 restart

Import MySQL Database File via Command Line Ubuntu Linux

Importing a MySQL database from the terminal in Linux is very easy. All it takes is one simple line:

mysql -u username -p database_name < myDatabase.sql

Make sure you enter in your MySQL username in place of username. In place of database_name, enter in the name of the database you are importing in to. After you enter this line of code via SSH, you will be prompted for the password of the MySQL user. Go ahead and enter in the password, and your database should get imported.