One place for hosting & domains


      How to Use a Remote Docker Server to Speed Up Your Workflow


      Building CPU-intensive images and binaries is a very slow and time-consuming process that can turn your laptop into a space heater at times. Pushing Docker images on a slow connection takes a long time, too. Luckily, there’s an easy fix for these issues. Docker lets you offload all those tasks to a remote server so your local machine doesn’t have to do that hard work.

      This feature was introduced in Docker 18.09. It brings support for connecting to a Docker host remotely via SSH. It requires very little configuration on the client, and only needs a regular Docker server without any special config running on a remote machine. Prior to Docker 18.09, you had to use Docker Machine to create a remote Docker server and then configure the local Docker environment to use it. This new method removes that additional complexity.

      In this tutorial, you’ll create a Droplet to host the remote Docker server and configure the docker command on your local machine to use it.


      To follow this tutorial, you’ll need:

      • A DigitalOcean account. You can create an account if you don’t have one already.
      • Docker installed on your local machine or development server. If you are working with Ubuntu 18.04, follow Steps 1 and 2 of How To Install and Use Docker on Ubuntu 18.04; otherwise, follow the official documentation for information about installing on other operating systems. Be sure to add your non-root user to the docker group, as described in Step 2 of the linked tutorial.

      Step 1 – Creating the Docker Host

      To get started, spin up a Droplet with a decent amount of processing power. The CPU Optimized plans are perfect for this purpose, but Standard ones work just as well. If you will be compiling resource-intensive programs, the CPU Optimized plans provide dedicated CPU cores which allow for faster builds. Otherwise, the Standard plans offer a more balanced CPU to RAM ratio.

      The Docker One-click image takes care of all of the setup for us. Follow this link to create a 16GB/8vCPU CPU-Optimized Droplet with Docker from the control panel.

      Alternatively, you can use doctl to create the Droplet from your local command line. To install it, follow the instructions in the doctl README file on GitHub.

      The following command creates a new 16GB/8vCPU CPU-Optimized Droplet in the FRA1 region based on the Docker One-click image:

      • doctl compute droplet create docker-host
      • --image docker-18-04
      • --region fra1
      • --size c-8
      • --wait
      • --ssh-keys $(doctl compute ssh-key list --format ID --no-header | sed 's/$/,/' | tr -d 'n' | sed 's/,$//')

      The doctl command uses the ssh-keys value to specify which SSH keys it should apply to your new Droplet. We use a subshell to call doctl compute ssh-key-list to retrieve the SSH keys associated with your DigitalOcean account, and then parse the results using the sed and tr commands to format the data in the correct format. This command includes all of your account’s SSH keys, but you can replace the highlighted subcommand with the fingerprint of any key you have in your account.

      Once the Droplet is created you’ll see its IP address among other details:


      ID Name Public IPv4 Private IPv4 Public IPv6 Memory VCPUs Disk Region Image Status Tags Features Volumes 148681562 docker-host your_server_ip 16384 8 100 fra1 Ubuntu Docker 5:18.09.6~3 on 18.04 active

      You can learn more about using the doctl command in the tutorial How To Use doctl, the Official DigitalOcean Command-Line Client.

      When the Droplet is created, you’ll have a ready to use Docker server. For security purposes, create a Linux user to use instead of root.

      First, connect to the Droplet with SSH as the root user:

      Once connected, add a new user. This command adds one named sammy:

      Then add the user to the docker group to give it permission to run commands on the Docker host.

      • sudo usermod -aG docker sammy

      Finally, exit from the remote server by typing exit.

      Now that the server is ready, let's configure the local docker command to use it.

      Step 2 – Configuring Docker to Use the Remote Host

      To use the remote host as your Docker host instead of your local machine, set the DOCKER_HOST environment variable to point to the remote host. This variable will instruct the Docker CLI client to connect to the remote server.

      • export DOCKER_HOST=ssh://sammy@your_server_ip

      Now any Docker command you run will be run on the Droplet. For example, if you start a web server container and expose a port, it will be run on the Droplet and will be accessible through the port you exposed on the Droplet's IP address.

      To verify that you're accessing the Droplet as the Docker host, run docker info.

      You will see your Droplet's hostname listed in the Name field like so:


      … Name: docker-host

      One thing to keep in mind is that when you run a docker build command, the build context (all files and folders accessible from the Dockerfile) will be sent to the host and then the build process will run. Depending on the size of the build context and the amount of files, it may take a longer time compared to building the image on a local machine. One solution would be to create a new directory dedicated to the Docker image and copy or link only the files that will be used in the image so that no unneeded files will be uploaded inadvertently.


      You've created a remote Docker host and connected to it locally. The next time your laptop's battery is running low or you need to build a heavy Docker image, use your shiny remote Docker server instead of your local machine.

      You might also be interested in learning how to optimize Docker images for production, or how to optimize them specifically for Kubernetes.

      Source link

      How to Install and Secure phpMyAdmin with Nginx on a Debian 9 server


      While many users need the functionality of a database system like MySQL, interacting with the system solely from the MySQL command-line client requires familiarity with the SQL language, so it may not be the preferred interface for some.

      phpMyAdmin was created so that users can interact with MySQL through an intuitive web interface, running alongside a PHP development environment. In this guide, we’ll discuss how to install phpMyAdmin on top of an Nginx server, and how to configure the server for increased security.

      Note: There are important security considerations when using software like phpMyAdmin, since it runs on the database server, it deals with database credentials, and it enables a user to easily execute arbitrary SQL queries into your database. Because phpMyAdmin is a widely-deployed PHP application, it is frequently targeted for attack. We will go over some security measures you can take in this tutorial so that you can make informed decisions.


      Before you get started with this guide, you’ll need the following available to you:

      Because phpMyAdmin handles authentication using MySQL credentials, it is strongly advisable to install an SSL/TLS certificate to enable encrypted traffic between server and client. If you don’t have an existing domain configured with a valid certificate, you can follow the guide on How to Secure Nginx with Let’s Encrypt on Debian 9.

      Warning: If you don’t have an SSL/TLS certificate installed on the server and you still want to proceed, please consider enforcing access via SSH Tunnels as explained in Step 5 of this guide.

      Once you have met these prerequisites, you can go ahead with the rest of the guide.

      Step 1 — Installing phpMyAdmin

      The first thing we need to do is install phpMyAdmin on the LEMP server. We’re going to use the default Debian repositories to achieve this goal.

      Let’s start by updating the server’s package index with:

      Now you can install phpMyAdmin with:

      • sudo apt install phpmyadmin

      During the installation process, you will be prompted to choose the web server (either Apache or Lighthttp) to configure. Because we are using Nginx as web server, we shouldn't make a choice here. Press tab and then OK to advance to the next step.

      Next, you’ll be prompted whether to use dbconfig-common for configuring the application database. Select Yes. This will set up the internal database and administrative user for phpMyAdmin. You will be asked to define a new password for the phpmyadmin MySQL user. You can also leave it blank and let phpMyAdmin randomly create a password.

      The installation will now finish. For the Nginx web server to find and serve the phpMyAdmin files correctly, we’ll need to create a symbolic link from the installation files to Nginx's document root directory:

      • sudo ln -s /usr/share/phpmyadmin /var/www/html

      Your phpMyAdmin installation is now operational. To access the interface, go to your server's domain name or public IP address followed by /phpmyadmin in your web browser:


      phpMyAdmin login screen

      As mentioned before, phpMyAdmin handles authentication using MySQL credentials, which means you should use the same username and password you would normally use to connect to the database via console or via an API. If you need help creating MySQL users, check this guide on How To Manage an SQL Database.

      Note: Logging into phpMyAdmin as the root MySQL user is discouraged because it represents a significant security risk. We'll see how to disable root login in a subsequent step of this guide.

      Your phpMyAdmin installation should be completely functional at this point. However, by installing a web interface, we've exposed our MySQL database server to the outside world. Because of phpMyAdmin's popularity, and the large amounts of data it may provide access to, installations like these are common targets for attacks. In the following sections of this guide, we'll see a few different ways in which we can make our phpMyAdmin installation more secure.

      Step 2 — Changing phpMyAdmin's Default Location

      One of the most basic ways to protect your phpMyAdmin installation is by making it harder to find. Bots will scan for common paths, like /phpmyadmin, /pma, /admin, /mysql and such. Changing the interface's URL from /phpmyadmin to something non-standard will make it much harder for automated scripts to find your phpMyAdmin installation and attempt brute-force attacks.

      With our phpMyAdmin installation, we've created a symbolic link pointing to /usr/share/phpmyadmin, where the actual application files are located. To change phpMyAdmin's interface URL, we will rename this symbolic link.

      First, let's navigate to the Nginx document root directory and list the files it contains to get a better sense of the change we'll make:

      You’ll receive the following output:


      total 8 -rw-r--r-- 1 root root 612 Apr 8 13:30 index.nginx-debian.html lrwxrwxrwx 1 root root 21 Apr 8 15:36 phpmyadmin -> /usr/share/phpmyadmin

      The output shows that we have a symbolic link called phpmyadmin in this directory. We can change this link name to whatever we'd like. This will in turn change phpMyAdmin's access URL, which can help obscure the endpoint from bots hardcoded to search common endpoint names.

      Choose a name that obscures the purpose of the endpoint. In this guide, we'll name our endpoint /nothingtosee, but you should choose an alternate name. To accomplish this, we'll rename the link:

      • sudo mv phpmyadmin nothingtosee
      • ls -l

      After running the above commands, you’ll receive this output:


      total 8 -rw-r--r-- 1 root root 612 Apr 8 13:30 index.nginx-debian.html lrwxrwxrwx 1 root root 21 Apr 8 15:36 nothingtosee -> /usr/share/phpmyadmin

      Now, if you go to the old URL, you'll get a 404 error:


      phpMyAdmin 404 error

      Your phpMyAdmin interface will now be available at the new URL we just configured:


      phpMyAdmin login screen

      By obfuscating phpMyAdmin's real location on the server, you're securing its interface against automated scans and manual brute-force attempts.

      Step 3 — Disabling Root Login

      On MySQL as well as within regular Linux systems, the root account is a special administrative account with unrestricted access to the system. In addition to being a privileged account, it's a known login name, which makes it an obvious target for brute-force attacks. To minimize risks, we'll configure phpMyAdmin to deny any login attempts coming from the user root. This way, even if you provide valid credentials for the user root, you'll still get an "access denied" error and won't be allowed to log in.

      Because we chose to use dbconfig-common to configure and store phpMyAdmin settings, the default configuration is currently stored in the database. We'll need to create a new file to define our custom settings.

      Even though the PHP files for phpMyAdmin are located inside /usr/share/phpmyadmin, the application uses configuration files located at /etc/phpmyadmin. We will create a new custom settings file inside /etc/phpmyadmin/conf.d, and name it pma_secure.php:

      • sudo nano /etc/phpmyadmin/conf.d/pma_secure.php

      The following configuration file contains the necessary settings to disable passwordless logins (AllowNoPassword set to false) and root login (AllowRoot set to false):


      # PhpMyAdmin Settings
      # This should be set to a random string of at least 32 chars
      $cfg['blowfish_secret'] = '3!#32@3sa(+=_4?),5XP_:U%%834sdfSdg43yH#{o';
      $cfg['Servers'][$i]['auth_type'] = 'cookie';
      $cfg['Servers'][$i]['AllowNoPassword'] = false;
      $cfg['Servers'][$i]['AllowRoot'] = false;

      Save the file when you're done editing by pressing CTRL + X then y to confirm changes and ENTER. The changes will apply automatically. If you reload the login page now and try to log in as root, you will get an Access Denied error:

      access denied

      Root login is now prohibited on your phpMyAdmin installation. This security measure will block brute-force scripts from trying to guess the root database password on your server. Moreover, it will enforce the usage of less-privileged MySQL accounts for accessing phpMyAdmin's web interface, which by itself is an important security practice.

      Step 4 — Creating an Authentication Gateway

      Hiding your phpMyAdmin installation on an unusual location might sidestep some automated bots scanning the network, but it's useless against targeted attacks. To better protect a web application with restricted access, it's generally more effective to stop attackers before they can even reach the application. This way, they'll be unable to use generic exploits and brute-force attacks to guess access credentials.

      In the specific case of phpMyAdmin, it's even more important to keep the login interface locked away. By keeping it open to the world, you're offering a brute-force platform for attackers to guess your database credentials.

      Adding an extra layer of authentication to your phpMyAdmin installation enables you to increase security. Users will be required to pass through an HTTP authentication prompt before ever seeing the phpMyAdmin login screen. Most web servers, including Nginx, provide this capability natively.

      To set this up, we first need to create a password file to store the authentication credentials. Nginx requires that passwords be encrypted using the crypt() function. The OpenSSL suite, which should already be installed on your server, includes this functionality.

      To create an encrypted password, type:

      You will be prompted to enter and confirm the password that you wish to use. The utility will then display an encrypted version of the password that will look something like this:



      Copy this value, as you will need to paste it into the authentication file we'll be creating.

      Now, create an authentication file. We'll call this file pma_pass and place it in the Nginx configuration directory:

      • sudo nano /etc/nginx/pma_pass

      In this file, you’ll specify the username you would like to use, followed by a colon (:), followed by the encrypted version of the password you received from the openssl passwd utility.

      We are going to name our user sammy, but you should choose a different username. The file should look like this:



      Save and close the file when you're done.

      Now we're ready to modify the Nginx configuration file. For this guide, we'll use the configuration file located at /etc/nginx/sites-available/ You should use the relevant Nginx configuration file for the web location where phpMyAdmin is currently hosted. Open this file in your text editor to get started:

      • sudo nano /etc/nginx/sites-available/

      Locate the server block, and the location / section within it. We need to create a new location section within this block to match phpMyAdmin's current path on the server. In this guide, phpMyAdmin's location relative to the web root is /nothingtosee:


      server {
          . . .
              location / {
                      try_files $uri $uri/ =404;
              location /nothingtosee {
                      # Settings for phpMyAdmin will go here
          . . .

      Within this block, we'll need to set up two different directives: auth_basic, which defines the message that will be displayed on the authentication prompt, and auth_basic_user_file, pointing to the file we just created. This is how your configuration file should look like when you're finished:


      server {
          . . .
              location /nothingtosee {
                      auth_basic "Admin Login";
                      auth_basic_user_file /etc/nginx/pma_pass;
          . . .

      Save and close the file when you're done. To check if the configuration file is valid, you can run:

      The following output is expected:


      nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful

      To activate the new authentication gate, you must reload the web server:

      • sudo systemctl reload nginx

      Now, if you visit the phpMyAdmin URL in your web browser, you should be prompted for the username and password you added to the pma_pass file:


      Nginx authentication page

      Once you enter your credentials, you'll be taken to the standard phpMyAdmin login page.

      Note: If refreshing the page does not work, you may have to clear your cache or use a different browser session if you've already been using phpMyAdmin.

      In addition to providing an extra layer of security, this gateway will help keep your MySQL logs clean of spammy authentication attempts.

      Step 5 — Setting Up Access via Encrypted Tunnels (Optional)

      For increased security, it is possible to lock down your phpMyAdmin installation to authorized hosts only. You can whitelist authorized hosts in your Nginx configuration file, so that any request coming from an IP address that is not on the list will be denied.

      Even though this feature alone can be enough in some use cases, it's not always the best long-term solution, mainly due to the fact that most people don't access the Internet from static IP addresses. As soon as you get a new IP address from your Internet provider, you'll be unable to get to the phpMyAdmin interface until you update the Nginx configuration file with your new IP address.

      For a more robust long-term solution, you can use IP-based access control to create a setup in which users will only have access to your phpMyAdmin interface if they're accessing from either an authorized IP address or localhost via SSH tunneling. We'll see how to set this up in the sections below.

      Combining IP-based access control with SSH tunneling greatly increases security because it fully blocks access coming from the public internet (except for authorized IPs), in addition to providing a secure channel between user and server through the use of encrypted tunnels.

      Setting Up IP-Based Access Control on Nginx

      On Nginx, IP-based access control can be defined in the corresponding location block of a given site, using the directives allow and deny. For instance, if we want to only allow requests coming from a given host, we should include the following two lines, in this order, inside the relevant location block for the site we would like to protect:

      allow hostname_or_IP;
      deny all;

      You can allow as many hosts as you want, you only need to include one allow line for each authorized host/IP inside the respective location block for the site you're protecting. The directives will be evaluated in the same order as they are listed, until a match is found or the request is finally denied due to the deny all directive.

      We'll now configure Nginx to only allow requests coming from localhost or your current IP address. First, you'll need to know the current public IP address your local machine is using to connect to the Internet. There are various ways to obtain this information; for simplicity, we're going to use the service provided by You can either open the URL in your browser, or run the following command from your local machine:

      • curl

      You should get a simple IP address as output, like this:


      That is your current public IP address. We'll configure phpMyAdmin's location block to only allow requests coming from that IP, in addition to localhost. We'll need to edit once again the configuration block for phpMyAdmin inside /etc/nginx/sites-available/

      Open the Nginx configuration file using your command-line editor of choice:

      • sudo nano /etc/nginx/sites-available/

      Because we already have an access rule within our current configuration, we need to combine it with IP-based access control using the directive satisfy all. This way, we can keep the current HTTP authentication prompt for increased security.

      This is how your phpMyAdmin Nginx configuration should look like after you're done editing:


      server {
          . . .
          location /nothingtosee {
              satisfy all; #requires both conditions
              allow; #allow your IP
              allow; #allow localhost via SSH tunnels
              deny all; #deny all other sources
              auth_basic "Admin Login";
              auth_basic_user_file /etc/nginx/pma_pass;
          . . .

      Remember to replace nothingtosee with the actual path where phpMyAdmin can be found, and the highlighted IP address with your current public IP address.

      Save and close the file when you're done. To check if the configuration file is valid, you can run:

      The following output is expected:


      nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful

      Now reload the web server so the changes take effect:

      • sudo systemctl reload nginx

      Because your IP address is explicitly listed as an authorized host, your access shouldn't be disturbed. Anyone else trying to access your phpMyAdmin installation will now get a 403 error (Forbidden):


      403 error

      In the next section, we'll see how to use SSH tunneling to access the web server through local requests. This way, you'll still be able to access phpMyAdmin's interface even when your IP address changes.

      Accessing phpMyAdmin Through an Encrypted Tunnel

      SSH tunneling works as a way of redirecting network traffic through encrypted channels. By running an ssh command similar to what you would use to log into a server, you can create a secure "tunnel" between your local machine and that server. All traffic coming in on a given local port can now be redirected through the encrypted tunnel and use the remote server as a proxy, before reaching out to the internet. It's similar to what happens when you use a VPN (Virtual Private Network), however SSH tunneling is much simpler to set up.

      We'll use SSH tunneling to proxy our requests to the remote web server running phpMyAdmin. By creating a tunnel between your local machine and the server where phpMyAdmin is installed, you can redirect local requests to the remote web server, and what's more important, traffic will be encrypted and requests will reach Nginx as if they're coming from localhost. This way, no matter what IP address you're connecting from, you'll be able to securely access phpMyAdmin's interface.

      Because the traffic between your local machine and the remote web server will be encrypted, this is a safe alternative for situations where you can't have an SSL/TLS certificate installed on the web server running phpMyAdmin.

      From your local machine, run this command whenever you need access to phpMyAdmin:

      • ssh user@server_domain_or_IP -L 8000:localhost:80 -L 8443:localhost:443 -N

      Let's examine each part of the command:

      • user: SSH user to connect to the server where phpMyAdmin is running
      • hostname_or_IP: SSH host where phpMyAdmin is running
      • -L 8000:localhost:80 redirects HTTP traffic on port 8000
      • -L 8443:localhost:443 redirects HTTPS traffic on port 8443
      • -N: do not execute remote commands

      Note: This command will block the terminal until interrupted with a CTRL+C, in which case it will end the SSH connection and stop the packet redirection. If you'd prefer to run this command in background mode, you can use the SSH option -f.

      Now, go to your browser and replace server_domain_or_IP with localhost:PORT, where PORT is either 8000 for HTTP or 8443 for HTTPS:


      phpMyAdmin login screen

      Note: If you're accessing phpMyAdmin via https, you might get an alert message questioning the security of the SSL certificate. This happens because the domain name you're using (localhost) doesn't match the address registered within the certificate (domain where phpMyAdmin is actually being served). It is safe to proceed.

      All requests on localhost:8000 (HTTP) and localhost:8443 (HTTPS) are now being redirected through a secure tunnel to your remote phpMyAdmin application. Not only have you increased security by disabling public access to your phpMyAdmin, you also protected all traffic between your local computer and the remote server by using an encrypted tunnel to send and receive data.

      If you'd like to enforce the usage of SSH tunneling to anyone who wants access to your phpMyAdmin interface (including you), you can do that by removing any other authorized IPs from the Nginx configuration file, leaving as the only allowed host to access that location. Considering nobody will be able to make direct requests to phpMyAdmin, it is safe to remove HTTP authentication in order to simplify your setup. This is how your configuration file would look like in such a scenario:


      server {
          . . .
          location /nothingtosee { 
              allow; #allow localhost only
              deny all; #deny all other sources
          . . .

      Once you reload Nginx's configuration with sudo systemctl reload nginx, your phpMyAdmin installation will be locked down and users will be required to use SSH tunnels in order to access phpMyAdmin's interface via redirected requests.


      In this tutorial, we saw how to install phpMyAdmin on Ubuntu 18.04 running Nginx as the web server. We also covered advanced methods to secure a phpMyAdmin installation on Ubuntu, such as disabling root login, creating an extra layer of authentication, and using SSH tunneling to access a phpMyAdmin installation via local requests only.

      After completing this tutorial, you should be able to manage your MySQL databases from a reasonably secure web interface. This user interface exposes most of the functionality available via the MySQL command line. You can browse databases and schema, execute queries, and create new data sets and structures.

      Source link

      Automating Initial Server Setup with Ansible on Ubuntu 18.04


      When you first create a new Ubuntu 18.04 server, there are a few configuration steps that you should take early on as part of the basic setup. This will increase the security and usability of your server, working as a solid foundation for subsequent actions.

      While you can complete these steps manually, automating the process will save you time and eliminate human error. With the popularization of containerized applications and microservices, server automation now plays an essential role in systems administration. It is also a way to establish standard procedures for new servers.

      This guide explains how to use Ansible to automate the steps contained in our Initial Server Setup Guide. Ansible is a modern configuration management tool that can be used to automate the provisioning and configuration of remote systems.

      Pre-Flight Check

      In order to execute the automated setup provided by the playbook we’re discussing in this guide, you’ll need:

      • Ansible installed either on your local machine or on a remote server that you have set up as an Ansible Control Node. You can follow Step 1 of the tutorial How to Install and Configure Ansible on Ubuntu 18.04 to get this set up.
      • Root access to one or more Ubuntu 18.04 servers that will be managed by Ansible.

      Before running a playbook, it’s important to make sure Ansible is able to connect to your servers via SSH and run Ansible modules using Python. The next two sections cover how to set up your Ansible inventory to include your servers and how to run ad-hoc Ansible commands to test for connectivity and valid credentials.

      Inventory File

      The inventory file contains information about the hosts you’ll manage with Ansible. You can include anywhere from one to several hundred of servers in your inventory file, and hosts can be organized into groups and subgroups. The inventory file is also often used to set variables that will be valid for certain hosts and groups only, in order to be used within playbooks and templates. Some variables can also affect the way a playbook is run, like the ansible_python_interpreter variable that we’ll see in a moment.

      To inspect the contents of your default Ansible inventory, open the /etc/ansible/hosts file using your command-line editor of choice, on your local machine or an Ansible Control Node:

      • sudo nano /etc/ansible/hosts

      Note: some Ansible installations won’t create a default inventory file. If the file doesn’t exist in your system, you can create a new file at /etc/ansible/hosts or provide a custom inventory path using the -i parameter when running commands and playbooks.

      The default inventory file provided by the Ansible installation contains a number of examples that you can use as references for setting up your inventory. The following example defines a group named servers with three different servers in it, each identified by a custom alias: server1, server2, and server3:


      server1 ansible_host=
      server2 ansible_host=
      server3 ansible_host=

      The server:vars subgroup sets the ansible_python_interpreter host parameter that will be valid for all hosts included in the servers group. This parameter makes sure the remote server uses the /usr/bin/python3 Python 3 executable instead of /usr/bin/python (Python 2.7), which is not present on recent Ubuntu versions.

      To finish setting up your inventory file, replace the highlighted IPs with the IP addresses of your servers. When you’re finished, save and close the file by pressing CTRL+X then y to confirm changes and then ENTER.

      Now that your inventory file is ready, it’s time to test connectivity to your nodes

      Testing Connectivity

      After setting up the inventory file to include your servers, it’s time to check if Ansible is able to connect to these servers and run commands via SSH. For this guide, we will be using the Ubuntu root account because that’s typically the only account available by default on newly created servers. This playbook will create a new non-root user with sudo privileges that you should use in subsequent interactions with the remote server.

      From your local machine or Ansible Control Node, run:

      • ansible -m ping all -u root

      This command will use the built-in ping Ansible module to run a connectivity test on all nodes from your default inventory, connecting as root. The ping module will test:
      if hosts are accessible;
      if you have valid SSH credentials;
      if hosts are able to run Ansible modules using Python.

      If instead of key-based authentication you’re using password-based authentication to connect to remote servers, you should provide the additional parameter -k to the Ansible command, so that it will prompt you for the password of the connecting user.

      • ansible -m ping all -u root -k

      Note: Keep in mind that some servers might have additional security measures against password-based authentication as the root user, and in some cases you might be required to manually log in to the server to change the initial root password.

      You should get output similar to this:


      server1 | SUCCESS => { "changed": false, "ping": "pong" } server2 | SUCCESS => { "changed": false, "ping": "pong" } server3 | SUCCESS => { "changed": false, "ping": "pong" }

      If this is the first time you’re connecting to these servers via SSH, you’ll be asked to confirm the authenticity of the hosts you’re connecting to via Ansible. When prompted, type yes and then hit Enter to confirm.

      Once you get a “pong” reply back from a host, it means you’re ready to run Ansible commands and playbooks on that server.

      What Does this Playbook Do?

      This Ansible playbook provides an alternative to manually running through the procedure outlined in the Ubuntu 18.04 initial server setup guide and the guide on setting up SSH keys on Ubuntu 18.04.

      Running this playbook will cause the following actions to be performed:

      1. The administrative group wheels is created and then configured for passwordless sudo.
      2. A new administrative user is created within that group, using the name specified by the create_user variable.
      3. A public SSH key is copied from the location defined by the variable copy_local_key, and added to the authorized_keys file for the user created in the previous step.
      4. Password-based authentication is disabled for the root user.
      5. The local apt package index is updated and basic packages defined by the variable sys_packages are installed.
      6. The UFW firewall is configured to allow only SSH connections and deny any other requests.

      For more information about each of the steps included in this playbook, please refer to our Ubuntu 18.04 initial server setup guide.

      Once the playbook has finished running, you’ll be able to log in to the server using the newly created sudo account.

      How to Use this Playbook

      To get started, we’ll download the contents of the playbook to your Ansible Control Node. This can be either your local machine, or a remote server where you have Ansible installed and your inventory set up.

      For your convenience, the contents of the playbook are also included in a further section of this guide.

      To download this playbook from the command-line, you can use curl:

      • curl -L -o initial_server_setup.yml

      This will download the contents of the playbook to a file named initial_server_setup.yml on your current local path. You can examine the contents of the playbook by opening the file with your command-line editor of choice:

      • sudo nano initial_server_setup.yml

      Once you’ve opened the playbook file, you should notice a section named vars with three distinct variables that require your attention:

      • create_user: The name of the non-root user account to create and grant sudo privileges to. Our example uses sammy, but you can use whichever username you’d like.
      • copy_local_key: Local path to a valid SSH public key to set up as an authorized key for the new non-root sudo account. The default value points to the current local user’s public key located at ~/.ssh/
      • sys_packages: A list of basic system packages that will be installed using the package manager tool apt.

      Once you’re done updating the variables inside initial_server_setup.yml, save and close the file.

      You’re now ready to run this playbook on one or more servers. Most playbooks are configured to be executed on all servers from your inventory, by default. We can use the -l flag to make sure that only a subset of servers, or a single server, is affected by the playbook. To execute the playbook only on server1, you can use the following command:

      • ansible-playbook initial_server_setup.yml -l server1

      You will get output similar to this:


      PLAY [all] *************************************************************************************************************************************** TASK [Make sure we have a 'wheel' group] ********************************************************************************************************* changed: [server1] TASK [Allow 'wheel' group to have passwordless sudo] ********************************************************************************************* changed: [server1] TASK [Create a new regular user with sudo privileges] ******************************************************************************************** changed: [server1] TASK [Set authorized key for remote user] ******************************************************************************************************** changed: [server1] TASK [Disable password authentication for root] ************************************************************************************************** changed: [server1] TASK [Update apt] ******************************************************************************************************************************** changed: [server1] TASK [Install required system packages] ********************************************************************************************************** ok: [server1] TASK [UFW - Allow SSH connections] *************************************************************************************************************** changed: [server1] TASK [UFW - Deny all other incoming traffic by default] ****************************************************************************************** changed: [server1] PLAY RECAP *************************************************************************************************************************************** server1 : ok=9 changed=8 unreachable=0 failed=0

      Once the playbook execution is finished, you’ll be able to log in to the server with:

      • ssh sammy@server_domain_or_IP

      Remember to replace sammy with the user defined by the create_user variable, and server_domain_or_IP with your server’s hostname or IP address.

      In case you have set a custom public key with the copy_local_key variable, you’ll need to provide an extra parameter specifying the location of its private key counterpart:

      • ssh sammy@server_domain_or_IP -i ~/.ssh/ansible_controller_key

      After logging in to the server, you can check the UFW firewall’s active rules to confirm that it’s properly configured:

      You should get output similar to this:


      Status: active To Action From -- ------ ---- OpenSSH ALLOW Anywhere OpenSSH (v6) ALLOW Anywhere (v6)

      This means that the UFW firewall has successfully been enabled. Since this was the last task in the playbook, it confirms that the playbook was fully executed on this server.

      The Playbook Contents

      You can find the initial server setup playbook in the ansible-playbooks repository in the DigitalOcean Community GitHub organization. To copy or download the script contents directly, click the Raw button towards the top of the script, or click here to view the raw contents directly.

      The full contents are also included here for convenience:


      - hosts: all
        remote_user: root
        gather_facts: false
          create_user: sammy
          copy_local_key: "{{ lookup('file', lookup('env','HOME') + '/.ssh/') }}"
          sys_packages: [ 'curl', 'vim', 'git', 'ufw' ]
          - name: Make sure we have a 'wheel' group
              name: wheel
              state: present
          - name: Allow 'wheel' group to have passwordless sudo
              path: /etc/sudoers
              state: present
              regexp: '^%wheel'
              line: '%wheel ALL=(ALL) NOPASSWD: ALL'
              validate: '/usr/sbin/visudo -cf %s'
          - name: Create a new regular user with sudo privileges
              name: "{{ create_user }}"
              groups: wheel
              shell: /bin/bash
          - name: Set authorized key for remote user
              user: "{{ create_user }}"
              state: present
              key: "{{ copy_local_key }}"
          - name: Disable password authentication for root
              path: /etc/ssh/sshd_config
              state: present
              regexp: '^PermitRootLogin'
              line: 'PermitRootLogin prohibit-password'
          - name: Update apt
            apt: update_cache=yes
          - name: Install required system packages
            apt: name={{ sys_packages }} state=latest
          - name: UFW - Allow SSH connections
              rule: allow
              name: OpenSSH
          - name: UFW - Deny all other incoming traffic by default
              state: enabled
              policy: deny
              direction: incoming

      Feel free to modify this playbook or include new tasks to best suit your individual needs within your own workflow.


      Automating the initial server setup can save you time, while also making sure your servers will follow a standard configuration that can be improved and customized to your needs. With the distributed nature of modern applications and the need for more consistency between different staging environments, automation like this becomes a necessity.

      In this guide, we demonstrated how to use Ansible for automating the initial tasks that should be executed on a fresh server, such as creating a non-root user with sudo access, enabling UFW and disabling remote root login.

      If you'd like to include new tasks in this playbook to further customize your initial server setup, please refer to our introductory Ansible guide Configuration Management 101: Writing Ansible Playbooks.

      Source link