Configure development server with Docker

Table of Content

It sometimes happens to setup development server for team with support many Docker environments.
Why is it Docker?

  • It’s easy to setup.
  • It’s easy to migrate.
  • It’s easy to support.
  • It’s just easy.

Update APT

As always, first as all, update and upgrade your APT.

# apt update
# apt upgrade

System settings

# echo fs.inotify.max_user_watches=582222 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p

Change hostname using hostnamectl

# hostnamectl set-hostname dev.timebase.app
# hostnamectl
   Static hostname: dev.timebase.app
         Icon name: computer-vm
           Chassis: vm
        Machine ID: d2112e9bc476412b9e86f82930e22961
           Boot ID: 3ce13f255d1846729ef6f51f31e4fdd5
    Virtualization: kvm
  Operating System: Ubuntu 20.04.2 LTS
            Kernel: Linux 5.4.0-28-generic
      Architecture: x86-64

Disable SSH password login on Linux to increase security

Assume you’ve just gotten access to a new server with a basic configuration with automatically generated root password. It would be great to disable the possibility to connect to the server through SSH with password, instead you have to use a key pair.

Make sudo ask for the root password

To turn on the rootpw flag, making sudo ask for the root password, in /etc/sudoers, add this line:

Defaults rootpw

Create a new sudo user account

You must create a regular user account and grant that user permission to gain root-level access via su command or NA command. Otherwise, you will be locked out of your server.

# useradd -m -s /bin/bash timebase

Set the user’s password using the passwd command:

# passwd timebase

Add user to sudo (Ubuntu/Debian) group

# usermod -aG sudo timebase

The above command allows people in group wheel or sudo to run all commands. Verify it using the id command:

# su - timebase
$ id timebase

Sample outputs:

uid=1000(timebase) gid=1000(timebase) groups=1000(timebase),27(sudo)

Ctrl+D to logout from a login shell.

Please note that you can add existing users to sudo or wheel group too. No need to create a new user account:

# usermod -aG sudo userNameHere

Install your public key in remote server

Add your public key to remote server (don’t forget to change IP to yours)

$ ssh-copy-id -i ~/.ssh/id_rsa.pub timebase@80.65.78.198

Now open a new terminal and be sure that you can connect with your key just typing

$ timebase root@80.65.78.198

If you see the greeting message, everything is fine and you can go to the next step.
Ctrl+D to logout from a login shell.

Disable the password based login on a server

Warning: Make sure you add yourself to sudoers files. Otherwise you will not able to login as root later on.

  1. Open the SSH configuration file sshd_config with the text editor vi:
    # vi /etc/ssh/sshd_config
  2. In the line PermitRootLogin yes replace the word yes with the word no:
    PermitRootLogin no
  3. Find ChallengeResponseAuthentication and set to no:
    ChallengeResponseAuthentication no
  4. Next, find PasswordAuthentication set to no too:
    PasswordAuthentication no
  5. Finally look for UsePAM and set to no, too:
    UsePAM no
  6. Save the file.
  7. Restart the service.
    # systemctl restart sshd

Verification

Try to login as root

$ ssh root@80.209.229.183
root@80.209.229.183: Permission denied (publickey,gssapi-keyex,gssapi-with-mic).

Try to login as another user with password only

$ ssh timebase@80.209.229.183 -o PubkeyAuthentication=no
timebase@80.209.229.183: Permission denied (publickey,gssapi-keyex,gssapi-with-mic).

Try to login as another user with public key

$ ssh timebase@80.209.229.183
Last login: Mon Jun  7 14:03:01 2021 from 78.98.52.223

Download and Install Docker

Set up the repository

  1. Update the apt package index and install packages to allow apt to use a repository over HTTPS:
    # apt install apt-transport-https ca-certificates curl gnupg lsb-release make
  2. Add Docker’s official GPG key:
    # curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
  3. Use the following command to set up the stable repository.
    # echo \
    "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
    $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Install Docker Engine

Enter the following command to download and install the Docker package.

apt update
apt install docker-ce docker-ce-cli containerd.io

Check Docker Version

You can check the version of Docker with the following command.

$ docker --version
Docker version 20.10.7, build f0df350

Launch Docker

Start Docker and enter the following command to enable it after every time the system reboots.

# systemctl enable --now docker
Synchronizing state of docker.service with SysV service script with /lib/systemd/systemd-sysv-install.
Executing: /lib/systemd/systemd-sysv-install enable docker

To disable it again, simply type in the following command.

# systemctl disable --now docker

Set User Privileges

This step will show you how to give privileges to any user with Docker. You can replace “timebase” with the user account you are giving permission.

$ sudo usermod -aG docker $USER
$ sudo gpasswd -a $USER docker
$ newgrp docker

Test Docker

Test Docker by running the following command, which will open a container to run the Hello World command.

# docker run hello-world

Install Docker Compose

  1. Run this command to download the current stable release of Docker Compose:

    # curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

    To install a different version of Compose, substitute 1.29.2 with the version of Compose you want to use.

  2. Apply executable permissions to the binary:

    # chmod +x /usr/local/bin/docker-compose

    Note: If the command docker-compose fails after installation, check your path. You can also create a symbolic link to /usr/bin or any other directory in your path.

  3. Test the installation.

    $ docker-compose --version
    docker-compose version 1.29.2, build 5becea4c

Install AWS CLI

Install required packages

# apt-get install python3 python3-venv unzip mysql-client

Checking Python availability

Make sure phyton command is available with:

$ python --version
Python 3.8.5

If you get an error like this /usr/bin/env: ‘python’: No such file or directory instead. Check if Python 3 has been installed, run these commands:

# whereis python3

Then create a symlink to it:

# ln -s /usr/bin/python3 /usr/bin/python

