From a9305fa4a29b8bc899f7d88527492dd23e8f1a0c Mon Sep 17 00:00:00 2001 From: root Date: Tue, 2 Jun 2026 15:17:09 -0400 Subject: [PATCH] fix registry link --- .env.docker.production.example | 2 ++ .env.docker.production.generated | 1 + .gitlab-ci.yml | 6 ++--- docker-compose.registry.local.yml | 22 ++++++++++++++++ docs/DOCKER.md | 40 ++++++++++++++++++++++++----- package.json | 1 + scripts/docker-prod-common.sh | 39 ++++++++++++++++++++++++++++ scripts/docker-registry-local-up.sh | 32 +++++++++++++++++++++++ 8 files changed, 134 insertions(+), 9 deletions(-) create mode 100644 docker-compose.registry.local.yml create mode 100644 scripts/docker-registry-local-up.sh diff --git a/.env.docker.production.example b/.env.docker.production.example index ffb13ea..7c39185 100644 --- a/.env.docker.production.example +++ b/.env.docker.production.example @@ -5,6 +5,7 @@ PUBLIC_SITE_DOMAIN=example.com PGMANAGE_DOMAIN=pgmanage.example.com PORTAINER_DOMAIN=portainer.example.com REGISTRY_DOMAIN=registry.rentaldrivego.ma +REGISTRY_UPSTREAM_URL=http://10.0.0.10:5000 # ── Optional prebuilt image source ──────────────────────────────────────────── # Used for pull-based deployments. CI injects APP_IMAGE and APP_VERSION @@ -15,6 +16,7 @@ REGISTRY_HOST=registry.rentaldrivego.ma REGISTRY_USER=rentaldrivego_registry REGISTRY_PASSWORD=PMPS5k0D7rUeJOk0NkhI5bRtoGjkUqjK REGISTRY_IMAGE=registry.rentaldrivego.ma/rentaldrivego/car_management_system +REGISTRY_HTTP_SECRET=PMPS5k0D7rUeJOk0NkhI5bRtoGjkUqjK # ── Database ────────────────────────────────────────────────────────────────── # Full connection URL (used when DATABASE_URL_FROM_POSTGRES=false) diff --git a/.env.docker.production.generated b/.env.docker.production.generated index 42ad5b3..dac62b6 100644 --- a/.env.docker.production.generated +++ b/.env.docker.production.generated @@ -5,6 +5,7 @@ PUBLIC_SITE_DOMAIN=example.com PGMANAGE_DOMAIN=pgmanage.example.com PORTAINER_DOMAIN=portainer.example.com REGISTRY_DOMAIN=registry.example.com +REGISTRY_UPSTREAM_URL=http://10.0.0.10:5000 # Database DATABASE_URL_FROM_POSTGRES=true diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index cd7d4b5..51a6917 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -147,10 +147,10 @@ deploy_to_vps: echo "-- Syncing deployment assets --" ssh $VPS_USER@$VPS_IP " set -e - mkdir -p '$DEPLOY_ROOT/scripts' '$DEPLOY_ROOT/docker/pgmanage' '$DEPLOY_ROOT/docker/registry/auth' + mkdir -p '$DEPLOY_ROOT/scripts' '$DEPLOY_ROOT/docker/pgmanage' '$DEPLOY_ROOT/docker/registry/auth' '$DEPLOY_ROOT/dynamic' " - scp docker-compose.production.yml docker-compose.portainer.production.yml docker-compose.registry.production.yml traefik.yaml $VPS_USER@$VPS_IP:$DEPLOY_ROOT/ - scp scripts/docker-prod-common.sh scripts/docker-prod-deploy.sh scripts/docker-prod-up-registry.sh $VPS_USER@$VPS_IP:$DEPLOY_ROOT/scripts/ + scp docker-compose.production.yml docker-compose.portainer.production.yml docker-compose.registry.production.yml docker-compose.registry.local.yml traefik.yaml $VPS_USER@$VPS_IP:$DEPLOY_ROOT/ + scp scripts/docker-prod-common.sh scripts/docker-prod-deploy.sh scripts/docker-prod-up-registry.sh scripts/docker-registry-local-up.sh $VPS_USER@$VPS_IP:$DEPLOY_ROOT/scripts/ scp docker/pgmanage/override.py $VPS_USER@$VPS_IP:$DEPLOY_ROOT/docker/pgmanage/ echo "-- Running deploy script on VPS --" diff --git a/docker-compose.registry.local.yml b/docker-compose.registry.local.yml new file mode 100644 index 0000000..1b1b2c3 --- /dev/null +++ b/docker-compose.registry.local.yml @@ -0,0 +1,22 @@ +name: rentaldrivego-registry-local + +services: + registry: + image: registry:2 + restart: unless-stopped + ports: + - 5000:5000 + environment: + REGISTRY_HTTP_ADDR: 0.0.0.0:5000 + REGISTRY_HTTP_RELATIVEURLS: "true" + REGISTRY_HTTP_SECRET: ${REGISTRY_HTTP_SECRET:-change-me} + REGISTRY_AUTH: htpasswd + REGISTRY_AUTH_HTPASSWD_REALM: Registry Realm + REGISTRY_AUTH_HTPASSWD_PATH: /auth/htpasswd + REGISTRY_STORAGE_DELETE_ENABLED: "true" + volumes: + - registry_local_data:/var/lib/registry + - ./docker/registry/auth:/auth:ro + +volumes: + registry_local_data: diff --git a/docs/DOCKER.md b/docs/DOCKER.md index ae589dc..3c5cf5a 100644 --- a/docs/DOCKER.md +++ b/docs/DOCKER.md @@ -8,6 +8,7 @@ Three Docker environments are available: - `docker-compose.pgmanage.yml` for a standalone pgManage container - `docker-compose.portainer.production.yml` for a standalone production Portainer deployment behind Traefik - `docker-compose.registry.production.yml` for a standalone production Docker registry behind Traefik +- `docker-compose.registry.local.yml` for a Docker registry running on a separate local server with port `5000` exposed directly ### Development @@ -165,7 +166,8 @@ Production now derives `DATABASE_URL` inside the app container from `POSTGRES_HO The example file uses `rentaldrivego.ma` for the marketplace and public site. The dashboard and admin panel are routed under that same host at `/dashboard` and `/admin`. Set `PORTAINER_DOMAIN=portainer.rentaldrivego.ma` in `.env.docker.production` to expose Portainer through Traefik. Set `PGMANAGE_DOMAIN=pgmanage.rentaldrivego.ma` to expose pgManage through Traefik, and set `PGMANAGE_LICENSE_KEY` if you are running the enterprise image. -Set `REGISTRY_DOMAIN=registry.rentaldrivego.ma` to expose the local Docker registry through Traefik. +Set `REGISTRY_DOMAIN=registry.rentaldrivego.ma` to expose the Docker registry through Traefik. +Set `REGISTRY_UPSTREAM_URL=http://:5000` on the VPS when the registry itself runs on a different server and Traefik should reverse-proxy to it. If you want to use a self-hosted registry on the same VPS, also set these values in `.env.docker.production`: @@ -265,21 +267,47 @@ Equivalent raw Docker Compose command: docker compose -p rentaldrivego-portainer-prod --env-file .env.docker.production -f docker-compose.portainer.production.yml up -d ``` -#### 6b. Deploy the local registry +#### 6b. Deploy the registry on a separate local server -The registry is deployed separately from the main app stack and reuses the shared `traefik-proxy` network managed by Traefik. +For the split setup: + +1. Run the registry on your local server with port `5000` exposed directly. +2. Set `REGISTRY_UPSTREAM_URL` on the VPS to `http://:5000`. +3. Restart Traefik on the VPS so it renders the dynamic registry upstream file and serves TLS for `REGISTRY_DOMAIN`. + +On the local registry server: ```bash -npm run docker:prod:start:registry +npm run docker:registry:local:start ``` Equivalent raw Docker Compose command: ```bash -docker compose -p rentaldrivego-registry-prod --env-file .env.docker.production -f docker-compose.registry.production.yml up -d +docker compose -p rentaldrivego-registry-local --env-file .env.docker.production -f docker-compose.registry.local.yml up -d ``` -On first start, the script generates `docker/registry/auth/htpasswd` from `REGISTRY_USER` and `REGISTRY_PASSWORD` in `.env.docker.production`. After the registry is up, verify it with: +On first start, the script generates `docker/registry/auth/htpasswd` from `REGISTRY_USER` and `REGISTRY_PASSWORD` in `.env.docker.production`. + +From the VPS, verify the upstream directly before involving Traefik: + +```bash +curl -I http://:5000/v2/ +``` + +Expected response: + +```text +HTTP/1.1 401 Unauthorized +``` + +Then on the VPS restart Traefik: + +```bash +bash scripts/docker-prod-up-traefik.sh +``` + +After that, verify the public route and login flow: ```bash docker login registry.rentaldrivego.ma diff --git a/package.json b/package.json index 9cbc31f..622656a 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "docker:prod:start:pgmanage": "bash scripts/docker-prod-up-pgmanage.sh", "docker:prod:start:portainer": "bash scripts/docker-prod-up-portainer.sh", "docker:prod:start:registry": "bash scripts/docker-prod-up-registry.sh", + "docker:registry:local:start": "bash scripts/docker-registry-local-up.sh", "docker:prod:deploy": "bash scripts/docker-prod-deploy.sh", "docker:prod:up": "bash scripts/docker-prod-up-all.sh", "docker:prod:down": "docker compose -p rentaldrivego-prod --env-file .env.docker.production -f docker-compose.production.yml down", diff --git a/scripts/docker-prod-common.sh b/scripts/docker-prod-common.sh index 76e200f..060fa52 100755 --- a/scripts/docker-prod-common.sh +++ b/scripts/docker-prod-common.sh @@ -8,6 +8,8 @@ PORTAINER_COMPOSE_FILE="${ROOT_DIR}/docker-compose.portainer.production.yml" REGISTRY_COMPOSE_FILE="${ROOT_DIR}/docker-compose.registry.production.yml" TRAEFIK_COMPOSE_FILE="${ROOT_DIR}/traefik.yaml" ENV_FILE="${ROOT_DIR}/.env.docker.production" +DYNAMIC_DIR="${ROOT_DIR}/dynamic" +REGISTRY_DYNAMIC_FILE="${DYNAMIC_DIR}/registry-upstream.yml" PROJECT_NAME="${DOCKER_PROD_PROJECT_NAME:-rentaldrivego-prod}" PORTAINER_PROJECT_NAME="${DOCKER_PORTAINER_PROJECT_NAME:-rentaldrivego-portainer-prod}" REGISTRY_PROJECT_NAME="${DOCKER_REGISTRY_PROJECT_NAME:-rentaldrivego-registry-prod}" @@ -39,6 +41,10 @@ ensure_api_uploads_volume() { fi } +ensure_dynamic_dir() { + mkdir -p "${DYNAMIC_DIR}" +} + prod_compose() { docker compose -p "${PROJECT_NAME}" --env-file "${ENV_FILE}" -f "${PROD_COMPOSE_FILE}" "$@" } @@ -149,6 +155,38 @@ start_portainer() { portainer_compose up -d } +render_registry_proxy_config() { + ensure_dynamic_dir + + if [[ -z "${REGISTRY_DOMAIN:-}" && -z "${REGISTRY_UPSTREAM_URL:-}" ]]; then + rm -f "${REGISTRY_DYNAMIC_FILE}" + return 0 + fi + + if [[ -z "${REGISTRY_DOMAIN:-}" || -z "${REGISTRY_UPSTREAM_URL:-}" ]]; then + echo "REGISTRY_DOMAIN and REGISTRY_UPSTREAM_URL must either both be set or both be unset." >&2 + exit 1 + fi + + cat > "${REGISTRY_DYNAMIC_FILE}" <&2 + exit 1 +fi + +set -a +source "${ENV_FILE}" +set +a + +mkdir -p "${AUTH_DIR}" + +if [[ -n "${REGISTRY_USER:-}" && -n "${REGISTRY_PASSWORD:-}" ]]; then + docker run --rm --entrypoint htpasswd httpd:2-alpine -Bbn "${REGISTRY_USER}" "${REGISTRY_PASSWORD}" > "${AUTH_FILE}" + chmod 600 "${AUTH_FILE}" +elif [[ ! -f "${AUTH_FILE}" ]]; then + echo "Set REGISTRY_USER and REGISTRY_PASSWORD in ${ENV_FILE} or create ${AUTH_FILE} manually." >&2 + exit 1 +fi + +docker compose -p rentaldrivego-registry-local --env-file "${ENV_FILE}" -f "${COMPOSE_FILE}" up -d + +echo "Local registry is starting on port 5000."