Rough notes on setting up an Ubuntu 22.04LTS server with docker and snap

IP allocations

First, we set up a static IP on the network device that would handle all external traffic and a DHCP on the network device that would access the management network, which is connected for maintenance.

To do so, we created the following file:


using the following command:

sudo nano /etc/netplan/01-netcfg.yaml;

and added the following content to it:

# This file describes the network interfaces available on your system
# For more information, see netplan(5).
  version: 2
  renderer: networkd
      dhcp4: no
      addresses: []
          addresses: [,]
      dhcp4: yes

To apply the changes, we executed the following:

sudo netplan apply;

Update everything (the operating system and all packages)

Usually, it is a good idea to update your system before making significant changes to it:

sudo apt update -y; sudo apt upgrade -y; sudo apt autoremove -y;

Install docker via snap

In this setup, we did not use the docker version available on the Ubuntu repositories, we went for the ones from the snap. To install it, we used the following commands:

sudo apt install snapd;
sudo snap install docker;

Increase network pool for docker daemon

To handle the following problem:

ERROR: could not find an available, non-overlapping IPv4 address pool among the defaults to assign to the network

We modified the following file


using the command:

sudo nano /var/snap/docker/current/config/daemon.json;

and set the content to be as follows:

    "log-level":        "error",
    "storage-driver":   "overlay2",
    "default-address-pools": [
            "base": "",
            "size": 24
            "base": "",
            "size": 24

We executed the following command to restart the docker daemon and get the network changes applied:

sudo snap disable docker;
sudo snap enable docker;

Gave access to our user to manage the docker

We added our user to the docker group so that we could manage the docker daemon without sudo rights.

sudo addgroup --system docker;
sudo adduser $USER docker;
newgrp docker;
sudo snap disable docker;
sudo snap enable docker;

After that, we made sure that the access rights to the volumes were correct:

sudo chown -R www-data:www-data /volumes/*
sudo chown -R tux:tux /volumes/letsencrypt/ /volumes/reverse/private/


After we copied everything in place, we executed the following command to create our containers and start them with the appropriate networks and volumes:

docker-compose up -d --remove-orphans;

We had to increase the timeout as we were getting the following error:

ERROR: for container_a  UnixHTTPConnectionPool(host='localhost', port=None): Read timed out. (read timeout=60)
ERROR: An HTTP request took too long to complete. Retry with --verbose to obtain debug information.
If you encounter this issue regularly because of slow network conditions, consider setting COMPOSE_HTTP_TIMEOUT to a higher value (current value: 60).

Updating the databases and performing any repairs

First, we connected to a terminal of the database container using the following command:

docker exec -it mariadb_c1 /bin/bash;

From there, we executed the following commands:

mysql_upgrade --user=root --password;
mysqlcheck -p -o --all-databases;

Bulk / Batch stopping docker containers

The following commands will help you stop many docker containers simultaneously. Of course, you can change the command stop to another, for example rm or whatever suits your needs.

You need to keep in mind that if you have dependencies between containers, you might need to execute the commands below more than once.

Stop all docker containers.

docker container stop $(docker container ls -q);
#This command creates a list of all containers.
#Using the -q parameter, we only get back the container ID and not all information about them.
#Then it will stop each container one by one.

Stop specific docker containers using a filter on their name.

docker container stop $(docker container ls -q --filter name=_web);
#This command finds all containers that their name contains _web.
#Using the -q parameter, we only get back the container ID and not all information about them.
#Then it will stop each container one by one.

A personal note

Check the system for things you might need to configure, like a crontab or other services.

A script that handles privileges on the docker volumes

To avoid access problems with the various external volumes we created the mysql user and group on the host machine as follows:

sudo groupadd -g 999 mysql;
sudo useradd -u 999 mysql -g mysql;

Then we execute the following to repair ownership issues with our containers. Please note that this script is custom to a particular installation and might not meet your needs.


sudo chown -R www-data:www-data ~/volumes/*;
sudo chown -R bob:bob ~/volumes/letsencrypt/ ~/volumes/reverse/private/;
find ~/volumes/ -maxdepth 2 -type d -name mysql -exec sudo chown -R mysql:mysql '{}' \;;

g++ not found on Fedora 25

On a Fedora 25 (64bit) we got the error g++ not found.

We could have installed g++ using:

sudo dnf install gcc-c++ -y;

But we wanted to install all common additional development tools that we might need for C/C++ development in the future without going over the list of available packages to find which ones.
To do so, we installed all the packages of the group that is marked to be used for C development using dnf as follows:

sudo dnf group install "C Development Tools and Libraries" -y;

Linux: Check if a User or a Group Exists 2

You can find out if user exists by searching in the /etc/passwd file using the following command:

egrep -i "^useraccount:" /etc/passwd

The above command will print the matching record from /etc/passwd if the user exists or nothing if the user does not exist.
The ^ symbol is used to make sure there is no characters before the username and the : character is used as the delimiter in the file (which indicates the end of the username). By wrapping the username with these characters we are sure that if we matched a record, we matched the correct record with the full username.

A very simple way to use this code in a script is by utilizing the $? (question mark) variable. The question mark variable contains the exit status of the last command that executed. Specifically, egrep will return 0 if there was a match or else it will return a a positive number (usually 1).
Taking advantage of this behavior, after executing the above command, we check the $? variable to see the result with an if statement.

egrep -i "^useraccount:" /etc/passwd;
if [ $? -eq 0 ]; then
   echo "User Exists"
   echo "User does not exist -- Invalid Username"

You can also find out if a group exists by searching in the /etc/group file. Similar to the approach we showed before, we can check if a group exists using the following:

egrep -i "^groupname" /etc/group;
if [ $? -eq 0 ]; then
   echo "Group Exists"
   echo "Group does not exist -- Invalid Group name"


gpasswd group
gpasswd -a useraccount groupname
gpasswd -d useraccount groupname
gpasswd -R groupname
gpasswd -r groupname
gpasswd [-A useraccount,...] [-M useraccount ,...] groupname

gpasswd is used to administer the /etc/group file (and /etc/gshadow file if compiled with SHADOWGRP defined).
System administrator can use:
-A option to define group administrator(s)
-M option to define members and has all rights of group administrators and members.

Group administrator can use:
-a to add users
-d to delete users.

Administrators can use:
-r option to remove group password. When no password is set only group members can use newgrp to join the group.
-R disables access to the group through newgrp command.

gpasswd called by a group administrator with group name only prompts for the group password. If password is set the members can still newgrp without a password, non-members must supply the password.