Creating a cheap container and package registry

Creating a cheap container and package registry
Photo by Ian Taylor

Since I was in need of a cheap private container and package registry, I began looking around for good solutions. While I found some, I was not satisfied with the pricing. So I decided to create my own.

Here is how you can host your own container and package registry for free using gitea and a cheap vps. I'm using a 2vCPU 2GB RAM, 40 GB SSD VPS from Netcup for 3,25€/month. While this is not the cheapest VPS you can get, it is still very cheap, and you get a lot of performance for your money.

Hosting

I won't go into detail on how to set up gitea, since there are already a lot of tutorials out there. Also, you should properly secure your server with at least a firewall and fail2ban.

Here is the full docker-compose.yml file I'm using:

version: "3"

services:
reverse - proxy:
image: traefik:v2.7
restart: always
command:
- "--providers.docker=true"
  - "--providers.docker.exposedbydefault=false"
  - "--entrypoints.websecure.address=:443"
  - "--entrypoints.web.address=:80"
  - "--entrypoints.web.http.redirections.entryPoint.to=websecure"
  - "--entrypoints.web.http.redirections.entryPoint.scheme=https"
  - "--entrypoints.web.http.redirections.entrypoint.permanent=true"
  - "--certificatesresolvers.myresolver.acme.dnschallenge=true"
  - "--certificatesresolvers.myresolver.acme.dnschallenge.provider=cloudflare"
  - "--certificatesresolvers.myresolver.acme.dnschallenge.resolvers=8.8.8.8,1.1.1.1"
  - "--certificatesresolvers.myresolver.acme.caserver=https://acme-v02.api.letsencrypt.org/directory"
  - "[email protected]"
  - "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"
ports:
- "80:80"
  - "443:443"
networks:
- traefik
environment:
- "CLOUDFLARE_DNS_API_TOKEN=${CLOUDFLARE_DNS_API_TOKEN}"
volumes:
- "./docker-compose-data/letsencrypt:/letsencrypt"
  - /var/run / docker.sock: /var/run / docker.sock
server:
image: gitea / gitea: 1
container_name: gitea
environment:
- USER_UID=1000
  - USER_GID=1000
restart: always
networks:
- traefik
volumes:
- ./ gitea: /data
  - /etc/timezone: /etc/timezone: ro
    - /etc/localtime: /etc/localtime: ro
labels:
- "traefik.enable=true"
  - "traefik.http.routers.gittea.rule=Host(`your.domain.com`)"
  - "traefik.http.routers.gittea.entrypoints=websecure"
  - "traefik.http.routers.gittea.tls.certresolver=myresolver"
  - "traefik.http.services.gittea.loadbalancer.server.port=3000"
  - "traefik.docker.network=traefik"
watchtower:
image: containrrr / watchtower
volumes:
- /var/run / docker.sock: /var/run / docker.sock
restart: always
networks:
traefik:
name: traefik

As you can see, I'm using traefik as a reverse proxy. Watchtower is used to automatically update the used images. If you take the config as is, you will need to configure traefik with your cloudflare api token or update the challenge and provider. Checkout the traefik docs for that. You should forward port 22 if you want to use gitea as git server too.

Comparison

AWS ECR: ~0.10$/GB/month + data transfer out 0.09$/GB

This is only the container registry. You would have to use something like CodeArtifact to match the features.

GitHub: 0.25$/GB/month + data transfer out 0.50$/GB

For this example I take the literal conversion of 1€ = 1$.

3.25€/month = 3.25$/month

AWS ECR: 0.10$/GB/month * 40GB = 4$/month

GitHub: 0.25$/GB/month * 40GB = 10$/month

And this is only storage. You will also need to pay for data transfer out unless you accept to be vendor locked and even region locked (AWS). I will not calculate this, since it depends on your usage.

Sure you have to manage your own server, but you can also use it for other things. And you can also use it to host your own git server.

Since i'm not using AWS exclusively and don't plan on being locked in on using GitHub Actions, this solution is perfect for me.