آنچه در این مقاله میخوانید
چگونه تصاویر نسل جدید را با imgproxy و Docker ارائه دهیم؟
۱۴ مهر ۱۴۰۴
تصاویر یکی از مهمترین عناصر وبسایتها هستند و نقش مستقیم در تجربه کاربری و سرعت بارگذاری دارند. فرمتهای قدیمی مانند JPEG و PNG هنوز استفاده میشوند، اما حجم بالای آنها میتواند باعث کندی سایت شود. به همین دلیل، فرمتهای نسل جدید مانند WebP و AVIF معرفی شدند که تصاویر را تا 50% سبکتر میکنند و بارگذاری سایت را بسیار سریعتر میکنند.
با این حال، تبدیل تصاویر موجود و مدیریت آنها میتواند زمانبر و پیچیده باشد. اینجاست که imgproxy
به کمک میآید؛ ابزاری که تصاویر را در لحظه پردازش میکند، تغییر اندازه میدهد، افکت اضافه میکند و فرمت آنها را بهینه میکند و با imgproxy
، تصاویر همواره بهینه و آماده ارائه به کاربران هستند، بدون اینکه کیفیت کاهش یابد.
در این آموزش، یاد میگیریم چگونه با استفاده از Docker (داکر) imgproxy
را راهاندازی کنیم، تصاویر را بهصورت امن ارائه دهیم و بهطور خودکار از فرمتهای نسل جدید استفاده کنیم تا وبسایت شما سریعتر و مدرنتر شود.
در ادامه خواهید خواند:
- پیش نیاز
- مرحله 1: نصب
imgproxy
با استفاده از Docker - مرحله 2: ساخت URLهای
imgproxy
برای ویرایش تصاویر - مرحله 3: امنسازی
imgproxy
با استفاده از امضا - مرحله 4: تنظیم
imgproxy
برای ارائه خودکار تصاویر نسل جدید - جمع بندی

