The problem

AWS ECR is a pretty decent solution to host your docker images. I like it because you can use AWS Cognito to define what users can fetch what image from your private ECR repository. It also has a nice cost-effective pricing model.

What I don’t like is that those private repositories looks ugly when you reference them in your docker-compose.yml file:

services:
  my-service:
    image: 123456789012.dkr.ecr.eu-central-1.amazonaws.com/my-repo:latest

Firstly, I don’t like that it’s bind to the particular AWS account ID. Imagine creating a new AWS account and moving the repository there.

Also, what if, in the future, you decide to go with another docker repository provider? You would need to change the URL in all places where it’s used.

If you’re talking about a web application you host on the environment you fully control - it might not be as much of a problem. However, consider having multiple many devices deployed with your dockerized application that are installed on the customer site, and you need to update them all…

The solution

The solution is to use your custom domain that will be a proxy to the AWS ECR repository. This way you can change the AWS Account, region or even the repository provider and update it only in a single place - your proxy.

How to do it

I already have my NGINX server that is used as a reverse proxy for other services, so I decided to add the Docker proxy to it. Here is the sample config file:


server {
    server_name docker.mycustomdomain.pl;
    listen 443;
    chunked_transfer_encoding on;
    client_max_body_size 0;

    ssl_dhparam /dhparams4096.pem;
    ssl_session_timeout 1d;
    ssl_session_cache shared:MozSSL:10m;
    ssl_session_tickets off;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;

    ssl_certificate /cert.pem;
    ssl_certificate_key /key.pem;

    ssl_early_data on;

    ssl_stapling on;
    ssl_stapling_verify on;

    location / {
      proxy_set_header Host 123456789012.dkr.ecr.eu-central-1.amazonaws.com;
      proxy_set_header X-Forwarded-Host $host;
      proxy_pass https://123456789012.dkr.ecr.eu-central-1.amazonaws.com;
    }
}

In this case I do use the Let’s Encrypt wildcard certificate for *.mycustomdomain.pl and the redirect from HTTP to HTTPS is done in another (default.conf) config file. You can adjust to your needs.

Usage

You can login using your new proxy:

aws ecr get-login-password --region eu-central-1 | docker login --username AWS --password-stdin https://docker.mycustomdomain.pl

…and that’s how you can define your image now in the docker-compose.yml file:

services:
  my-service:
    image: docker.mycustomdomain.pl/my-repo:latest

Useful resources