AWS CLI installation

  1. For the latest version of the AWS CLI, use the following command block:

    # apt install 
    # curl "https://s3.amazonaws.com/aws-cli/awscli-bundle.zip" -o "awscli-bundle.zip"
    # unzip awscli-bundle.zip
    # ./awscli-bundle/install -i /usr/local/aws -b /usr/local/bin/aws
  2. Create new AWS CLI profile

    $ aws configure --profile <your-name>
    AWS Access Key ID [None]: AK****************TY # change it with real ID
    AWS Secret Access Key [None]: Zk************************************ZE # change it with real key
    Default region name [None]: eu-central-1
    Default output format [None]: json
  3. Check if it’s saved correctly

    $ cat ~/.aws/credentials
    [<your-name>]
    aws_access_key_id = AK****************TY
    aws_secret_access_key = Zk************************************ZE
  4. Try to login with

    $ $(aws ecr get-login --no-include-email --profile <your-name>)

Allow access to GitLab private repositories

  1. Create the key pair on the server:

    $ ssh-keygen -t rsa
  2. Copy the new SSH key:

    $ cat ~/.ssh/id_rsa.pub
  3. Add the SSH key to GitLab:
    Go to GitLab -> Preferences -> SSH Keys, past public key in the form and hit Add key button.

Configure a project

We need to create directory where all our project will be placed and directory for MySQL dumps. I’m going to setup the project from git repository. You can be free use any other repository.

  1. Login with your non-root user and create directories.

    $ cd ~
    $ mkdir {docker,dump}
  2. Clone your project

    $ cd docker
    $ git clone https://gitlab.com/timebase/tb-web
    $ cd tb-web-tgs/

    We have prepare makefile in our project that allows as to run the project as:

    $ make up

    You can use native docker-compose command instead:

    $ docker-compose up
  3. Open your project in a browser 80.65.78.198:8081.

    Note. Use the port number that you indicate in .evn or docker-compose.yml file.

But as you can notice it’s not comfortably to use IP and port, even more when the number of dev projects increase it’ll make a nightmare to remember who is who. To simplify our life we will install Nginx and apply reasonable names to our projects.

Install Nginx

# apt install nginx
  1. Prepare a configuration file under:

    # cat /etc/nginx/sites-available/tgs.timebase.app.conf
    server {
    server_name tgs.timebase.app;
    
    access_log /var/log/nginx/tgs.timebase.app.access.log;
    error_log /var/log/nginx/tgs.timebase.app.error.log;
    
    location / {
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_cache_bypass $http_upgrade;
    
        proxy_connect_timeout 600;
        proxy_send_timeout 600;
        proxy_read_timeout 600;
        send_timeout 600;
        proxy_pass http://localhost:8081/;
    }
    }

    Make sure you indicate correct port number of your Docker container in proxy_pass config.

  2. Enable your project that Nginx can read this configuration:

    # ln -s /etc/nginx/sites-available/tgs.timebase.app.conf /etc/nginx/sites-enabled/tgs.timebase.app.conf
  3. Test Nginx configuration

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

Install Certbot

To make your project available on the Internet we have to configure Certbot to be able to connect through HTTPS.

  1. Before to setup Certbot you must to add your domain to DNS.

  2. Install Certbot and it’s Nginx plugin with apt:

    # apt install certbot python3-certbot-nginx

    Certbot is now ready to use, but in order for it to automatically configure SSL for Nginx, we need to verify some of Nginx’s configuration.

  3. Obtaining an SSL Certificate
    Certbot provides a variety of ways to obtain SSL certificates through plugins. The Nginx plugin will take care of reconfiguring Nginx and reloading the config whenever necessary. To use this plugin, type the following:

    # certbot --nginx -d tgs.timebase.app -d www.tgs.timebase.app

This runs certbot with the --nginx plugin, using -d to specify the domain names we’d like the certificate to be valid for.

If this is your first time running certbot, you will be prompted to enter an email address and agree to the terms of service. After doing so, certbot will communicate with the Let’s Encrypt server, then run a challenge to verify that you control the domain you’re requesting a certificate for.

  1. Verifying Certbot Auto-Renewal

    # systemctl status certbot.timer
    ● certbot.timer - Run certbot twice daily
     Loaded: loaded (/lib/systemd/system/certbot.timer; enabled; vendor preset: enabled)
     Active: active (waiting) since Mon 2021-06-07 18:38:40 EEST; 10min ago
    Trigger: Tue 2021-06-08 10:57:25 EEST; 16h left
    Triggers: ● certbot.service
    Jun 07 18:38:40 dev.timebase.app systemd[1]: Started Run certbot twice daily.
  2. Check your /etc/nginx/sites-enabled/tgs.timebase.app.conf:

    # cat /etc/nginx/sites-enabled/tgs.timebase.app.conf
    server {
    server_name tgs.timebase.app;
    
    access_log /var/log/nginx/tgs.timebase.app.access.log;
    error_log /var/log/nginx/tgs.timebase.app.error.log;
    
    location / {
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_cache_bypass $http_upgrade;
    
        proxy_connect_timeout 600;
        proxy_send_timeout 600;
        proxy_read_timeout 600;
        send_timeout 600;
        proxy_pass http://localhost:8081/;
    }
    
    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/tgs.timebase.app/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/tgs.timebase.app/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
    }
    server {
    if ($host = tgs.timebase.app) {
        return 301 https://$host$request_uri;
    } # managed by Certbot
    
    server_name tgs.timebase.app;
    listen 80;
    return 404; # managed by Certbot
    }

    As you can see certbot added some configuration automatically. Now try to access tgs.timebase.app through your browser.

Useful links:

How To Secure Nginx with Let’s Encrypt on Ubuntu 20.04

Leave a Reply

Your email address will not be published. Required fields are marked *