Docker & Docker Compose, Bugs & Fixes.

In the name of God

I was trying to bring a website on my server from a simple web host. This article is just a resource gathering of opening and reading about 150 browser tabs. I feel I'd need to read this sooner or later again. Hope it's useful.

I am trying to bring a website on my Ubuntu 22.04 server. These are the required stuff:

  • Nginx + SSL for the domain
  • PHP + Composer
  • MariaDB (or MySQL) + PHPMyAdmin

I felt I have to learn Docker at some point so I started here. And I wanted to make my server a little more secure.

First Step

This isn't a step by step guide. Your first step would be to read about all the By DigitalOcean and A Guide Collection by Igor Fomin at Hackernoon links at the Read More section at the bottom of this article. Then, many of your questions would be answered here.

Let's Go

Docker vs Docker Compose

Docker is an open platform for developing, shipping, and running applications.

  • docker manages single containers.
  • docker compose manages multiple container applications.

Usage of docker compose requires 3 steps:

  1. Define the app environment with a Dockerfile
  2. Define the app services in docker-compose.yml
  3. Run docker compose up to start and run app

(Source: stackoverflow.com/a/50577830/11041841)

Docker Error: HTTP 408 response body: invalid character '<' looking for beginning of value

After installing Docker, I tried docker pull hello-world to test it, but got the error:

Error response from daemon: error parsing HTTP 408 response body: invalid character '<' looking for beginning of value: "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n\n"

The solution (thanks to this StackOverflow answer) was to adjust the MTU.

# sudo ip link set dev [interface] mtu [size]
  sudo ip link set dev eth0 mtu 1400
# In another case:
  sudo ip enp1s0 mtu 1000 up

You can get your device info to choose the [interface] using:

sudo ip a

Docker Error: You have reached your pull rate limit.

Another error I encountered was this. This could have had 2 reasons:

  1. I wasn't logged in to Docker in the CLI.
  2. US Sanctions on Iran.

I live in Iran 🇮🇷. The heavy weight of the US sanctions are inhuman and annoying.

Login to Docker CLI

First try to [signup at docker.com and] login to the Docker CLI (preferably with a token instead of password for better security) using (Source):

docker login

Using DNS Servers

  1. Find a DNS service.
  2. Set the DNS on your Ubuntu.
  3. Login to Docker CLI and try again.
How to Set DNS on Ubuntu

First read askubuntu.com/a/1407182/1636166. if it didn't work, use the following method.

You need to configure the /etc/network/interfaces file if you want to change your DNS server via the command line.

It should look something like this:

# The loopback network interface  
auto lo  
iface lo inet loopback  

# The primary network interface  
auto eth0 
iface eth0 inet static
# iface eth0 inet dhcp
# address 192.168.X.X
# netmask 255.255.255.0
# gateway 192.168.X.X
dns-nameservers X.X.X.X

If you have more than one DNS server, just add a space between each:

dns-nameservers X.X.X.X Y.Y.Y.Y Z.Z.Z.Z

Just replace the Xs, Ys, and Zs with your own IPs of the DNS servers of choice, and when this is done, you can run this command to update the settings (ifconfig, ifdown, ifup are deprecated):

sudo ip link set eth0 down && sudo ip link set eth0 up

# Deprecated version
sudo ifdown eth0 && sudo ifup eth0

Make sure to use these commands in a single line with && to avoid getting stuck out if you're using your system over a network or SSH.

(Source: askubuntu.com/a/346845/1636166 & unix.stackexchange.com/a/50614/554870 & unix.stackexchange.com/a/534879/554870)

From some Docker version on, the Docker Compose command has changed from docker-compose to docker compose, removing the dash.

Starting Docker Compose

There are different commands for this (start, up, run, ...).

In the CLI, go to the folder containing your docker-compose.yml file, then run this to build and run it:

# Start and restart all the services defined in `docker-compose.yml`
docker compose up

# Start and restart all the services defined in `docker-compose.yml` **detached** from the CLI
docker compose up -d

# Only to restart containers that were previously created, but were stopped. It never creates new containers.
docker compose start

# Running `one-off` or `adhoc` tasks.
docker compose run

# If you have new changes on your images or Dockerfiles use (probably after `down` command), to start them again, run:

# To still use image cache
docker compose up --build