پیش نیاز
برای دنبال کردن این آموزش، به موارد زیر نیاز خواهید داشت:
- یک سرور یا سیستم توسعه با Docker نصب شده
- یک زبان برنامهنویسی برای اجرای اسکریپتها؛ در این آموزش از Ruby استفاده میکنیم.
- آشنایی اولیه با ابزارهای توسعه مرورگر
مرحله 1: نصب imgproxy
با استفاده از Docker
در این مرحله، شما imgproxy
را نصب میکنید و بررسی میکنید که به درستی در حال اجرا است. روشهای مختلفی برای نصب imgproxy
وجود دارد، اما در این آموزش از Docker استفاده میکنیم چون قابل حمل است و هنگام انتقال به محیط تولید تغییرات کمی نیاز دارد.
ابتدا، روی سرور یا ماشین توسعه خود که Docker نصب شده، دستور زیر را اجرا کنید تا مطمئن شوید Docker در حال اجرا است.
docker info
شروع خروجی باید چیزی شبیه به دستور زیر باشد (نگران تفاوت تعداد کانتینرها یا تصاویر نباشید):
Output
Client:
Context: default
Debug Mode: false
Plugins:
buildx: Docker Buildx (Docker Inc., v0.7.1)
compose: Docker Compose (Docker Inc., v2.2.1)
scan: Docker Scan (Docker Inc., v0.14.0)
Server:
Containers: 15
Running: 0
Paused: 0
Stopped: 15
Images: 47
Server Version: 20.10.11
...
بعد از اطمینان از اجرای Docker، میتوانید آخرین نسخه imgproxy
را از طریق Dockerhub دانلود کنید:
docker pull darthsim/imgproxy:latest
در این مرحله، مجموعهای از نوارهای پیشرفت را مشاهده خواهید کرد که نشان میدهد تصویر در حال دانلود است.
سپس با دستور زیر یک نمونه از کانتینر را اجرا کنید:
docker run -p 8080:8080 -it darthsim/imgproxy
در این دستور:
- گزینه
-p
پورت8080
کانتینر را به پورت8080
ماشین شما متصل میکند. - گزینه
-it
یک ترمینال تعاملی باز میکند تا بتوانید لاگهایimgproxy
را مشاهده کنید. darthsim/imgproxy
نام تصویری است که دانلود کردهاید و میخواهید اجرا کنید.
خروجی باید چیزی شبیه به این باشد:
WARNING [2021-12-24T03:21:18Z] No keys defined, so signature checking is disabled
WARNING [2021-12-24T03:21:18Z] No salts defined, so signature checking is disabled
INFO [2021-12-24T03:21:18Z] Starting server at :8080
هشدارها در این مرحله اهمیت ندارند؛ در مراحل بعدی آنها را تنظیم خواهید کرد.
در این مرحله، شما imgproxy
را نصب و اجرای آن را تایید کردهاید. در مرحله بعد، با ایجاد URL های imgproxy
، یاد میگیرید که چگونه تصاویر را تغییر دهید و از آنها در وبسایت خود استفاده کنید.
نکته آموزشی: مشاهده لاگها در این مرحله به شما کمک میکند تا درک بهتری از عملکرد کانتینر و وضعیت سرور داشته باشید. حتی اگر همه چیز بهنظر درست میرسد، همیشه بررسی لاگها میتواند مشکلات احتمالی را زودتر نشان دهد.
با برنامه آماده imgproxy لیارا، تصاویر سایتت رو آنی و با سرعت بالا بهینهسازی کن.
✅ نصب یککلیکی✅ بهینهسازی لحظهای تصاویر✅ سازگار با ذخیرهسازی ابری و سرورهای محلی
خرید و راهاندازی imgproxy
مرحله 2: ساخت URLهای imgproxy
برای ویرایش تصاویر
در این مرحله، شما یادمیگیرید چگونه URL های imgproxy
بسازید تا بتوانید تصاویر را تغییر داده و درخواست کنید.
وقتی از imgproxy
استفاده میکنید، کاربر نهایی سایت یک درخواست HTTP به imgproxy
ارسال میکند. سپس imgproxy
تصویر اصلی را دریافت میکند. تصویر اصلی میتواند هرجایی در اینترنت باشد که پروکسی ما به آن دسترسی دارد. (امنسازی این مورد در مرحله بعد آموزش داده میشود.) پس از دریافت تصویر، imgproxy آن را طبق نیاز شما تغییر میدهد و تصویر نهایی را به کاربر ارسال میکند.
شما نوع تغییرات را با پارامترهای URL مشخص میکنید. فرمت URL های imgproxy
به شکل زیر است:
http://your-imgproxy-host/%signature/%processing_options/%encoded_source_url.%extension
%signature
اختیاری است و در مرحله بعدی آن را تنظیم میکنید.%processing_options
جایی است که مشخص میکنیدimgproxy
چه تغییراتی روی تصویر انجام دهد، مثل برش، واترمارک یا افکتهای دیگر. اگر نمیخواهید تصویر تغییر کند، میتوانید آن را خالی بگذارید.%encoded_source_url
به تصویر اصلی اشاره دارد، همان تصویری که میخواهید تغییر دهد. این URL باید رمزگذاری شود تا وقتی در URL پروکسی قرار میگیرد معتبر باقی بماند.%extension
اختیاری است و نوع فایل تصویر خروجی را مشخص میکند، مثلا.jpg
.
پس از تولید URL پروکسی، میتوانید src
یک تگ <img>
را با URL جدید جایگزین کنید. مثال:
<img src="https://yourserver.com/assets/image.png" />
با imgproxy
، میتوانید این URL را به چیزی شبیه زیر تغییر دهید:
<img src="https://imgproxy.yourserver.com/your-imgproxy-url-here" />
نکته آموزشی: برای یادگیری سریع، URL ها را مستقیم در نوار آدرس مرورگر وارد کنید تا نتیجه را فورا ببینید.
از آنجایی که imgproxy
را در Docker اجرا کردهاید، سرور شما روی localhost
و پورت 8080
در حال گوش دادن است. بنابراین میزبان imgproxy
شما:
http://localhost:8080
توجه: اگر از سرور راه دور استفاده میکنید، بهجای localhost
از آدرس IP سرور خود استفاده کنید. اگر URL درست باشد، با مراجعه به http://your-server-ip:8080
پیام “Hey, I’m imgproxy” را مشاهده خواهید کرد.
برای این آموزش، میتوانید از تصویر یک توله سگ استفاده کنید:https://i.imgur.com/KSLD4VV.jpeg
(این تصویر اصلی از Unsplash گرفته شده است.) یا هر تصویر دیگری که در اینترنت قابل دسترسی باشد. بهتر است از تصاویر واقعی (jpg) استفاده کنید، نه لوگو یا تصویر گرافیکی.
اولین قدم برای ساخت URL پروکسی، رمزگذاری URL تصویر اصلی است. یعنی تمام کاراکترهای خاص URL مثل ://
، /
، .
با کاراکترهای امن جایگزین میشوند تا URL در پروکسی معتبر بماند.
imgproxy
از Base64 امن برای URL استفاده میکند. میتوانید از زبان برنامهنویسی مورد علاقه خود یا ابزارهای آنلاین Base64 استفاده کنید. (حتماً گزینه “Perform URL-safe encoding” را فعال کنید.)
توجه: میتوانید به جای Base64 از گزینه /plain
استفاده کنید، اما در این صورت باید پارامترهای query را خودتان رمزگذاری کنید. در کل، استفاده از Base64 امنتر و کم خطاتر است.
با رمزگذاری URL تصویر توله سگ، به شکل زیر در میآید:
aHR0cHM6Ly9pLmltZ3VyLmNvbS9LU0xENFZWLmpwZWc
اکنون میتوانید آن را در URL imgproxy قرار دهید و در مرورگر باز کنید:
http://localhost:8080/sig/aHR0cHM6Ly9pLmltZ3VyLmNvbS9LU0xENFZWLmpwZWc
توجه: اگر تصویر دیگری استفاده میکنید، بخش آخر URL را با Base64 تصویر خود جایگزین کنید.
با باز کردن این URL، تصویر اصلی توله سگ بدون تغییر نمایش داده میشود.
اگر تصویر نمایش داده نشد، پیام خطا خواهید دید یا میتوانید خروجی دستور docker run
مرحله قبل را بررسی کنید تا لاگهای imgproxy
شامل درخواستهای خطادار را ببینید.
بعد، میتوانید فرمت تصویر را با بخش .extension
تغییر دهید:
http://localhost:8080/sig/aHR0cHM6Ly9pLmltZ3VyLmNvbS9LU0xENFZWLmpwZWc.png
این بار بارگذاری طولانیتر است و اگر ابزار توسعه مرورگر خود را باز کنید، متوجه میشوید که حجم تصویر PNG بسیار بزرگتر از JPG اصلی است (در نمونه توله سگ، PNG حدود 15.84MB و JPG حدود 1.3MB). imgproxy
هنگام درخواست تصویر، آن را از JPG به PNG تبدیل کرده است.

