fix registry link
This commit is contained in:
@@ -5,6 +5,7 @@ PUBLIC_SITE_DOMAIN=example.com
|
|||||||
PGMANAGE_DOMAIN=pgmanage.example.com
|
PGMANAGE_DOMAIN=pgmanage.example.com
|
||||||
PORTAINER_DOMAIN=portainer.example.com
|
PORTAINER_DOMAIN=portainer.example.com
|
||||||
REGISTRY_DOMAIN=registry.rentaldrivego.ma
|
REGISTRY_DOMAIN=registry.rentaldrivego.ma
|
||||||
|
REGISTRY_UPSTREAM_URL=http://10.0.0.10:5000
|
||||||
|
|
||||||
# ── Optional prebuilt image source ────────────────────────────────────────────
|
# ── Optional prebuilt image source ────────────────────────────────────────────
|
||||||
# Used for pull-based deployments. CI injects APP_IMAGE and APP_VERSION
|
# 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_USER=rentaldrivego_registry
|
||||||
REGISTRY_PASSWORD=PMPS5k0D7rUeJOk0NkhI5bRtoGjkUqjK
|
REGISTRY_PASSWORD=PMPS5k0D7rUeJOk0NkhI5bRtoGjkUqjK
|
||||||
REGISTRY_IMAGE=registry.rentaldrivego.ma/rentaldrivego/car_management_system
|
REGISTRY_IMAGE=registry.rentaldrivego.ma/rentaldrivego/car_management_system
|
||||||
|
REGISTRY_HTTP_SECRET=PMPS5k0D7rUeJOk0NkhI5bRtoGjkUqjK
|
||||||
|
|
||||||
# ── Database ──────────────────────────────────────────────────────────────────
|
# ── Database ──────────────────────────────────────────────────────────────────
|
||||||
# Full connection URL (used when DATABASE_URL_FROM_POSTGRES=false)
|
# Full connection URL (used when DATABASE_URL_FROM_POSTGRES=false)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ PUBLIC_SITE_DOMAIN=example.com
|
|||||||
PGMANAGE_DOMAIN=pgmanage.example.com
|
PGMANAGE_DOMAIN=pgmanage.example.com
|
||||||
PORTAINER_DOMAIN=portainer.example.com
|
PORTAINER_DOMAIN=portainer.example.com
|
||||||
REGISTRY_DOMAIN=registry.example.com
|
REGISTRY_DOMAIN=registry.example.com
|
||||||
|
REGISTRY_UPSTREAM_URL=http://10.0.0.10:5000
|
||||||
|
|
||||||
# Database
|
# Database
|
||||||
DATABASE_URL_FROM_POSTGRES=true
|
DATABASE_URL_FROM_POSTGRES=true
|
||||||
|
|||||||
+3
-3
@@ -147,10 +147,10 @@ deploy_to_vps:
|
|||||||
echo "-- Syncing deployment assets --"
|
echo "-- Syncing deployment assets --"
|
||||||
ssh $VPS_USER@$VPS_IP "
|
ssh $VPS_USER@$VPS_IP "
|
||||||
set -e
|
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 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 $VPS_USER@$VPS_IP:$DEPLOY_ROOT/scripts/
|
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/
|
scp docker/pgmanage/override.py $VPS_USER@$VPS_IP:$DEPLOY_ROOT/docker/pgmanage/
|
||||||
|
|
||||||
echo "-- Running deploy script on VPS --"
|
echo "-- Running deploy script on VPS --"
|
||||||
|
|||||||
@@ -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:
|
||||||
+34
-6
@@ -8,6 +8,7 @@ Three Docker environments are available:
|
|||||||
- `docker-compose.pgmanage.yml` for a standalone pgManage container
|
- `docker-compose.pgmanage.yml` for a standalone pgManage container
|
||||||
- `docker-compose.portainer.production.yml` for a standalone production Portainer deployment behind Traefik
|
- `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.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
|
### 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`.
|
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 `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 `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://<local-registry-server-ip>: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`:
|
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
|
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://<local-registry-server-ip>: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
|
```bash
|
||||||
npm run docker:prod:start:registry
|
npm run docker:registry:local:start
|
||||||
```
|
```
|
||||||
|
|
||||||
Equivalent raw Docker Compose command:
|
Equivalent raw Docker Compose command:
|
||||||
|
|
||||||
```bash
|
```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://<local-registry-server-ip>: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
|
```bash
|
||||||
docker login registry.rentaldrivego.ma
|
docker login registry.rentaldrivego.ma
|
||||||
|
|||||||
@@ -35,6 +35,7 @@
|
|||||||
"docker:prod:start:pgmanage": "bash scripts/docker-prod-up-pgmanage.sh",
|
"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:portainer": "bash scripts/docker-prod-up-portainer.sh",
|
||||||
"docker:prod:start:registry": "bash scripts/docker-prod-up-registry.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:deploy": "bash scripts/docker-prod-deploy.sh",
|
||||||
"docker:prod:up": "bash scripts/docker-prod-up-all.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",
|
"docker:prod:down": "docker compose -p rentaldrivego-prod --env-file .env.docker.production -f docker-compose.production.yml down",
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ PORTAINER_COMPOSE_FILE="${ROOT_DIR}/docker-compose.portainer.production.yml"
|
|||||||
REGISTRY_COMPOSE_FILE="${ROOT_DIR}/docker-compose.registry.production.yml"
|
REGISTRY_COMPOSE_FILE="${ROOT_DIR}/docker-compose.registry.production.yml"
|
||||||
TRAEFIK_COMPOSE_FILE="${ROOT_DIR}/traefik.yaml"
|
TRAEFIK_COMPOSE_FILE="${ROOT_DIR}/traefik.yaml"
|
||||||
ENV_FILE="${ROOT_DIR}/.env.docker.production"
|
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}"
|
PROJECT_NAME="${DOCKER_PROD_PROJECT_NAME:-rentaldrivego-prod}"
|
||||||
PORTAINER_PROJECT_NAME="${DOCKER_PORTAINER_PROJECT_NAME:-rentaldrivego-portainer-prod}"
|
PORTAINER_PROJECT_NAME="${DOCKER_PORTAINER_PROJECT_NAME:-rentaldrivego-portainer-prod}"
|
||||||
REGISTRY_PROJECT_NAME="${DOCKER_REGISTRY_PROJECT_NAME:-rentaldrivego-registry-prod}"
|
REGISTRY_PROJECT_NAME="${DOCKER_REGISTRY_PROJECT_NAME:-rentaldrivego-registry-prod}"
|
||||||
@@ -39,6 +41,10 @@ ensure_api_uploads_volume() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ensure_dynamic_dir() {
|
||||||
|
mkdir -p "${DYNAMIC_DIR}"
|
||||||
|
}
|
||||||
|
|
||||||
prod_compose() {
|
prod_compose() {
|
||||||
docker compose -p "${PROJECT_NAME}" --env-file "${ENV_FILE}" -f "${PROD_COMPOSE_FILE}" "$@"
|
docker compose -p "${PROJECT_NAME}" --env-file "${ENV_FILE}" -f "${PROD_COMPOSE_FILE}" "$@"
|
||||||
}
|
}
|
||||||
@@ -149,6 +155,38 @@ start_portainer() {
|
|||||||
portainer_compose up -d
|
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}" <<EOF
|
||||||
|
http:
|
||||||
|
routers:
|
||||||
|
registry:
|
||||||
|
rule: Host(\`${REGISTRY_DOMAIN}\`)
|
||||||
|
entryPoints:
|
||||||
|
- websecure
|
||||||
|
tls:
|
||||||
|
certResolver: letsencrypt
|
||||||
|
service: registry-upstream
|
||||||
|
|
||||||
|
services:
|
||||||
|
registry-upstream:
|
||||||
|
loadBalancer:
|
||||||
|
servers:
|
||||||
|
- url: "${REGISTRY_UPSTREAM_URL}"
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
ensure_registry_auth_file() {
|
ensure_registry_auth_file() {
|
||||||
mkdir -p "${REGISTRY_AUTH_DIR}"
|
mkdir -p "${REGISTRY_AUTH_DIR}"
|
||||||
|
|
||||||
@@ -176,6 +214,7 @@ start_registry() {
|
|||||||
start_traefik() {
|
start_traefik() {
|
||||||
ensure_env_file
|
ensure_env_file
|
||||||
ensure_traefik_network
|
ensure_traefik_network
|
||||||
|
render_registry_proxy_config
|
||||||
traefik_compose up -d
|
traefik_compose up -d
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
ENV_FILE="${ROOT_DIR}/.env.docker.production"
|
||||||
|
COMPOSE_FILE="${ROOT_DIR}/docker-compose.registry.local.yml"
|
||||||
|
AUTH_DIR="${ROOT_DIR}/docker/registry/auth"
|
||||||
|
AUTH_FILE="${AUTH_DIR}/htpasswd"
|
||||||
|
|
||||||
|
if [[ ! -f "${ENV_FILE}" ]]; then
|
||||||
|
echo "Missing ${ENV_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."
|
||||||
Reference in New Issue
Block a user