# Another version of it (Don't know the difference)
docker compose up --build --force-recreate

# To never use cache
docker compose build --no-cache

The -d option is to start the services detached from the CLI. but If you're running it for the first time, not using this options makes debugging easier, as it shows to logs. If so, you can use Ctrl+C to stop the services.

Together with --force-recreate, you might want to consider using the flag -V too:

-V, --renew-anon-volumes   Recreate anonymous volumes instead of retrieving data from the previous containers.

Stopping the Docker Composer Services

There are different commands for this (pause, stop, down).

down & stop

By current official documentation, down stops and removes containers, networks, volumes, and images created by up, if they are already stopped or partially removed and so on, then it will do the trick too.

Docker Compose down command stops all services associated with a Docker Compose configuration. Unlike stop, it also removes any containers and internal networks associated with the services. But NOT internally specified volumes. To do that as well, you need to additionally specify the -v flag after the down command. (Source)

# Stop services only, but don't remove them
docker compose stop

# Stop and remove containers, networks (optionally images and volumes as well)
docker compose down

# Down and remove volumes (or `-v`)
docker compose down --volumes 

# Down and remove images
docker compose down --rmi <all|local> 

# Delete all containers
`docker rm -f $(docker ps -a -q)`

# Delete all volumes
`docker volume rm $(docker volume ls -q)`

(Source: stackoverflow.com/q/32612650/11041841 & stackoverflow.com/a/61930747/11041841 & linuxhint.com/how-to-clean-up-docker-compos..)

Another method of resetting is (suggested by this StackOverflow answer):

docker compose rm -f
docker compose pull
# docker compose up --build -d
# docker compose stop -t 1

And another one (not tested, suggested by this StackOverflow answer):

docker stop $(docker ps -qa)
docker system prune -af --volumes

Running Commands in the Docker Container's Shell

docker attach will let you connect to your Docker container, but this isn't really the same thing as ssh. If your container is running a webserver, for example, docker attach will probably connect you to the stdout of the web server process. It won't necessarily give you a shell.

To run arbitrary commands inside an existing container (Source):

docker exec -it <container_id> bash

Of course, whatever command you are running must exist in the container filesystem.

In the above command <container_id> is the name or ID of the target container. It doesn't matter whether or not you're using docker compose; just run docker ps and use either the ID (a hexadecimal string displayed in the first column) or the name (displayed in the final column).

docker exec only works on running containers (otherwise use docker run -it --entrypoint /bin/bash or similar).

-it means:

  • -i, --interactive: Keep STDIN open even if not attached.
  • -t,--tty: Allocate a pseudo-TTY.

PHP-fpm

When setting up PHP in my nginx config, I was using the following config, as I normally would without docker:

# Pass PHP scripts to FastCGI server
location ~ \.php$ {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
}

But it gave me an error:

nginx: [emerg] open() "/etc/nginx/snippets/fastcgi-php.conf" failed (2: No such file or directory)

This answer on StackOverflow recommended the following, and it worked:

location ~ \.php$ {
    # NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
    include fastcgi_params;                
    fastcgi_intercept_errors on;
    fastcgi_pass unix:/run/php/php8.1-fpm.sock;
    fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
}

The important part of the answer is changing include snippets/fastcgi-php.conf to include fastcgi_params.

SSL & Certbot

After trying a bit, I finally concluded that for my case, the best way to use HTTPS/SSL on my website it to use the nginx on the host OS, rather than the nginx in the docker container, and then reverse proxy to it.

But here are some useful links:

And when using the certbot --nginx command, I encountered this error:

The requested nginx plugin does not appear to be installed

If you could, install the python3-certbot-nginx package.

sudo apt-get install python3-certbot-nginx

Or you can not use --nginx and manually add the certificates to the nginx config.

(Source: stackoverflow.com/a/64571234/11041841 & github.com/certbot/certbot/issues/1736)

Also Read Nginx and Let’s Encrypt with Docker in Less Than 5 Minutes (pentacent.medium.com).

Little Facts

  • To install packages in the container, we can use the ol' Dockerfile (Source)
  • The Nginx config should not be named default.conf. (Source)

Read More

By DigitalOcean

A Guide Collection by Igor Fomin at Hackernoon

The GitHub Repo: github.com/ikknd/docker-study

GitHub Gists & Repos

Other References