میتوانید تصویر را به فرمتهای بهینهتر Next-Generation مثل webp
یا avif
هم تبدیل کنید:
http://localhost:8080/sig/aHR0cHM6Ly9pLmltZ3VyLmNvbS9LU0xENFZWLmpwZWc.webp
نسخه webp
حدود 600KB است که تقریباً 53٪ کمتر از JPG اصلی حجم دارد. این فرمت باعث افزایش سرعت بارگذاری تصویر میشود.
همچنین میتوانید اندازه تصویر و افکتها را تغییر دهید. برای مثال، تصویر را به عرض 200 و ارتفاع 500 پیکسل با نوع تغییر اندازه fill
(حفظ نسبت تصویر و برش قسمتهای اضافی) تغییر دهید و سپس با ماسک 5
افکت Gaussian Blur اضافه کنید:
http://localhost:8080/sig/size:200:500/resizing_type:fill/blur:5/aHR0cHM6Ly9pLmltZ3VyLmNvbS9LU0xENFZWLmpwZWc
با باز کردن این URL، تصویر تغییر اندازه داده شده و مات نمایش داده میشود.

علاوه بر تغییر اندازه و مات کردن، تبدیلهای زیادی برای تصاویر وجود دارد. برای گزینههای بیشتر به بخش Generating the URL در مستندات imgproxy
مراجعه کنید.
در این مرحله، شما URLهای imgproxy
برای نمایش و تغییر تصویر ایجاد کردید. در مرحله بعد، یاد میگیرید چگونه imgproxy
را امن کنید تا فقط از URLهای مشخص شده تصویر دریافت کند (پارامتر %signature
).
imgproxy چیست؟ بهینهسازی تصاویر وب با imgproxy
imgproxy
مرحله 3: امنسازی imgproxy
با استفاده از امضا
تا این مرحله، شما در بخش “signature” از یک مقدار نمونه استفاده میکردید. اما برای امنیت، باید URLهایی که استفاده میکنید را امضا کنید. این کار باعث میشود تنها URLهایی که با استفاده از کلید و salt مخفی شما ساخته شدهاند توسط imgproxy
پردازش شوند و دیگران نتوانند منابع سرور شما را هدر دهند. در این مرحله، شما imgproxy
را طوری تنظیم میکنید که امضای URL را اجباری کند و یک امضای معتبر تولید کنید.
imgproxy
یک برنامه 12-عاملی است و میتوان آن را با متغیرهای محیطی (Environment Variables) تنظیم کرد بدون نیاز به تغییر فایلها. این روش در Docker عالی کار میکند، چون Docker با گزینه --env
اجازه میدهد متغیرها را به کانتینر منتقل کنید.
برای تولید امضا، ابتدا نیاز به یک جفت کلید و salt دارید که میتواند یک رشته تصادفی هگزادسیمال باشد. میتوانید آن را روی کامپیوتر خود بسازید یا از ابزارهای آنلاین تولید رشته تصادفی استفاده کنید. هر رشته باید 64 کاراکتر باشد و حداقل دو رشته بسازید: یکی برای کلید و دیگری برای salt.
مثال رشته هگزادسیمال تصادفی 64 کاراکتری:
Example Random Hex
49d5e2cd30d80fccc2e30877e4e58b2f0854a8dca6fb2e980b129171910080ed7ffa5dfbfde006e0c1a8ff52e7b5c614f0d3e9ec6e6ed754399fb0e2eb473c59
توجه: رشتههای شما متفاوت خواهند بود. آنها را ذخیره کنید تا در فرمان بعدی استفاده کنید.
سپس Docker را دوباره با همان فرمان مرحله 1 اجرا کنید، اما این بار دو گزینه --env
اضافه کنید تا متغیرهای محیطی IMGPROXY_KEY و IMGPROXY_SALT را با مقادیر تصادفی خود ست کنید:
docker run --env IMGPROXY_KEY=first-hex-result --env IMGPROXY_SALT=second-hex-result -p 8080:8080 -it darthsim/imgproxy
اکنون در مرورگر به آدرس زیر بروید:
http://localhost:8080/sig/aHR0cHM6Ly9pLmltZ3VyLmNvbS9LU0xENFZWLmpwZWc
یک پیام 403 Forbidden دریافت خواهید کرد. همچنین در لاگ Docker چیزی شبیه این خواهید دید:
Example Docker Log
WARNING [2021-12-28T03:12:34Z] Completed in 134.6µs /sig/aHR0cHM6Ly9pLmltZ3VyLmNvbS9LU0xENFZWLmpwZWc request_id=WQGTfRgeBXPvaQYHkNjab method=GET status=403 client_ip=172.17.0.1 error="Invalid signature"
همانطور که در انتهای لاگ میبینید، imgproxy
یک خطای 403 برگرداند چون امضای معتبر ارائه نشده است. این نشان میدهد که imgproxy
درست تنظیم شده تا امضا بخواهد. این فرآیند نمونهای از احراز هویت با راز مشترک (Shared Secret Authentication) است. imgproxy
به صورت داخلی یک SHA256 از URL درخواست شده همراه با کلید و salt تولید میکند تا امضا بسازد. تنها کسانی که این کلید و salt را دارند، میتوانند URL معتبر بسازند. دیگران نمیتوانند منابع شما را مصرف کنند.
نکته: کلید و salt را مستقیماً در URL قرار ندهید، زیرا این اطلاعات میتواند عمومی شود (در سورس سایت یا کش مرورگر). به همین دلیل از یک هش یکطرفه مثل SHA256 استفاده میکنیم تا کسی نتواند با امضا، کلید و salt را بازسازی کند.
حال باید یک امضای معتبر تولید کنید. چندین نمونه پیادهسازی در مخزن GitHub imgproxy موجود است، اما در این آموزش از Ruby استفاده میکنیم.
با استفاده از nano
یا ویرایشگر مورد علاقه، یک فایل به نام signature.rb
بسازید:
nano signature.rb
محتوای زیر را داخل فایل کپی کنید. کلید و salt را با مقادیر تولید شده قبلی جایگزین کنید. اگر از سرور راه دور استفاده میکنید، localhost
را با آدرس IP سرور خود جایگزین کنید.
# adapted from https://github.com/imgproxy/imgproxy/blob/master/examples/signature.rb
require "openssl"
require "base64"
key = ["your IMGPROXY_KEY value"].pack("H*")
salt = ["your IMGPROXY_SALT value"].pack("H*")
url = "https://i.imgur.com/KSLD4VV.jpeg"
encoded_url = Base64.urlsafe_encode64(url).tr("=", "").scan(/.{1,16}/).join("/")
path = "/#{encoded_url}"
digest = OpenSSL::Digest.new("sha256")
hmac = Base64.urlsafe_encode64(OpenSSL::HMAC.digest(digest, key, "#{salt}#{path}")).tr("=", "")
signed_path = "/#{hmac}#{path}"
puts "Open http://localhost:8080#{signed_path} in a web browser"
این کد ابتدا کتابخانههای مورد نیاز برای تولید امضا را بارگذاری میکند، سپس کلید و salt را به بایتهای هگز تبدیل میکند (.pack("H*")
) که مورد انتظار OpenSSL است.
بعد URL تصویر را با Base64 امن برای URL رمزگذاری میکند، مشابه مرحله قبل، با این تفاوت که کاراکترهای =
حذف شده و هر 16 کاراکتر با /
جدا میشوند تا URL خواناتر باشد.
سپس با استفاده از الگوریتم SHA256 و کلید و salt، امضا تولید شده و به صورت Base64 رمزگذاری میشود تا بتواند در URL استفاده شود. در نهایت URL امضا شده در مرورگر چاپ میشود.
برای اجرای اسکریپت و دریافت URL امضا شده:
ruby signature.rb
خروجی شبیه به خروجی زیر خواهد بود:
Open http://localhost:8080/-CAkkjs5IioquivOi5LYyDnVxEULmPK-xIwIwXTleUA/aHR0cHM6Ly9pLmlt/Z3VyLmNvbS9LU0xE/NFZWLmpwZWc in a web browser
قسمت هایلایت شده در URL شما متفاوت خواهد بود. این URL امضا شده فقط توسط شما قابل تولید است، چون تنها شما کلید و salt را دارید. اگر URL امضا شده را در مرورگر باز کنید، تصویر به جای 403 نمایش داده میشود. حتماً URL امضا شده را برای مراحل بعد ذخیره کنید.
اکنون imgproxy
شما تنها با URLهای امضا شده کار میکند و فقط کسانی که کلید و salt دارند میتوانند با آن ارتباط برقرار کنند.
در مرحله بعد، یاد میگیریم چگونه imgproxy
را طوری تنظیم کنیم که بهطور خودکار از فرمتهای مدرن تصاویر استفاده کند.
با هاست ابری Docker لیارا، اپلیکیشنهات رو در محیطی ایزوله و امن اجرا کن.
✅ میزبانی با Docker Container✅ شبکه خصوصی✅ SSL رایگان و کاهش/افزایش منابع در لحظه
خرید و راهاندازی هاست Docker
مرحله 4: تنظیم imgproxy
برای ارائه خودکار تصاویر نسل جدید
تا این مرحله، شما بهصورت دستی به imgproxy
میگفتید که از کدام فرمت برای نمایش تصویر استفاده کند. حالا میتوانیم طوری تنظیم کنیم که imgproxy
خودکار از بهینهترین فرمت ممکن استفاده کند. یعنی اگر مرورگر کاربر از فرمتهای نسل بعدی مانند WebP یا AVIF پشتیبانی کند، آن را ارائه میدهد و در غیر این صورت بهصورت خودکار به PNG یا JPG برمیگردد.
imgproxy
این کار را با بررسی هدر Accept انجام میدهد که مرورگرها بهصورت خودکار در درخواستها ارسال میکنند تا مشخص شود کدام فرمتهای تصویر پشتیبانی میشوند. برای مثال، Chrome هدر زیر را ارسال میکند:
image/avif,image/webp,image/apng,image/*,*/*;q=0.8
چون هم image/avif
و هم image/webp
وجود دارند، میدانیم Chrome از هر دو فرمت پشتیبانی میکند.
برای فعالسازی این قابلیت در imgproxy
، باید AVIF/WebP Support Detection را روشن کنید. برای این کار، متغیر محیطی زیر را هنگام اجرای Docker ست کنید:
IMGPROXY_ENABLE_WEBP_DETECTION=true
ابتدا با Ctrl+C کانتینر Docker را متوقف کنید، سپس دوباره آن را با فرمان زیر اجرا کنید و کلید و salt خود را جایگزین کنید:
docker run --env IMGPROXY_ENABLE_WEBP_DETECTION=true --env IMGPROXY_KEY=your-key-from-Step-3 --env IMGPROXY_SALT=your-Salt-from-Step 3 -p 8080:8080 -it darthsim/imgproxy
این همان فرمان Docker مرحله 3 است، با این تفاوت که یک –env جدید برای فعالسازی تشخیص WebP اضافه شده است.
برای بررسی، تصویر را در مرورگر باز کنید. URL امضا شدهای که در مرحله 3 تولید کردید را وارد کنید:
http://localhost:8080/-CAkkjs5IioquivOi5LYyDnVxEULmPK-xIwIwXTleUA/aHR0cHM6Ly9pLmlt/Z3VyLmNvbS9LU0xE/NFZWLmpwZWc
اگر همه چیز درست باشد، تصویر با فرمت WebP ارائه میشود. میتوانید این موضوع را با بررسی اندازه و نوع پاسخ در ابزار توسعهدهنده مرورگر یا با استفاده از curl چک کنید.
برای تست با curl، یک تب جدید باز کنید تا imgproxy
همچنان در حال اجرا باشد و دستور زیر را اجرا کنید (URL خود را جایگزین کنید):
curl -s -v -H "Accept: image/avif,image/webp,image/apng,image/*,*/*;q=0.8" http://localhost:8080/M-RTYvp5xktEK9gG93hPwAB6on9aX7H5XciGsI3XSac/aHR0cHM6Ly9pLmlt/Z3VyLmNvbS9LU0xE/NFZWLmpwZWc
-s
خروجی را خاموش میکند (چون تصویر در متن ساده معنی ندارد).-v
حالت verbose است تا هدرها را ببینید.-H
هدر Accept را مشابه مرورگر Chrome تنظیم میکند.
در هدر Content-Type
خواهید دید که imgproxy
یک تصویر WebP ارسال کرده است:
< Content-Type: image/webp
اگر بخواهید، میتوانید همین کار را برای IMGPROXY_ENABLE_AVIF_DETECTION هم انجام دهید تا پشتیبانی از فرمت AVIF فعال شود.
در این مرحله، imgproxy
بهطور خودکار از فرمتهای نسل بعدی استفاده میکند، فقط اگر مرورگر کاربر آن را پشتیبانی کند.
داکر (Docker) چیست؟
Docker
جمع بندی
با اجرای این مراحل، نهتنها کنترل بیشتری بر نحوه ارائه تصاویر در وبسایت حاصل میشود، بلکه گامی موثر در بهبود تجربه کاربری و افزایش سرعت بارگذاری نیز برداشته خواهد شد. imgproxy
این امکان را فراهم میکند تا فرآیند بهینهسازی تصاویر به شکلی هوشمند و کارآمد انجام گیرد، فشار وارد بر سرور کاهش یابد و رضایت کاربران ارتقا یابد. در ادامه نیز میتوان با شخصیسازی تنظیمات و بهرهگیری از قابلیتهای پیشرفته این ابزار، انعطافپذیری بیشتری متناسب با نیاز هر پروژه به دست آورد.