Author: Mathias Lipowski

Build and Release a Flutter App

Updating the app’s version number

To update the version number, navigate to the pubspec.yaml file and update the following line with the current version string:

version: 1.0.0+1

After the change, run:

flutter pub get

Build and release the iOS app

A detailled description of the whole process is described at

To release the iOS app, you use Flutter to build a xcarchive file. This build archive can be published the same way you would do it with Xcode by using the archive manager and one of the different Distribution options.

Build the iOS app:

flutter build ipa

The generated xcarchive file is saved to your app directory under:


Build and release the Android app

A detailled description of the whole process is described at

To release the Android app, you use Flutter to build a app bundle aab file. This file can be distributed by using Google Play Console or any other store.

Build the Android app:

flutter build appbundle

The generated aab app bundle file is saved to your app directory under:


Photo by Artur Shamsutdinov on Unsplash

Ping server on a specific port


You can’t ping ports, as Ping is using ICMP which doesn’t have the concept of ports. Ports belong to the transport layer protocols like TCP and UDP. However, you could use nmap to see whether ports are open or not:

nmap -p 80

The output will look like this:

nmap -p 80
Starting Nmap 7.92 ( ) at 2021-12-08 10:59 CET
Nmap scan report for (
Host is up (0.017s latency).
rDNS record for

80/tcp open  http

Nmap done: 1 IP address (1 host up) scanned in 0.09 seconds


How to Run and Update Docker Images and Containers

The following text shows the default workflow to run and update a Docker image based on the example of GitLab. But this should also work for other containers.

Docker Installation

First make sure that your local machine has Docker installed. I use Debian and for this, a detailed description is available in Dockers documentation. There are also instructions for CentOS, Ubuntu, Fedora and others.

You can check the installed Docker version:

docker version
Client: Docker Engine - Community
 Version:           20.10.11
 API version:       1.41

Run a Docker Container

Let’s start with an environment variable that defines the path where all the Gitlab data is stored. This is outside of the Docker container which allows an easy update without loosing data. To define the variable $GITLAB_HOME, you can use:

export GITLAB_HOME="/srv/gitlab"

To run a Docker container, simply use the run command with your parameters. For GitLab, this might look like:

docker run --detach
  --hostname <>
  --publish 443:443 --publish 80:80 --publish 2222:22
  --name gitlab
  --restart always  
  --volume $GITLAB_HOME/config:/etc/gitlab 
  --volume $GITLAB_HOME/logs:/var/log/gitlab
  --volume $GITLAB_HOME/data:/var/opt/gitlab

You should use your own settings and replace <> with your setup.

For the sake of completeness, you might also need a runner for GitLab. Let’s run this container as well:

docker run --detach 
  --name gitlab_runner
  --restart always 
  --network host 
  -v /run/docker.sock:/var/run/docker.sock 

And this one needs to be registered in your GitLab instance:

docker exec -it gitlab_runner gitlab-runner register 
  --url https://<>/
  --registration-token <registration_token>

More details about the configuration of the GitLab runner is descriped in this post.

Update a Docker Container to the Latest Version

Let’s check, which container are running by using:

docker ps

The output shows all your containers and their ids:

CONTAINER ID   IMAGE                         COMMAND                  CREATED       STATUS                 NAMES
02fe426970f1   gitlab/gitlab-ce:latest       "/assets/wrapper"        4 hours ago   Up 4 hours (healthy)   gitlab
5742e07f809b   gitlab/gitlab-runner:latest   "/usr/bin/dumb-init …"   4 days ago    Up 5 hours             gitlab_runner

We have to stop the container and remove the image. When you used a run command (for GitLab) as shown above, this should not affect the data as this is stored outside of the container.

docker stop 02fe426970f1
docker rm 02fe426970f1

To remove the associated image, you can use the docker rmi. For this, we need to find the id of this image by listing all images:

docker images
REPOSITORY         TAG      IMAGE ID       CREATED        SIZE
gitlab/gitlab-ce   latest   46cd6954564a   17 hours ago   2.36GB
mysql              5.7      c20987f18b13   2 weeks ago    448MB
cirrusci/flutter   2.8.1    98a87781f179   2 weeks ago    3.49GB

Now we can remove the image (in my case the gitlab-ce image):

docker rmi 46cd6954564a

The update of the image can be done by using pull. This will download the images (in this case the latest version) and stores it on your system:

docker pull gitlab/gitlab-ce:latest

After this, you can use the same run command as before to run a container with the updated image:

docker run --detach
  --hostname <>
  --publish 443:443 --publish 80:80 --publish 2222:22
  --name gitlab
  --restart always  
  --volume $GITLAB_HOME/config:/etc/gitlab 
  --volume $GITLAB_HOME/logs:/var/log/gitlab
  --volume $GITLAB_HOME/data:/var/opt/gitlab

A final check, shows the container is up and running:

docker ps
CONTAINER ID   IMAGE                         COMMAND                  CREATED        STATUS                 NAMES
f3dab1163c07   gitlab/gitlab-ce:latest       "/assets/wrapper"        2 minutes ago  Up 4 hours (healthy)   gitlab
5742e07f809b   gitlab/gitlab-runner:latest   "/usr/bin/dumb-init …"   4 days ago     Up 5 hours             gitlab_runner

Instead of automatically using the latest version of each image (e.g. gitlab/gitlab-ce:latest) you can also specify a version number like gitlab/gitlab-ce:14.5.2. This is helpful when you need to update a system in steps. Or if you need to follow a specific upgrade path, which is the case for GitLab.

Photo by Ian Taylor on Unsplash.

How to simply analyze access logs of web servers

There is a tool for that: GoAccess. It’s an easy to use command line tool to analyze any access log and create beautiful insights.


On macOS you can use HomeBrew to install GoAccess:

brew install goaccess

For other operation systems, please check out the detailed documentation on their website.


The most elegant way is the terminal output. For this, simply type:

 goaccess access.log --log-format=COMBINED

Which creates such an output (you can navigate down to see much more details):

You can also create an html file that you can view in your browser:

goaccess access.last.log -o report.last.html --log-format=COMBINED

And voilà:

To learn more about all options, you can check out the documentation of GoAccess.

Photo by Aryan Dhiman on Unsplash.

Dart: code snippets for faster coding

There are different concepts that improve the data handling in Dart. The following list of snippets is a collection of the most handy once. Warning: this might simplify your code a lot! 😉

The Spread Operator

Dart supports the spread operator, which allows to insert a collection (multiple elements) into a collection:

var values = [1, 2, 3];
var moreValues = [...values, 4, 5, 6];
// [1, 2, 3, 4, 5, 6]


Dart supports different operators. You can implement many of these operators as class members.

unary postfixexpr++    expr--    ()    []    .    ?.
unary prefix-expr    !expr    ~expr    ++expr    --expr      await expr 
multiplicative*    /    %  ~/
additive+    -
shift<<    >>    >>>
bitwise AND&
bitwise XOR^
bitwise OR|
relational and type test>=    >    <=    <    as    is    is!
equality==    !=
logical AND&&
logical OR||
conditionalexpr1 ? expr2 : expr3
cascade..    ?..
assignment=    *=    /=   +=   -=   &=   ^=   etc.

Merging Two Maps

The code snippet below merges two maps. All (key) values in default are available in the merged map. This snippet only works for single level maps, multidimensional maps are only handled on the first level:

var options = {
    "hidden": "false",
    "option": "3",
var defaults = {
    "hidden": "true",
    "escape": "false",
options = {...defaults, ...options};
// {hidden: false, escape: false, option: 3}

Default Value

To set a default value for a nullable variable, you can use the “if null” operator ‘??’:

const defaultValue = "Default";
final someVar = null;
var expectingValue = someVar ?? defaultValue;
// "Default"

if and for in Collections

Dart offers an easy way to create dynamic lists by using conditionals (if) and repetition (for):

var nav = [
  if (promoActive) 'Outlet'
var listOfInts = [1, 2, 3];
var listOfStrings = [
  for (var i in listOfInts) '#$i'
assert(listOfStrings[1] == '#1');

String to Number

var stringValue = "123";
var intValue = int.parse(stringValue);
// 123 (int)
var stringValue = "123.45";
var doubleValue = double.parse(stringValue);
// 123.45 (double)

Numbers to String

Most of the Dart data types support a toString() method, which allows a conversion to strings. This is very handy for every parameter where a string is needed:

int intValue = 123;
var stringValue = intValue.toString();
// "123" (string)

GitLab – ERROR: Registering runner… failed, certificate signed by unknown authority

If your self-hosted GitLab server is using a self-signed certificate for https, it might be possible that you get an error during the registration of a GitLab Runner:

ERROR: Registering runner... failed        runner=HbU25D-y status=couldn't execute POST against Post x509: certificate signed by unknown authority
PANIC: Failed to register the runner. You may be having network problems.

To solve the problem, you have to provide the full chain certificate *.pem used by your GitLab Server:

gitlab-runner register --tls-ca-file /path/to/fullchain.pem

In my case, the valid certificate could be found on the GitLab server in /etc/gitlab/trusted-certs/fullchain.pem. This one was copied to the GitLab Runner server and used in the command above.

As I did not set up the server on my own, I do not know if this is the default path and filename of a certificate signed by Let’s Encrypt. But in my case, this one worked to register the runner.

Which programming language is the best one?

Is it really possible to answer this question?

Yes, the correct answer is: all of them. Or let’s ask another question first: for which problem?

There is not “the one and only” best programming language, there are tons. This question is simply not a good one. It’s good for endless discussion, but it’s neither complete, nor does it give you details about the problem to solve. An answer will not solve the unknown problem of the author. Every coding language has it advantages when it comes to solving a specific problem. But which one? There are advantages for JavaScript, Python, PHP, Java, Swift, Dart and others. But what if the author wants to write some firmware for a micro controller? Ok, you see the point.

But why do people ask those questions?

I see a lot of such questions posted on all social platforms. And as those questions are so incomplete, there are no correct answers. The results are endless discussions about the advantages of each coding language. And this is what most of the authors want: an open question which leads to endless attention. In detail: likes and retweets to pretend the algorithms to be an interesting account. Honestly, no one reads through thousands of responses. And if yes, you only see the advantages that each comfortable developer or user sees in his area of expertise. This might lead to some short attention, but it will never create some high quality and valuable content fo the users. And that’s a pity.

And what about: iOS or Android? Windows or macOS? Python or JavaScript? Same thing! The answers are just a time wasting mess.

Photo by Donald Giannatti on Unsplash.

Flutter: rounded corners for images

There are different possibilities to create a rounded corner of images:


  borderRadius: BorderRadius.circular(10.0),
    height: 100.0,
    width: 100.0,


  height: 100.0,
  width: 100.0,
  decoration: BoxDecoration(
    image: DecorationImage(
      fit: BoxFit.cover, 
      image: NetworkImage(''),
    borderRadius: BorderRadius.circular(10.0),

Photo by Chaitanya Tvs on Unsplash