آنچه در این مقاله میخوانید
چگونه تصاویر نسل جدید را با 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 را از طریق Docker Hub دانلود کنید:
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 این امکان را فراهم میکند تا فرآیند بهینهسازی تصاویر به شکلی هوشمند و کارآمد انجام گیرد، فشار وارد بر سرور کاهش یابد و رضایت کاربران ارتقا یابد. در ادامه نیز میتوان با شخصیسازی تنظیمات و بهرهگیری از قابلیتهای پیشرفته این ابزار، انعطافپذیری بیشتری متناسب با نیاز هر پروژه به دست آورد.