{
  "path": "/3mjdpz4ti422b",
  "site": "at://did:plc:nuc33thnsiqzhytkleyr5jek/site.standard.publication/3mjdo3xyaoc2l",
  "tags": [
    "self-hosting",
    "caddy",
    "tailscale",
    "container-registry"
  ],
  "$type": "site.standard.document",
  "title": "Self-hosted container registry with web UI",
  "content": {
    "$type": "pub.leaflet.content",
    "pages": [
      {
        "id": "019d8476-8c22-7220-b994-274411b6faef",
        "$type": "pub.leaflet.pages.linearDocument",
        "blocks": [
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "facets": [
                {
                  "index": {
                    "byteEnd": 51,
                    "byteStart": 8
                  },
                  "features": [
                    {
                      "uri": "https://github.com/Joxit/docker-registry-ui",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                }
              ],
              "plaintext": "Source: https://github.com/Joxit/docker-registry-ui"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.header",
              "level": 2,
              "plaintext": "Docker/Podman compose"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.code",
              "language": "yaml",
              "plaintext": "services:\n  registry-ui:\n    image: joxit/docker-registry-ui:main\n    restart: always\n    ports:\n      - \"127.0.0.1:4433:80\"\n    environment:\n      - SINGLE_REGISTRY=true\n      - REGISTRY_TITLE=hyperreal's Container Registry\n      - DELETE_IMAGES=true\n      - SHOW_CONTENT_DIGEST=true\n      - NGINX_PROXY_PASS_URL=http://registry-server:5000\n      - SHOW_CATALOG_NB_TAGS=true\n      - CATALOG_MIN_BRANCHES=1\n      - CATALOG_MAX_BRANCHES=1\n      - TAGLIST_PAGE_SIZE=100\n      - REGISTRY_SECURED=false\n      - CATALOG_ELEMENTS_LIMIT=1000\n    container_name: registry-ui\n\n  registry-server:\n    image: registry:2.8.2\n    restart: always\n    environment:\n      REGISTRY_HTTP_HEADERS_Access-Control-Allow-Origin: '[http://aux-remote.carp-wyvern.ts.net]'\n      REGISTRY_HTTP_HEADERS_Access-Control-Allow-Methods: '[HEAD,GET,OPTIONS,DELETE]'\n      REGISTRY_HTTP_HEADERS_Access-Control-Allow-Credentials: '[true]'\n      REGISTRY_HTTP_HEADERS_Access-Control-Allow-Headers: '[Accept,Cache-Control]'\n      REGISTRY_HTTP_HEADERS_Access-Control-Expose-Headers: '[Docker-Content-Digest]'\n      REGISTRY_STORAGE_DELETE_ENABLED: 'true'\n    volumes:\n      - ./registry/data:/var/lib/registry\n    container_name: registry-server",
              "syntaxHighlightingTheme": "catppuccin-mocha"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.header",
              "level": 2,
              "plaintext": "Authorization and Authentication"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "plaintext": "For a public registry with authentication, the following headers are required:"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.code",
              "language": "yaml",
              "plaintext": "environment:\n  REGISTRY_HTTP_HEADERS_Access-Control-Allow-Headers: '[Authorization,Accept,Cache-Control]'",
              "syntaxHighlightingTheme": "catppuccin-mocha"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "plaintext": "For a private registry without authentication, the following headers are required:"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.code",
              "language": "yaml",
              "plaintext": "environment:\n  REGISTRY_HTTP_HEADERS_Access-Control-Allow-Headers: '[Accept,Cache-Control]'",
              "syntaxHighlightingTheme": "catppuccin-mocha"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.header",
              "level": 2,
              "plaintext": "Caddy reverse proxy"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.header",
              "level": 3,
              "plaintext": "Public registry"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.code",
              "language": "plaintext",
              "plaintext": "registry.hyperreal.coffee {\n    reverse_proxy localhost:4433\n}",
              "syntaxHighlightingTheme": "catppuccin-mocha"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.header",
              "level": 3,
              "plaintext": "Private registry via Tailnet"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.code",
              "language": "plaintext",
              "plaintext": "aux-remote.carp-wyvern.ts.net {\n    reverse_proxy localhost:4433\n}",
              "syntaxHighlightingTheme": "catppuccin-mocha"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "facets": [
                {
                  "index": {
                    "byteEnd": 56,
                    "byteStart": 33
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#code"
                    }
                  ]
                }
              ],
              "plaintext": "Ensure the following is added to /etc/default/tailscaled:"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.code",
              "language": "shellscript",
              "plaintext": "TS_PERMIT_CERT_UID=caddy",
              "syntaxHighlightingTheme": "catppuccin-mocha"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "plaintext": "The above will ensure Caddy receives SSL certs from the Tailscale daemon."
            }
          }
        ]
      }
    ]
  },
  "description": "",
  "publishedAt": "2026-02-16T02:34:00.000Z"
}