One place for hosting & domains

      How To Set Up Redis as a Cache for MySQL with PHP on Ubuntu 20.04

      The author selected Girls Who Code to receive a donation as part of the Write for DOnations program.


      Redis (Remote Dictionary Server) is a fast open-source, in-memory database that you can use as a key-value store for a highly scalable and performance-oriented system. Some of Redis’ use cases include: caching, high-speed transactions, real-time analytics, live notifications, machine learning, searching, and queue/job processing. Since Redis is an in-memory key-value store, its performance makes it suitable for caching data in your application.

      Caching is storing data temporarily in a high-speed storage layer (for example, in a computer RAM) to serve data faster when clients make the same future requests. This enhances the re-use of previously computed data instead of fetching it each time from the disk.

      When you’re working with PHP and MySQL, using Redis as a cache improves your application performance because Redis stores data in RAM, which is several times faster than a hard disk (HDD) or a solid-state drive (SSD). Caching also reduces database costs—that is, the number of round trips made to the back-end database—and avoids overloading the backend.

      Caching data is an integral design feature when you’re designing web applications with higher reads than writes. Such applications include blogs, online stores, and social media sites.

      In this tutorial, you’ll use Redis to cache MySQL data with PHP on Ubuntu 20.04.


      To complete this tutorial, you’ll need the following:

      Step 1 — Installing the Redis Library for PHP

      To begin you’ll install the php-redis extension, which will allow you to use PHP to communicate with Redis. Run the following commands to update your server and install the extension:

      • sudo apt update
      • sudo apt install php-redis

      Confirm the installation and restart the Apache web server to load the extension:

      • sudo systemctl restart apache2

      Now that you have installed your dependencies, you’ll set up your database.

      Step 2 — Setting Up a Test Database, Table, and Sample Data

      In this step, you’ll create a MySQL database to store data permanently to disk. You’ll also create some tables and a user account with full privileges to the database.

      First, log in to your MySQL server as a root user:

      Enter the root password of your MySQL server that you set up in the LAMP prerequisite. Then, press ENTER to continue.

      Next, create a test_store database with the following command:

      • CREATE database test_store;

      Make sure the action is successful by confirming the output:


      Query OK, 1 row affected (0.00 sec)

      Next, create a user for your database. We’ll call this user test_user in this tutorial. Replace PASSWORD with a strong password as well:

      • CREATE USER 'test_user'@'localhost' IDENTIFIED WITH mysql_native_password BY 'PASSWORD';

      Then grant test_user full privileges to the test_store database with:

      • GRANT ALL PRIVILEGES ON test_store.* TO 'test_user'@'localhost';

      Finally run the following command to reload the grant tables in MySQL:

      Ensure you get the following output after each successful command:


      Query OK, 0 rows affected (0.01 sec)

      End the MySQL root session:

      You’ll receive the word Bye and the system will take you back to the server’s command line interface.

      Log back in to the MySQL server with the credentials for the test_user that you just created:

      Enter the password for the test_user to proceed. Then, switch to the test_store database when you’re in the mysql> prompt:

      Ensure you receive the following output:


      Database Changed.

      Next, you’ll create a products table with three columns. You’ll use the product_id column to uniquely identify each product. To avoid assigning the IDs manually, you’ll use the AUTO_INCREMENT keyword. Then, you’ll use the BIGINT data type for the product_id column to support a large data set. The BIGINT data type can hold a minimum value of -2^63 and a maximum value of 2^63 - 1.

      The product_name field will hold the actual names of your items. In this case, a VARCHAR data type with a length of 50 characters will be enough. The last column in the products table is the price—you’ll use the DOUBLE data type to accommodate prices with decimals (for example, 16.33).

      To create the products table, run the following command:

      • CREATE table products
      • (
      • product_name VARCHAR(50),
      • price DOUBLE
      • ) Engine = InnoDB;

      You will receive the following output:


      Query OK, 0 rows affected (0.01 sec)

      Now you’ll populate the products table with some records for testing purposes.

      You don’t need to enter data to the product_id column manually since the AUTO_INCREMENT column will complete this. Run the following commands one by one:

      • INSERT INTO products(product_name, price) VALUES ('Virtual Private Servers', '5.00');
      • INSERT INTO products(product_name, price) VALUES ('Managed Databases', '15.00');
      • INSERT INTO products(product_name, price) VALUES ('Block Storage', '10.00');
      • INSERT INTO products(product_name, price) VALUES ('Managed Kubernetes', '60.00');
      • INSERT INTO products(product_name, price) VALUES ('Load Balancer', '10.00');

      After running each command, ensure you get this output:


      Query OK, 1 row affected (0.00 sec)

      Verify the data using the SELECT command:

      You will receive output similar to the following:


      +------------+-------------------------+-------+ | product_id | product_name | price | +------------+-------------------------+-------+ | 1 | Virtual Private Servers | 5 | | 2 | Managed Databases | 15 | | 3 | Block Storage | 10 | | 4 | Managed Kubernetes | 60 | | 5 | Load Balancer | 10 | +------------+-------------------------+-------+ 5 rows in set (0.00 sec)

      End the MySQL session for the test_user:

      Once you’ve set up the test_store database, products table, and test_user, you’ll code a PHP script to retrieve data from the MySQL database and cache it to Redis.

      Step 3 — Designing a PHP Script for Fetching and Caching MySQL Data

      In this step, you’ll create a PHP script for retrieving the sample data that you’ve created in the previous step.

      When you run the script for the first time, it will read the data from MySQL (that is, from disk) and then cache it to Redis. As a result subsequent reads of the products’ data will be from Redis (that is, from system RAM). System memory is multiple times faster than even the fastest solid-state drive, thus data will be retrieved faster from the Redis cache than reading from the system disk.

      Note: While you might not get any performance boost, since you are retrieving just a few records from the MySQL database, several benchmarks prove that retrieving cached data from Redis is several times faster than reading it from MySQL when dealing with several hundred thousand records.

      Create a products.php file in the root directory of your website:

      • sudo nano /var/www/html/products.php

      To start, enter the following information to connect and create an instance of Redis and store it as an object in a $redis variable.

      The address connects to the localhost. You may change this value if you’re running Redis from a remote server. Remember to replace REDIS_PASSWORD with the specific password for Redis set in the /etc/redis/redis.conf configuration file.

      Also, enter the appropriate port number. By default, Redis runs on port 6379:


      $redis = new Redis();
      $redis->connect('', 6379);

      Note: In this guide, the $redis->auth('REDIS_PASSWORD') command sends your password to Redis in plain text. In a production environment, you may consider securing end-to-end communication between Redis and the client server running PHP code with a more powerful access control layer, such as TLS (Transport Layer Security). Also, when configuring your Redis password in the /etc/redis/redis.conf file, make sure you set a long and strong value to prevent brute-force attacks.

      The next step is initializing a PHP variable you’ll use as a key in Redis.

      As mentioned earlier in this guide, Redis acts as a key-value database and therefore you must have a unique key for the data that you intend to store and retrieve from it.

      So, define a PRODUCTS key by adding the following information to the /var/www/html/products.php file. You are free to use any name in place of PRODUCTS key.

      Your PHP script will use this key to cache information to Redis once data gets retrieved from the MySQL database:


      $key = 'PRODUCTS';

      Next, include a conditional PHP if...else statement to check if the PRODUCTS key exists in Redis:


      if (!$redis->get($key)) {
          $source="MySQL Server";
          $database_password = 'PASSWORD';
          $pdo = new PDO('mysql:host=" . $mysql_host . "; dbname=" . $database_name, $database_user, $database_password);
          $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
          $sql  = "SELECT * FROM products";
          $stmt = $pdo->prepare($sql);
          while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
             $products[] = $row;
          $redis->set($key, serialize($products));
          $redis->expire($key, 10);
      } else {
           $source = "Redis Server';
           $products = unserialize($redis->get($key));
      echo $source . ': <br>';

      If the key doesn’t exist in Redis, the script connects to the database that you created earlier, queries the products table, and stores the data in Redis using the $redis->set($key, serialize($products)) command.

      The $redis->expire($key, 10); command sets the expiration to 10 seconds. You may tweak this value depending on your cache policy.

      The $source variable helps you to identify the source of the data once it is echoed as an array at the end of the script using the echo $source and print_r($products) commands.

      Once you’ve put everything together, your /var/www/html/products.php file will be as follows:


      $redis = new Redis();
      $redis->connect('', 6379);
      $key = 'PRODUCTS';
      if (!$redis->get($key)) {
          $source="MySQL Server";
          $database_password = 'PASSWORD';
          $pdo = new PDO('mysql:host=" . $mysql_host . "; dbname=" . $database_name, $database_user, $database_password);
          $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
          $sql  = "SELECT * FROM products";
          $stmt = $pdo->prepare($sql);
          while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
             $products[] = $row;
          $redis->set($key, serialize($products));
          $redis->expire($key, 10);
      } else {
           $source = "Redis Server';
           $products = unserialize($redis->get($key));
      echo $source . ': <br>';

      Save and close the file.

      You’ve now set up a PHP script that will connect to MySQL and cache data to Redis. You’ll test your script in the next step.

      Step 4 — Testing the PHP Script

      To test if Redis is caching data from the MySQL database, you’ll enter the path of the PHP script in a browser window. Remember to replace your_server_IP with the public IP address of your server, like so: http://your_server_IP/products.php.

      When you run the script for the first time, you will receive the following output that displays data from the MySQL database because, at this point, the PHP script has not yet cached any data in Redis:

      MySQL Server
      Array ( [0] => Array ( [product_id] => 1 [product_name] => Virtual Private Servers [price] => 5 ) [1] => Array ( [product_id] => 2 [product_name] => Managed Databases [price] => 15 ) [2] => Array ( [product_id] => 3 [product_name] => Block Storage [price] => 10 ) [3] => Array ( [product_id] => 4 [product_name] => Managed Kubernetes [price] => 60 ) [4] => Array ( [product_id] => 5 [product_name] => Load Balancer [price] => 10 ) )

      Once you run the script again, you’ll get an output confirming that it’s reading data from Redis, which is acting as a cache for MySQL.

      Redis Server
      Array ( [0] => Array ( [product_id] => 1 [product_name] => Virtual Private Servers [price] => 5 ) [1] => Array ( [product_id] => 2 [product_name] => Managed Databases [price] => 15 ) [2] => Array ( [product_id] => 3 [product_name] => Block Storage [price] => 10 ) [3] => Array ( [product_id] => 4 [product_name] => Managed Kubernetes [price] => 60 ) [4] => Array ( [product_id] => 5 [product_name] => Load Balancer [price] => 10 ) )

      Remember that the key will expire after 10 seconds and data will again be retrieved from MySQL.


      In this guide, you’ve used Redis to cache MySQL data with PHP on Ubuntu 20.04. You may use the coding in this guide to set up a caching mechanism for your MySQL data, which is especially useful for high-traffic web applications.

      You can check out our Redis topic page for more educational resources. Or, learn more about coding in PHP with further tutorials and content on the PHP topic page.

      Source link

      How To Set Up Multi-Factor Authentication for SSH on CentOS 8

      Not using CentOS 8?

      Choose a different version or distribution.

      The author selected the COVID-19 Relief Fund to receive a donation as part of the Write for DOnations program.


      SSH uses passwords for authentication by default, and most SSH hardening instructions recommend using an SSH key instead. However, an SSH key is still only a single factor, though a much more secure factor. The channel is the terminal on your computer sending the data via an encrypted tunnel to the remote machine. But like a hacker can guess a password, they can steal an SSH key, and then in either case, with that single piece of data, an attacker can gain access to your remote systems.

      In this tutorial, we’ll set up multi-factor authentication to combat that. Multi-factor authentication (MFA) or Two-factor authentication (2FA) requires more than one factor to authenticate or log in. This means a bad actor would have to compromise multiple things, like your computer and your phone, to get in. There are several types of factors used in authentication:

      1. Something you know, like a password or security question
      2. Something you have, like an authenticator app or security token
      3. Something you are, like your fingerprint or voice

      One common factor is an OATH-TOTP app, like Google Authenticator. OATH-TOTP (Open Authentication Time-Based One-Time Password) is an open protocol that generates a one-time use password, commonly a six-digit number recycled every 30 seconds.

      This article will go over how to enable SSH authentication using an OATH-TOTP app in addition to an SSH key. Logging into your server via SSH will require two factors across two channels, thereby making it more secure than a password or SSH key alone. Also, we’ll go over some additional use cases for MFA and some helpful tips and tricks.

      And if you are seeking further guidance on securing SSH connections, check out these tutorials on Hardening OpenSSH and Hardening OpenSSH Client.


      To follow this tutorial, you will need:

      • One CentOS 8 server with a sudo non-root user and SSH key, which you can set up by following this Initial Server Setup tutorial.
      • A smartphone or tablet with an OATH-TOTP app installed, like Google Authenticator (iOS, Android).
      • Alternatively, you can also use a Linux command line app called ‘oathtool’ to generate an OATH-TOTP code. It’s available in various distribution repos
      • If you really want secure your SSH connection there are several good steps outlined in this SSH Essentials article, such as whitelisting users, disabling root login, and changing which port SSH uses.

      Step 1 — Installing Google’s PAM

      In this step, we’ll install and configure Google’s PAM.

      PAM, which stands for Pluggable Authentication Module, is an authentication infrastructure used on Linux systems to authenticate a user. Because Google made an OATH-TOTP app, they also made a PAM that generates TOTPs and is fully compatible with any OATH-TOTP app, like Google Authenticator or Authy.

      First, add the EPEL (Extra Packages for Enterprise Linux) repo:

      If your repositories have the EPEL install package, you will see the following output:


      ===== Name Matched: epel ===== epel-release.noarch : Extra Packages for Enterprise Linux repository configuration

      Now install the epel-release package to enable the EPEL repository:

      • sudo yum install epel-release

      However, if you don’t have the package epel-release, then you can install the repository information manually:

      • sudo yum install

      Next, install the PAM. You might be prompted to accept the EPEL key if this is the first time using the repo. Once accepted, you won’t be prompted for again to accept the key:

      • sudo yum install google-authenticator qrencode-libs

      With the PAM installed, we’ll use a helper app that comes with the PAM to generate a TOTP key for the user you want to add a second factor to. This key is generated on a user-by-user basis, not system-wide. This means every user that wants to use a TOTP auth app will need to log in and run the helper app to get their own key; you can’t just run it once to enable it for everyone (but there are some tips at the end of this tutorial to set up or require MFA for many users).

      Run these two commands to initialize the app:

      • google-authenticator -s ~/.ssh/google_authenticator

      Normally, all you need to do is run the google-authenticator command with no arguments, but SELinux doesn’t allow the ssh daemon to write to files outside of the .ssh directory in your home folder. This prevents authentication.

      SELinux is a powerful tool that protects your system from potential attacks, and it’s worth running in Enforcing mode. As such, turning off SELinux is not considered a best practice. Instead, we’ll move the default location of the google_authenticator file into your ~/.ssh directory.

      After you run the command, you’ll be asked a few questions. The first one asks if authentication tokens should be time-based:


      Do you want authentication tokens to be time-based (y/n) y

      This PAM allows for time-based or sequential-based tokens. Using sequential-based tokens mean the code starts at a certain point and then increments the code after every use. Using time-based tokens mean the code changes after a certain time frame. We’ll stick with time-based because that is what apps like Google Authenticator anticipate, so answer y for yes.

      After answering this question, a lot of output will scroll past, including a large QR code. Use your authenticator app on your phone to scan the QR code or manually type in the secret key. If the QR code is too big to scan, you can use the URL above the QR code to get a smaller version. Once it’s added, you’ll see a six-digit code that changes every 30 seconds in your app.

      Note: Make sure you record the secret key, verification code, and the emergency scratch codes in a safe place, like a password manager. The emergency scratch codes are the only way to regain access if you, for example, lose access to your TOTP app.

      The remaining questions inform the PAM on how to function. We’ll go through them one by one:


      Do you want me to update your "~/.google_authenticator" file (y/n) y

      This writes the key and options to the google_authenticator file. If you say no, the program quits and nothing is written, which means the authenticator won’t work:


      Do you want to disallow multiple uses of the same authentication token? This restricts you to one login about every 30s, but it increases your chances to notice or even prevent man-in-the-middle attacks (y/n) y

      By answering yes here, you are preventing a replay attack by making each code expire immediately after use. This prevents an attacker from capturing a code you just used and logging in with it:


      By default, a new token is generated every 30 seconds by the mobile app. In order to compensate for possible time-skew between the client and the server, we allow an extra token before and after the current time. This allows for a time skew of up to 30 seconds between authentication server and client. If you experience problems with poor time synchronization, you can increase the window from its default size of 3 permitted codes (one previous code, the current code, the next code) to 17 permitted codes (the 8 previous codes, the current code, and the 8 next codes). This will permit for a time skew of up to 4 minutes between client and server. Do you want to do so? (y/n) n

      Answering yes here allows up to 17 valid codes in a moving four minute window. By answering no, you limit it to 3 valid codes in a 1:30 minute rolling window. Unless you find issues with the 1:30 minute window, answering no is the more secure choice. If you answer no and later realize you need more time, this setting can be adjusted in the .google_authenticator file stored at the root of your home directory:


      If the computer that you are logging into isn't hardened against brute-force login attempts, you can enable rate-limiting for the authentication module. By default, this limits attackers to no more than 3 login attempts every 30s. Do you want to enable rate-limiting (y/n) y

      Rate limiting means a remote attacker can only attempt a certain number of guesses before being forced to wait some time before being able to try again. If you haven’t previously configured rate limiting directly into SSH, doing so now is a great hardening technique.

      Once you finish this setup, if you want to back up your secret key, you can copy the ~/.ssh/google-authenticator file to a trusted location. From there, you can deploy it on additional systems or redeploy it after a clean install. Be aware that by using the same key on multiple machines you are introducing the possibility of a replay attack if an attacker is able to sniff the token for one server then use it, within the valid window, against a different server. You must evaluate the likelihood of that risk versus having every system use a different token and managing those different tokens.

      Note: If you are using an encrypted home folder, which is beyond the scope of this article, you may need to store the ~./google-authenticator file in a directory outside of your home folder. The project README has details on how to do that.

      Since we stored the config file in a non-standard location, we need to restore the SELinux context based on its new location.

      Use the following command to do so:

      With those two changes done we now have the Google Authenticator PAM installed and configured, the next step is to configure SSH to use your TOTP key. We’ll need to tell SSH about the PAM and then configure SSH to use it.

      Step 2 — Configuring OpenSSH to Use MFA/2FA

      Because we’ll be making SSH changes over SSH, it’s important to never close your initial SSH connection. Instead, open a second SSH session to do testing. This is to avoid locking yourself out of your server if there was a mistake in your SSH configuration. Once everything works, then you can safely close any sessions. Another safety precaution is to create a backup of the system files you will be editing so in case something goes wrong you can simply revert to the vanilla file and start over again with a clean configuration.

      To begin, back up the sshd configuration file and then edit it. Here, we’re using nano, which isn’t installed on CentOS by default. You can install it with sudo yum install nano, or use your favorite alternative text editor.

      Backup the file and then open it:

      • sudo cp /etc/pam.d/sshd /etc/pam.d/sshd.bak
      • sudo nano /etc/pam.d/sshd

      Add the following line to the end of the file:


      auth       required secret=/home/${USER}/.ssh/google_authenticator nullok
      auth       required

      Since we had to put the google_authenticator config file in a non-standard location, we have to provide PAM with the path to the config file. The secret option tells PAM where the non-default location of the config file is stored.

      The nullok word at the end of the line tells the PAM that this authentication method is optional. This allows users without a OATH-TOTP token to still log in just using their SSH key. Once all users have an OATH-TOTP token, you can remove nullok from this line to make MFA mandatory.

      The second line with is required to allow authentication if I user doesn’t use an MFA token to login. When logging in each method needs a SUCCESS to allow authentication. If a user doesn’t use the MFA auth tool by utilizing the nullok option that returns an IGNORE for the interactive keyboard authentication. So if that line is ignored then the next line triggers which returns SUCCESS and allows authentication to proceed.

      Save and close the file.

      Next, we’ll configure SSH to support this kind of authentication.

      Back up the the SSH configuration file then open it for editing:

      • sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
      • sudo nano /etc/ssh/sshd_config

      Look for lines beginning ChallengeResponseAuthentication. Comment out the no line and uncomment the yes line.

      You file will look like this:


      . . .
      # Change to no to disable s/key passwords
      ChallengeResponseAuthentication yes
      #ChallengeResponseAuthentication no
      . . .

      Save and close the file and then restart SSH to reload the configuration files. Restarting the sshd service won’t close our current open connections, so you won’t risk locking yourself out with this command:

      • sudo systemctl restart sshd.service

      To test that everything’s working so far, open ANOTHER terminal window and try logging in over SSH. It is very important that you keep your current SSH session open and test with an additional session or you will lock yourself out at some point and will need to use the web console to get yourself back in.

      Note: If you’ve previously created an SSH key and are using it, you’ll notice you didn’t have to type in your user’s password or the MFA verification code. This is because an SSH key overrides all other authentication options by default. Otherwise, you should have gotten a password and verification code prompt.

      Next, to enable an SSH key as one factor and the verification code as a second, we need to tell SSH which factors to use and prevent the SSH key from overriding all other types.

      Step 3 — Making SSH Aware of MFA

      Reopen the sshd configuration file:

      • sudo nano /etc/ssh/sshd_config

      Add the following line at the bottom of the file. This tells SSH which authentication methods are required. This line tells SSH we need a SSH key and either a password or a verification code (or all three):


      . . .
      AuthenticationMethods publickey,password publickey,keyboard-interactive

      Save and close the file.

      Next, open the PAM sshd configuration file again:

      • sudo nano /etc/pam.d/sshd

      Find the line auth substack password-auth towards the top of the file. Comment it out by adding a # character as the first character on the line. This tells PAM not to prompt for a password:


      . . .
      #auth       substack     password-auth
      . . .

      Save and close the file, then restart SSH:

      • sudo systemctl restart sshd.service

      Now try logging into the server again with a different terminal session/window. Unlike last time, SSH should ask for your verification code. Upon entering it, you’ll be logged in. Even though you don’t see any indication that your SSH key was used, your login attempt used two factors. If you want to verify, you can add -v (for verbose) after the SSH command:

      Example SSH Output

      . . . debug1: Authentications that can continue: publickey debug1: Next authentication method: publickey debug1: Offering RSA public key: /Users/sammy/.ssh/id_rsa debug1: Server accepts key: pkalg ssh-rsa blen 279 Authenticated with partial success. debug1: Authentications that can continue: keyboard-interactive debug1: Next authentication method: keyboard-interactive Verification code:

      Towards the end of the output, you’ll see where SSH uses your SSH key and then asks for the verification code. You can now log in over SSH with a SSH key and a one-time password. If you want to enforce all three authentication types, you can follow the next step.

      You have now successfully added a second factor when logging in remotely to your server over SSH. If this is what you wanted — to use your SSH key and a TOTP token to enable MFA for SSH (for most people, this is the optimal configuration) — then you’re done.

      What follows are some tips and tricks for recovery, automated usage, and more.

      Step 4 — Adding a Third Factor (Optional)

      In Step 3, we listed the approved types of authentication in the sshd_config file:

      1. publickey (SSH key)
      2. password publickey (password)
      3. keyboard-interactive (verification code)

      Although we listed three different factors, with the options we’ve chosen so far, they only allow for an SSH key and the verification code. If you’d like to have all three factors (SSH key, password, and verification code), one quick change will enable all three.

      Open the PAM sshd configuration file:

      • sudo nano /etc/pam.d/sshd

      Locate the line you commented out previously, #auth substack password-auth, and uncomment the line by removing the # character. Save and close the file. Now once again, restart SSH:

      • sudo systemctl restart sshd.service

      By enabling the option auth substack password-auth, PAM will now prompt for a password in addition the checking for an SSH key and asking for a verification code, which we had working previously. Now we can use something we know (password) and two different types of things we have (SSH key and verification code) over two different channels (your computer for the SSH key and your phone for the TOTP token).

      Step 5 — Recovering Access to Google MFA (optional)

      As with any system that you harden and secure, you become responsible for managing that security. In this case, that means not losing your SSH key or your TOTP secret key and making sure you have access to your TOTP app. However, sometimes things happen, and you can lose control of the keys or apps you need to get in.

      Losing Access to the Secret Key

      If you lose your TOTP secret key, recovery can be broken up into a couple of steps. The first is getting back in without knowing the verification code and the second is finding the secret key or regenerating it for normal MFA login. This often can happen if you get a new phone and don’t transfer over your secrets to a new authenticator app.

      To get in after losing the TOTP secret key on a DigitalOcean Droplet, you can simply use the virtual console from your dashboard to log in using your username and password. This works because we only protected your user account with MFA for ssh connections. Non-ssh connections, such as a console login, doesn’t use the Google Authenticator PAM module.

      If you’re on a non-Droplet system then you have two options for regaining access:

      1. Console (local/non-ssh) access to the system (typically physical or via something like iDrac)
      2. Have a different user that doesn’t have MFA enabled

      The second option is the less secure option, since the point in using MFA is to harden all ssh connections, but it’s one fail safe if you lose access to your MFA authenticator app.

      Once you’re logged in, there are two ways to get the TOTP secret:

      1. Recover the existing key
      2. Generate a new key

      In each user’s home directory, the secret key and Google Authenticator settings are saved in the file ~/.ssh/google-authenticator. The very first line of this file is a secret key. A quick way to get the key is to execute the following command, which displays the first line of the google-authenticator file (i.e. the secret key). Then, take that secret key and manually type it into a TOTP app:

      • head -n 1 /home/sammy/.ssh/google_authenticator

      Once you’ve recovered your existing key, you can either manually type it into your authenticator app and then you should be back in business or you can fill in the relevant details in the URL below and have Google generate a QR code for you to scan. You’ll need to add your username, hostname, the secret key from the google-authenticator file, and then any name of your choosing for 'entry-name-in-auth-app’ to easily identify this key versus a different TOTP token:|0&cht=qr&chl=otpauth://totp/username@hostname%3Fsecret%3D16-char-secret%26issuer%3Dentry-name-in-auth-app

      If there is a reason not to use the existing key (for example, being unable to easily share the secret key with the impacted user securely), you can remove the ~/.ssh/google-authenticator file outright. This will allow the user to log in again using only a single factor, assuming you haven’t enforced MFA by removing the nullok option in the ’/etc/pam.d/sshd’ file. They can then run google-authenticator to generate a new key.

      Losing Access to the TOTP App

      If you need to log in to your server but don’t have access to your TOTP app to get your verification code, you can still log in using the recovery codes that were displayed when you first created your secret key. Note that these recovery codes are one-time use. Once one is used to log in, it cannot be used as a verification code again. Hopefully you saved them in a place that is accessible if you don’t have your TOTP app and yet still secure.

      Step 6 — Changing Authentication Settings (optional)

      If you want to change your MFA settings after the initial configuration, instead of generating a new configuration with the updated settings, you can just edit the ~/.ssh/google-authenticator file. This file is laid out in the following manner:

      .google-authenticator layout

      <secret key>
      <recovery codes>

      Options that are set in this file have a line in the options section; if you answered “no” to a particular option during the initial setup, the corresponding line is excluded from the file. In other words, the file only contains enabled options. If an option isn’t present it is by default disabled.

      Here are the changes you can make to this file:

      • To enable sequential codes instead of time based codes, change the line " TOTP_AUTH to " HOTP_COUNTER 1.
      • To allow multiple uses of a single code, remove the line " DISALLOW_REUSE.
      • To extend the code expiration window to 4 minutes, add the line " WINDOW_SIZE 17.
      • To disable multiple failed logins (rate limiting), remove the line " RATE_LIMIT 3 30.
      • To change the threshold of rate limiting, find the line " RATE_LIMIT 3 30 and adjust the numbers. The 3 in the original indicates the number of attempts over a period of time, and the 30 indicates the period of time in seconds.
      • To disable the use of recovery codes, remove the five 8 digit codes at bottom of the file.

      Step 7 — Avoiding MFA for Some Accounts (optional)

      There may be a situation in which a single user or a few service accounts (i.e. accounts used by applications, not humans) need SSH access without MFA enabled. For example, some applications that use SSH, like some FTP clients, may not support MFA. If an application doesn’t have a way to request the verification code, the request may get stuck until the SSH connection times out.

      As long as a couple of options in /etc/pam.d/sshd are set correctly, you can control which factors are used on a user-by-user basis.

      To allow MFA for some accounts and SSH key only for others, make sure the following settings in /etc/pam.d/sshd are active:


      auth       required
      #auth       substack     password-auth
      . . .
      # Used with polkit to reauthorize users in remote sessions
      -session   optional prepare
      auth       required nullok

      Here, auth substack password-auth is commented out because passwords need to be disabled. MFA cannot be forced if some accounts are meant to have MFA disabled, so leave the nullok option on the final line.

      After setting this configuration, simply run google-authenticator as any users that need MFA, and don’t run it for users where only SSH keys will be used.

      Step 8 — Automating Setup with Configuration Management (optional)

      Many system administrators use configuration management tools, like Puppet, Chef, or Ansible, to manage their systems. If you want to use a system like this to install set up a secret key when a new user’s account is created, there is a method to do that.

      google-authenticator supports command line switches to set all the options in a single, non-interactive command. To see all the options, you can type google-authenticator --help. Below is the command that would set everything up as outlined in Step 1:

      • google-authenticator -t -d -f -r 3 -R 30 -w 3 -s ~/.ssh/google_authenticator

      The options referenced above are as follows:

      • -t => Time based counter
      • -d => Disallow token reuse
      • -f => Force writing the settings to file without prompting the user
      • -r => How many attempts to enter the correct code
      • -R => How long in seconds a user can attempt to enter the correct code
      • -w => How many codes can are valid at a time (this references the 1:30 min - 4 min window of valid codes)
      • -s => Path to where the authentication file should be stored

      These answers all the questions we answered manually, saves it to a file, and then outputs the secret key, QR code, and recovery codes. (If you add the flag -q, then there won’t be any output.) If you do use this command in an automated fashion, make sure to capture the secret key and/or recovery codes and make them available to the user. Also remember to have your automation reset the SELinux context of the ’.ssh’ directory (restorecon -Rv ~/.ssh/).

      Step 9 — Forcing MFA for All Users (optional)

      If you want to force MFA for all users even on the first login, or if you would prefer not to rely on your users to generate their own keys, there’s an easy way to handle this. You can simply use the same google-authenticator file for each user, as there’s no user-specific data stored in the file.

      To do this, after the configuration file is initially created, a privileged user needs to copy the file to the .ssh directory of every home directory and change its permissions to the appropriate user. You can also copy the file to /etc/skel/ so it’s automatically copied over to a new user’s home directory upon creation.

      Warning: This can be a security risk because everyone is sharing the same second factor. This means that if it’s leaked, it’s as if every user had only one factor. Take this into consideration if you want to use this approach.

      Another method to force the creation of a user’s secret key is to use a bash script that:

      1. Creates a TOTP token,
      2. Prompts them to download the Google Authenticator app and scan the QR code that will be displayed, and
      3. Runs the google-authenticator application for them after checking if the google-authenticator file already exists.

      To make sure the script runs when a user logs in, you can name it .bash_login and place it at the root of their home directory.


      In this tutorial, you added two factors (an SSH key + MFA token) across two channels (your computer + your phone) to your server. You’ve made it very difficult for an outside agent to brute force their way into your machine via SSH and greatly increased the security of your machine.

      And remember, if you are seeking further guidance on securing SSH connections, check out these tutorials on Hardening OpenSSH and Hardening OpenSSH Client.

      Source link

      How To Set Up an Ubuntu 20.04 Server on a DigitalOcean Droplet


      In this guide, you will create an Ubuntu 20.04 server through DigitalOcean’s administrative panel and configure it to work with your SSH keys. Once you have your server set up, you can use it to deploy apps and websites.

      This tutorial is part of the Introduction to the Cloud Curriculum, which guides users through all the steps of securely deploying an application to the cloud. If you are searching for general documentation on DigitalOcean Droplets, please visit our product documentation How to Create a Droplet from the DigitalOcean Control Panel.


      Before you begin this guide, you’ll need the following:

      • Some familiarity with the command line. If you’d like an introduction or refresher to the command line, you can visit our Linux Command Line Primer (coming soon).
      • SSH keys to enable a secure connection with your server. To set up SSH keys via the command line, you can follow our guide How to Set Up SSH Keys on Ubuntu 20.04.
      • A credit card or PayPal account to set up a DigitalOcean Droplet. Note that the smallest Droplet offering can be used for this tutorial, whose monthly subscription fee is available on our Pricing page. Users can cancel their Droplet service at any time.

      Note: Eligible students can sign up to receive $50 in free credits for Digital Ocean through the GitHub Student Developer Pack.

      Step 1 — Creating a DigitalOcean account

      To access the DigitalOcean Control Panel and create a Droplet, you need a DigitalOcean account. To create a new account, navigate to the DigitalOcean new account registration page. You can choose to register through email, Google, or GitHub.

      After you’ve confirmed your account, you will need to enter your credit card or Paypal information. This information is collected to verify identity and keep spammers out. You will not be charged until you choose a plan and confirm your subscription, which we will cover in Step 4. You may see a temporary pre-authorization charge to verify the card, which will be reversed within a week.

      Once your information has been accepted, you will be taken to a window that says “Registration Complete”. You are now ready to proceed to the next step.

      Step 2 — Setting Up Your Droplet

      In the previous step, you should have been taken to a window that says “Registration Complete” with a “Let’s make something” button. Click on the “Let’s make something” button. The next window will display buttons for different Droplet options. Click on the “Go to Control Panel” link at the bottom:

      Webpage displaying Droplet options

      Once you click on the “Go to Control Panel” link, you will be taken to the control panel:

      Digital Ocean Cloud Control Panel

      Navigate to the “Create” menu in the upper right corner and click “Droplets” to open the Droplet create page. If you don’t have any Droplets, the Resources tab displays a large, blue “Get Started with a Droplet” button, which takes you to the same Droplet create page.

      The Droplet create page is where you choose your Droplet’s configuration, like its operating system, how much memory it has, and which features (like backups or monitoring) to enable.

      In the next step, you will choose an image of the operating system to be installed on your Droplet.

      Step 3 — Choosing an Image

      An image is a copy of an operating system. To create a Droplet, users need to pick an image of an operating system to run their server. DigitalOcean offers five different Linux operating system distributions. As this tutorial is for setting up an Ubuntu 20.04, click on the option for Ubuntu 20.04 (LTS) x 64:

      Options of images for Droplets

      After selecting your operating system, you are ready to proceed to the next step.

      Step 4 — Choosing a Plan

      In the Choose a plan section, you can choose the amount of RAM, storage space, and CPU cores your Droplet will have. If you are following this tutorial for the Introduction to the Cloud Curriculum, the Basic $5 per month plan will work for the Curriculum’s hands-on tutorials and exercises.

      Click on the option for the Basic $5/mo plan:

      Choose a plan secton

      After selecting a plan, you are ready to proceed to the next step.

      Step 5 — Adding Block Storage (Optional)

      This option allows users to add block storage as independent volumes that can be moved from one Droplet to another within the same region. Block storage is useful when you need additional file storage space for your Droplet. If you are following this tutorial for the Introduction to the Cloud Curriculum, you do not need to add block storage. Leave this option unselected unless you want to add block storage.

      You are now ready to proceed to the next step.

      Step 6 — Choosing a Datacenter Region

      In the Choose a datacenter region section, select the region where you want to create your Droplet.

      A good default will be preselected for you, but for the best performance and minimal latency, choose the datacenter nearest to you and your users.

      Datacenter region selections

      Once you have selected your datacenter, you are ready to proceed to the next step.

      Step 7 — Selecting Additional Options

      In the Select additional options section, you can enable several optional services that add functionality to your Droplet:

      Select additional options

      The three features available in this section are free, so enabling them does not increase the Droplet’s monthly cost. They can be understood as follows:

      IPv6 enables IPv6 access for your Droplet. IPv6 is the most recent version of the Internet Protocol, which identifies computers on networks and routes traffic across the Internet. IPv6 addresses provide more address space than their IPv4 counterparts, and are part of an effort to sustain the growth and deployment of Internet-ready devices.

      User data is arbitrary data that you specify which is written to the user-data field of the DigitalOcean metadata service. To learn more about the purpose of user data, you can visit the User Data product documentation.

      Monitoring adds the DigitalOcean agent to collect extended metrics and create alert policies. To learn more about monitoring, you can visit the Monitoring product documentation.

      You can leave these options blank unless you’d like to enable them. Once you’ve selected your desired options, you are ready to proceed to the next step.

      Step 8 — Setting Up SSH Authentication

      In this section, you will set up SSH authentication for your Droplet, using the pair of SSH keys you created as one of the prerequisites for this tutorial. If you did not already create SSH keys, there will be an opportunity to create them in just a few moments.

      Click on the option to use SSH keys for authentication, which is more secure than a password. Then click on the “New SSH Key” button:

      Authentication section of Droplet set up

      A pop up window will appear prompting you to copy your public SSH key and paste it in the provided space:

      Pop-up window for SSH key

      Note: If you have not created SSH keys, follow the directions on the right side of the pop-up window to create the keys or follow our guide How to Set Up SSH Keys on Ubuntu 20.04.

      To copy your public key, run the following command in your terminal:

      Copy the output from your terminal and paste it into the space provided by the cloud panel pop-up window. Then give your key a name so you can select it later on. When you have finished, click “Add new SSH key”. You will then return to the cloud panel where you can make sure your new key is selected.

      When you have selected your new key, you are ready to proceed to the next step.

      Step 9 — Finalizing and Creating Droplet

      In this final section of the Droplet creation process, you have the option to:

      • Select the number of Droplets you wish to create. If you are following this tutorial as part of the Introduction to the Cloud Curriculum, you need to only create one Droplet. Otherwise, select your desired amount of Droplets.
      • Name the Droplet. You can use the automatically-generated name or create your own name.
      • Add tags to help organize your Droplets. You can leave this option blank if you wish.
      • Assign your Droplet to a project to help with organization. A default folder will be created and selected here. You can create new folders later if you wish.
      • Add backups. This option enables a system-level backup of your Droplet to help prevent data loss. Note that choosing this option adds $1 to your cost per month. Choose this option if you wish.

      Finalizing and Creating Droplet <br>

      When you are finished making your choices, click “Create Droplet.” You will then be taken to a page showing a progress bar for the Droplet creation process. When the Droplet is ready, its IP address will be displayed:

      Droplet page

      You will use this IP address to securely connect with the Droplet through your terminal. Copy the IP address and then run the following command in your terminal to securely connect with your Droplet via SSH as a root user.

      The terminal will then display a message like this:


      The authenticity of host ' (' can't be established. ECDSA key fingerprint is SHA256:+Mx4ID5k4N8H7R24y+APZAoTe69hmAh9qMawyf/Lq9U. Are you sure you want to continue connecting (yes/no/[fingerprint])?

      Type yes. If you chose a passphrase when setting up SSH, you will be prompted to enter it here. If everything is working, you will then be logged into your Droplet as a root user. Note that it is strongly recommended to create a new user with lesser privileges for day-to-day use of your Droplet to avoid making irreparable changes. To create a new user, you can follow our Initial Server Setup guide, which is the next tutorial in the Introduction to the Cloud Curriculum.


      In this tutorial, you have set up an Ubuntu 20.04 server on a Droplet and enabled SSH access. To learn more about what you can do with this Droplet, you can visit our Introduction to the Cloud Curriculum.

      If you wish to delete your Droplet, you can visit our product documentation on How To Destroy a Droplet. To cancel your account, please follow the instructions on our Account Cancellation page.

      Source link