181 lines
5.4 KiB
Markdown
181 lines
5.4 KiB
Markdown
# Unprivileged Nginx Redirect Docker Image
|
|
|
|
[](https://ci.mrose.cloud/vincent/redirect)
|
|
|
|
A lightweight, secure, and reusable Docker image based on `nginxinc/nginx-unprivileged:alpine-slim` designed to redirect HTTP requests to any configurable target domain/path with customizable HTTP status codes.
|
|
|
|
It is designed to be built via **Drone CI** directly onto the host server's Docker daemon, allowing multiple containers to run on the host system using the single tagged image.
|
|
|
|
---
|
|
|
|
## Features
|
|
|
|
- **Ultra-Lightweight & Secure**: Based on `nginxinc/nginx-unprivileged:alpine-slim` (~12 MB), running as non-root user (UID 101).
|
|
- **Environment Variable Configuration**: Leverages native Nginx startup template rendering (`envsubst`).
|
|
- **Path & Query String Preservation**: Support for preserving request paths (e.g. `$request_uri`).
|
|
- **Built-in Health Checks**:`/healthz` endpoint returns `200 OK` for orchestrator probe support without triggering a redirect.
|
|
- **Drone CI Host Integration**: Pipeline builds directly onto the host machine's Docker engine via host Docker socket binding (`/var/run/docker.sock`).
|
|
|
|
---
|
|
|
|
## Environment Variables
|
|
|
|
| Variable | Default Value | Description |
|
|
| :--- | :--- | :--- |
|
|
| `REDIRECT_TARGET` | `https://example.com` | Target URL or domain for redirection. Add `$request_uri` to preserve path & query parameters. |
|
|
| `REDIRECT_CODE` | `301` | HTTP status code for redirection (e.g. `301`, `302`, `307`, `308`). |
|
|
| `LISTEN_PORT` | `8080` | Internal HTTP listening port (unprivileged standard). |
|
|
|
|
---
|
|
|
|
## Drone CI Integration
|
|
|
|
The included `.drone.yml` pipeline mounts the host Docker socket (`/var/run/docker.sock`) into a `docker:cli` container step. This builds and tags the image directly on the host host's Docker daemon.
|
|
|
|
```yaml
|
|
kind: pipeline
|
|
type: docker
|
|
name: build-host-redirect-image
|
|
|
|
steps:
|
|
- name: build-and-tag-host-image
|
|
image: docker:cli
|
|
volumes:
|
|
- name: dockersock
|
|
path: /var/run/docker.sock
|
|
commands:
|
|
- docker build --pull -t redirect:latest .
|
|
- |
|
|
if [ -n "$DRONE_COMMIT_SHA" ]; then
|
|
SHORT_SHA=$(echo $DRONE_COMMIT_SHA | cut -c1-7)
|
|
docker tag redirect:latest redirect:$SHORT_SHA
|
|
fi
|
|
- |
|
|
if [ -n "$DRONE_TAG" ]; then
|
|
docker tag redirect:latest redirect:$DRONE_TAG
|
|
fi
|
|
- |
|
|
apk add --no-cache git 2>/dev/null || true
|
|
git fetch --tags 2>/dev/null || true
|
|
LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || true)
|
|
if [ -n "$LATEST_TAG" ]; then
|
|
docker tag redirect:latest redirect:$LATEST_TAG
|
|
fi
|
|
|
|
volumes:
|
|
- name: dockersock
|
|
host:
|
|
path: /var/run/docker.sock
|
|
|
|
trigger:
|
|
event:
|
|
- push
|
|
- tag
|
|
- cron
|
|
```
|
|
|
|
> **Note**: Ensure your Drone runner environment allows mounting the host socket volume.
|
|
|
|
### Tagging a Release with Git
|
|
|
|
When you create and push a Git tag to your repository:
|
|
|
|
```bash
|
|
# Create a tag locally
|
|
git tag v1.0.0
|
|
|
|
# Push the tag to your git remote
|
|
git push origin v1.0.0
|
|
```
|
|
|
|
1. Git sends a `tag` webhook event to Drone CI.
|
|
2. Drone automatically populates `$DRONE_TAG` with the tag value (e.g. `v1.0.0`) and triggers the pipeline.
|
|
3. The pipeline builds and tags the host image as `redirect:v1.0.0` (as well as `redirect:latest` and `redirect:<short_sha>`).
|
|
|
|
### Weekly Scheduled Rebuilds (`weekly-build`)
|
|
|
|
To keep your Docker images updated with upstream OS/Nginx security patches:
|
|
|
|
1. In the **Drone CI UI** (or via Drone CLI), navigate to **Repository Settings** -> **Cron Jobs**.
|
|
2. Add a new Cron job named `weekly-build` set to trigger weekly (e.g., `@weekly` or `0 0 * * 0`).
|
|
3. When the `cron` event triggers:
|
|
- The pipeline executes `docker build --pull -t redirect:latest .` to fetch updated base layers from Alpine/Nginx.
|
|
- It fetches the latest Git release tag (`git describe --tags --abbrev=0`) and automatically updates `redirect:<latest_tag>` (e.g., `redirect:v1.0.0`) on the host daemon.
|
|
|
|
---
|
|
|
|
## Quick Start & Usage
|
|
|
|
### 1. Manual Build (Local Testing)
|
|
|
|
```bash
|
|
# Bash
|
|
./build-and-tag.sh redirect latest
|
|
|
|
# PowerShell
|
|
.\build-and-tag.ps1 -ImageName redirect -Tag latest
|
|
```
|
|
|
|
### 2. Run Single Containers
|
|
|
|
**Basic Domain Redirect (301 Permanent Redirect)**
|
|
```bash
|
|
docker run -d \
|
|
--name redirect-domain \
|
|
-p 8080:8080 \
|
|
-e REDIRECT_TARGET="https://destination.com" \
|
|
-e REDIRECT_CODE="301" \
|
|
redirect:latest
|
|
```
|
|
|
|
**Path & Query Parameter Preserving Redirect (302 Found)**
|
|
```bash
|
|
docker run -d \
|
|
--name redirect-path \
|
|
-p 8081:8080 \
|
|
-e REDIRECT_TARGET="https://destination.com\$request_uri" \
|
|
-e REDIRECT_CODE="302" \
|
|
redirect:latest
|
|
```
|
|
|
|
### 3. Multi-Container Setup with Docker Compose
|
|
|
|
To deploy multiple redirect services side-by-side using the host-tagged image:
|
|
|
|
```yaml
|
|
services:
|
|
site-a-redirect:
|
|
image: redirect:latest
|
|
container_name: site-a-redirect
|
|
ports:
|
|
- "8081:8080"
|
|
environment:
|
|
- REDIRECT_TARGET=https://site-a.com
|
|
- REDIRECT_CODE=301
|
|
|
|
site-b-redirect:
|
|
image: redirect:latest
|
|
container_name: site-b-redirect
|
|
ports:
|
|
- "8082:8080"
|
|
environment:
|
|
- REDIRECT_TARGET=https://site-b.com$request_uri
|
|
- REDIRECT_CODE=302
|
|
```
|
|
|
|
Run compose stack:
|
|
```bash
|
|
docker compose up -d
|
|
```
|
|
|
|
---
|
|
|
|
## Health Check Endpoint
|
|
|
|
All requests to `/healthz` bypass redirection and return an HTTP `200 OK` response with text body `OK`.
|
|
|
|
```bash
|
|
curl http://localhost:8080/healthz
|
|
# Response: HTTP 200 OK -> "OK"
|
|
```
|