|
1 | | -# Microservice for responsive resize, compression and optimization of images on the fly for web pages |
| 1 | +# 🖼️ Image Optimize |
2 | 2 |
|
3 | | -[](https://www.codacy.com/gh/MobileTeleSystems/image-optimize/dashboard?utm_source=github.com&utm_medium=referral&utm_content=MobileTeleSystems/image-optimize&utm_campaign=Badge_Grade) |
| 3 | +**High-performance microservice for on-the-fly image optimization, resizing, and format conversion** |
| 4 | + |
| 5 | +[](https://hub.docker.com/r/mtsrus/image-optimize) |
| 6 | +[](https://hub.docker.com/r/mtsrus/image-optimize) |
| 7 | +[](https://www.codacy.com/gh/MobileTeleSystems/image-optimize/dashboard) |
| 8 | +[](LICENSE) |
4 | 9 | [](CODE_OF_CONDUCT.md) |
5 | | -[](https://github.com/MobileTeleSystems/image-optimize/blob/main/LICENSE) |
6 | 10 |
|
7 | | -Optimizing images helps reduce image weight and increases website loading speed, |
8 | | -which is very important for both users and search engines. For these purposes, |
9 | | -we have created a microservice that perfectly copes with this task. |
| 11 | +[Quick Start](#-quick-start) • |
| 12 | +[API Reference](#-api-reference) • |
| 13 | +[Configuration](#%EF%B8%8F-configuration) • |
| 14 | +[Deployment](#-deployment) • |
| 15 | +[Contributing](#-contributing) |
| 16 | + |
| 17 | +--- |
| 18 | + |
| 19 | +## 📋 Overview |
| 20 | + |
| 21 | +**Image Optimize** is a lightweight, production-ready microservice that optimizes images dynamically. Built with [NestJS](https://nestjs.com/) and powered by [Sharp](https://sharp.pixelplumbing.com/), it delivers exceptional performance for modern web applications. |
| 22 | + |
| 23 | +### Why Image Optimize? |
| 24 | + |
| 25 | +Optimizing images is critical for web performance — reducing page load times, saving bandwidth, and improving SEO rankings. This microservice handles all optimization on-the-fly, requiring no pre-processing or storage of optimized variants. |
| 26 | + |
| 27 | +### ✨ Features |
| 28 | + |
| 29 | +| Feature | Description | |
| 30 | +|---------|-------------| |
| 31 | +| 🔄 **Dynamic Resizing** | Resize images to any width, perfect for responsive designs | |
| 32 | +| 🗜️ **Smart Compression** | Reduce file sizes with configurable quality settings (1-100) | |
| 33 | +| 🎨 **Modern Formats** | Convert to WebP, AVIF, JPEG, or PNG on demand | |
| 34 | +| ⚡ **High Performance** | Average processing time ~200ms per image | |
| 35 | +| 📊 **Prometheus Metrics** | Built-in `/metrics` endpoint for monitoring | |
| 36 | +| 🔐 **Security Controls** | Allowlist for sources, size restrictions, Basic Auth support | |
| 37 | +| 🐳 **Docker Ready** | Production-optimized container image | |
| 38 | + |
| 39 | +--- |
| 40 | + |
| 41 | +## 🚀 Quick Start |
| 42 | + |
| 43 | +### Using Docker (Recommended) |
| 44 | + |
| 45 | +```bash |
| 46 | +# Pull and run the latest version |
| 47 | +docker run -d --name image-optimize -p 3000:3000 mtsrus/image-optimize |
| 48 | +``` |
| 49 | + |
| 50 | +### Test the Service |
| 51 | + |
| 52 | +Open in your browser or use curl: |
| 53 | + |
| 54 | +```bash |
| 55 | +curl "http://localhost:3000/optimize?src=https://example.com/image.png&size=800&format=webp" |
| 56 | +``` |
| 57 | + |
| 58 | +### Example Request |
| 59 | + |
| 60 | +``` |
| 61 | +http://localhost:3000/optimize?src=https://example.com/photo.jpg&size=1200&format=avif&quality=85 |
| 62 | +``` |
| 63 | + |
| 64 | +--- |
| 65 | + |
| 66 | +## 📖 API Reference |
| 67 | + |
| 68 | +### `GET /optimize` |
| 69 | + |
| 70 | +Optimizes and returns an image based on the provided parameters. |
| 71 | + |
| 72 | +#### Parameters |
| 73 | + |
| 74 | +| Parameter | Type | Required | Default | Description | |
| 75 | +|-----------|------|----------|---------|-------------| |
| 76 | +| `src` | string | ✅ | — | URL-encoded source image URL | |
| 77 | +| `size` | integer | ✅ | — | Target width in pixels | |
| 78 | +| `format` | string | ✅ | — | Output format: `jpeg`, `png`, `webp`, `avif` | |
| 79 | +| `quality` | integer | ❌ | format default | Compression quality (1-100) | |
10 | 80 |
|
11 | | -Features: |
12 | | - - Resize images for the user's screen size, |
13 | | - - Image compression to reduce traffic, |
14 | | - - Converting images to modern formats such as webp and avif, |
15 | | - - Works with dynamic content, compression occurs on the fly, |
16 | | - - High compression speed, an average picture is processed in just 200 ms, |
17 | | - - Includes exporter of metrics for Prometheus, |
18 | | - - Supports basic authorization for multiple domains and endpoints, |
19 | | - - Supports security restrictions for allowed addresses. |
| 81 | +#### Response |
20 | 82 |
|
21 | | -## Try |
| 83 | +- **Success (200)**: Returns the optimized image with appropriate `Content-Type` header |
| 84 | +- **Error (400)**: Returns JSON with error details |
22 | 85 |
|
23 | | -To try the microservice features, run the container with the command: |
| 86 | +#### Example |
24 | 87 |
|
25 | | -```sh |
26 | | -docker run -it --rm -p 3000:3000 mtsrus/image-optimize |
| 88 | +```bash |
| 89 | +# Convert to WebP with 80% quality, resized to 1920px width |
| 90 | +curl -o optimized.webp \ |
| 91 | + "http://localhost:3000/optimize?src=https%3A%2F%2Fexample.com%2Fimage.png&size=1920&format=webp&quality=80" |
27 | 92 | ``` |
28 | 93 |
|
29 | | -Now you can open the browser and check the work with the command: |
| 94 | +### `GET /metrics` |
30 | 95 |
|
31 | | -```sh |
32 | | -http://localhost:3000/optimize?size=1060&format=webp&src=https://mtscdn.ru/upload/iblock/75d/cmn5ki0o5dyk5laamf0idch2n77qf8gd.png |
| 96 | +Returns Prometheus-compatible metrics for monitoring. |
| 97 | + |
| 98 | +```bash |
| 99 | +curl http://localhost:3000/metrics |
33 | 100 | ``` |
34 | 101 |
|
35 | | -By changing the src, size, format parameters, |
36 | | -you can choose the path to the image, |
37 | | -the final size and the image format. |
| 102 | +--- |
| 103 | + |
| 104 | +## ⚙️ Configuration |
| 105 | + |
| 106 | +Configure the service using environment variables: |
| 107 | + |
| 108 | +### Core Settings |
| 109 | + |
| 110 | +| Variable | Default | Description | |
| 111 | +|----------|---------|-------------| |
| 112 | +| `PORT` | `3000` | HTTP server port | |
| 113 | +| `SHARP_CONCURRENCY` | `0` | libvips thread count (`0` = auto-detect CPU cores) | |
| 114 | + |
| 115 | +### Security Settings |
| 116 | + |
| 117 | +| Variable | Default | Description | |
| 118 | +|----------|---------|-------------| |
| 119 | +| `ALLOW_SIZES` | `100-1920` | Allowed output sizes (comma-separated values or ranges) | |
| 120 | +| `ALLOW_SOURCES` | `*` | Allowed source URLs (URL-encoded, comma-separated) | |
| 121 | +| `BASIC_AUTHS` | — | Basic auth credentials for sources (see format below) | |
| 122 | + |
| 123 | +#### ALLOW_SIZES Examples |
| 124 | + |
| 125 | +```bash |
| 126 | +# Allow specific sizes only |
| 127 | +-e ALLOW_SIZES="320,640,1024,1920" |
| 128 | + |
| 129 | +# Allow a range |
| 130 | +-e ALLOW_SIZES="100-2000" |
| 131 | + |
| 132 | +# Mix of specific values and ranges |
| 133 | +-e ALLOW_SIZES="320,640,1024-1920" |
| 134 | +``` |
| 135 | + |
| 136 | +#### ALLOW_SOURCES Examples |
| 137 | + |
| 138 | +```bash |
| 139 | +# Allow images only from specific domains |
| 140 | +-e ALLOW_SOURCES="https%3A%2F%2Fcdn.example.com%2F,https%3A%2F%2Fimages.example.org%2F" |
| 141 | +``` |
38 | 142 |
|
39 | | -## Use |
| 143 | +#### BASIC_AUTHS Format |
40 | 144 |
|
41 | | -To start the microservice in production, use the command: |
| 145 | +For sources requiring authentication: |
42 | 146 |
|
43 | | -```sh |
44 | | -docker run -d --restart always -p 3000:3000 mtsrus/image-optimize |
| 147 | +```bash |
| 148 | +# Format: encodeURIComponent(url):encodeURIComponent(login):encodeURIComponent(password) |
| 149 | +-e BASIC_AUTHS="https%3A%2F%2Fsecure.example.com%2F:admin:secret123" |
45 | 150 | ``` |
46 | 151 |
|
47 | | -## Container parameters |
| 152 | +--- |
| 153 | + |
| 154 | +## 🐳 Deployment |
| 155 | + |
| 156 | +### Docker Compose |
| 157 | + |
| 158 | +```yaml |
| 159 | +services: |
| 160 | + image-optimize: |
| 161 | + image: mtsrus/image-optimize:latest |
| 162 | + restart: always |
| 163 | + ports: |
| 164 | + - "3000:3000" |
| 165 | + environment: |
| 166 | + - PORT=3000 |
| 167 | + - ALLOW_SIZES=320,640,1024,1280,1920 |
| 168 | + - ALLOW_SOURCES=https%3A%2F%2Fcdn.yoursite.com%2F |
| 169 | + healthcheck: |
| 170 | + test: ["CMD", "wget", "-q", "--spider", "http://localhost:3000/metrics"] |
| 171 | + interval: 30s |
| 172 | + timeout: 10s |
| 173 | + retries: 3 |
| 174 | +``` |
| 175 | +
|
| 176 | +### Kubernetes |
| 177 | +
|
| 178 | +```yaml |
| 179 | +apiVersion: apps/v1 |
| 180 | +kind: Deployment |
| 181 | +metadata: |
| 182 | + name: image-optimize |
| 183 | +spec: |
| 184 | + replicas: 3 |
| 185 | + selector: |
| 186 | + matchLabels: |
| 187 | + app: image-optimize |
| 188 | + template: |
| 189 | + metadata: |
| 190 | + labels: |
| 191 | + app: image-optimize |
| 192 | + spec: |
| 193 | + containers: |
| 194 | + - name: image-optimize |
| 195 | + image: mtsrus/image-optimize:latest |
| 196 | + ports: |
| 197 | + - containerPort: 3000 |
| 198 | + env: |
| 199 | + - name: ALLOW_SIZES |
| 200 | + value: "320,640,1024,1280,1920" |
| 201 | + resources: |
| 202 | + requests: |
| 203 | + memory: "256Mi" |
| 204 | + cpu: "250m" |
| 205 | + limits: |
| 206 | + memory: "512Mi" |
| 207 | + cpu: "1000m" |
| 208 | + livenessProbe: |
| 209 | + httpGet: |
| 210 | + path: /metrics |
| 211 | + port: 3000 |
| 212 | + initialDelaySeconds: 10 |
| 213 | + periodSeconds: 30 |
| 214 | +--- |
| 215 | +apiVersion: v1 |
| 216 | +kind: Service |
| 217 | +metadata: |
| 218 | + name: image-optimize |
| 219 | +spec: |
| 220 | + selector: |
| 221 | + app: image-optimize |
| 222 | + ports: |
| 223 | + - port: 80 |
| 224 | + targetPort: 3000 |
| 225 | +``` |
| 226 | +
|
| 227 | +### Production Recommendations |
| 228 | +
|
| 229 | +- **Scaling**: Run multiple replicas behind a load balancer |
| 230 | +- **Caching**: Use a CDN or reverse proxy (nginx, Varnish) to cache optimized images |
| 231 | +- **Memory**: Allocate at least 256MB RAM per instance |
| 232 | +- **Monitoring**: Scrape `/metrics` endpoint with Prometheus |
| 233 | + |
| 234 | +--- |
| 235 | + |
| 236 | +## 🧩 Frontend Integration |
| 237 | + |
| 238 | +### React Component |
| 239 | + |
| 240 | +Use our official React component for seamless integration: |
| 241 | + |
| 242 | +```bash |
| 243 | +npm install @mts/image-optimize-react |
| 244 | +``` |
| 245 | + |
| 246 | +```jsx |
| 247 | +import { OptimizedImage } from '@mts/image-optimize-react'; |
| 248 | +
|
| 249 | +function App() { |
| 250 | + return ( |
| 251 | + <OptimizedImage |
| 252 | + src="https://cdn.example.com/photo.jpg" |
| 253 | + optimizerUrl="https://your-optimizer.com/optimize" |
| 254 | + alt="Optimized photo" |
| 255 | + /> |
| 256 | + ); |
| 257 | +} |
| 258 | +``` |
| 259 | + |
| 260 | +👉 [image-optimize-react on GitHub](https://github.com/MobileTeleSystems/image-optimize-react) |
| 261 | + |
| 262 | +--- |
| 263 | + |
| 264 | +## 🛠️ Development |
| 265 | + |
| 266 | +### Prerequisites |
| 267 | + |
| 268 | +- Node.js 24+ |
| 269 | +- npm 10+ |
| 270 | + |
| 271 | +### Local Setup |
| 272 | + |
| 273 | +```bash |
| 274 | +# Clone the repository |
| 275 | +git clone https://github.com/MobileTeleSystems/image-optimize.git |
| 276 | +cd image-optimize |
| 277 | +
|
| 278 | +# Install dependencies |
| 279 | +npm install |
| 280 | +
|
| 281 | +# Run in development mode |
| 282 | +npm run start:dev |
| 283 | +
|
| 284 | +# Run tests |
| 285 | +npm test |
| 286 | +
|
| 287 | +# Run e2e tests |
| 288 | +npm run test:e2e |
| 289 | +
|
| 290 | +# Build for production |
| 291 | +npm run build |
| 292 | +``` |
| 293 | + |
| 294 | +### Project Structure |
| 295 | + |
| 296 | +``` |
| 297 | +src/ |
| 298 | +├── controllers/ |
| 299 | +│ ├── optimize-controller/ # Main optimization endpoint |
| 300 | +│ └── metrics/ # Prometheus metrics endpoint |
| 301 | +├── services/ |
| 302 | +│ ├── optimize.service.ts # Image processing logic (Sharp) |
| 303 | +│ ├── img-loader.service.ts # Remote image fetching |
| 304 | +│ └── allow.service.ts # Security validations |
| 305 | +├── enums/ |
| 306 | +│ └── formats.ts # Supported output formats |
| 307 | +└── main.ts # Application entry point |
| 308 | +``` |
| 309 | +
|
| 310 | +--- |
| 311 | +
|
| 312 | +## 🤝 Contributing |
| 313 | +
|
| 314 | +We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details. |
| 315 | +
|
| 316 | +1. Fork the repository |
| 317 | +2. Create your feature branch (`git checkout -b feature/amazing-feature`) |
| 318 | +3. Commit your changes (`git commit -m 'feat: add amazing feature'`) |
| 319 | +4. Push to the branch (`git push origin feature/amazing-feature`) |
| 320 | +5. Open a Pull Request |
| 321 | +
|
| 322 | +--- |
| 323 | +
|
| 324 | +## 📄 License |
48 | 325 |
|
49 | | -- `-e PORT=3000` - the port on which the microservice will be launched, default 3000. |
50 | | -- `-e ALLOW_SIZES="100,200,1024-1920"` - an array of allowed sizes for the resulting images, |
51 | | - default 100-1920. Use specific values to prevent heavy loads on the server. |
| 326 | +This project is licensed under the MIT License — see the [LICENSE](LICENSE) file for details. |
52 | 327 |
|
53 | | -- `-e ALLOW_SOURCES="https%3A%2F%2Ftb.mts.ru%2F"` - URL array of allowed addresses for image sources, default * (any). |
54 | | - Use comma as separator. It is recommended to apply encodeURIComponent to url. |
| 328 | +--- |
55 | 329 |
|
56 | | -- `-e BASIC_AUTHS="https%3A%2F%2Ftb.mts.ru%2F"` - an array of endpoints with basic authorization parameters, default empty. |
57 | | - Has format encodeURIComponent("url"):encodeURIComponent("login"):encodeURIComponent("password"). Use comma as separator. |
| 330 | +## 🔗 Links |
58 | 331 |
|
59 | | -- `-e SHARP_CONCURRENCY=0` - number of threads libvips' should create to process each image, |
60 | | - default 0 (will reset to the number of CPU cores). |
| 332 | +- [Docker Hub](https://hub.docker.com/r/mtsrus/image-optimize) |
| 333 | +- [GitHub Repository](https://github.com/MobileTeleSystems/image-optimize) |
| 334 | +- [React Component](https://github.com/MobileTeleSystems/image-optimize-react) |
| 335 | +- [Report a Bug](https://github.com/MobileTeleSystems/image-optimize/issues) |
| 336 | +- [Security Policy](SECURITY.md) |
61 | 337 |
|
62 | | -## Components for web |
| 338 | +--- |
63 | 339 |
|
64 | | -To optimize images in the browser, there is a component for React. You can find it |
65 | | -[by following the link](https://github.com/MobileTeleSystems/image-optimize-react). |
66 | | -The component itself determines the most suitable image parameters and requests it from this microservice. |
| 340 | +**Made with ❤️ by [MTS](https://github.com/MobileTeleSystems)** |
0 commit comments