pseudoyu

pseudoyu

Blockchain | Programming | Photography | Boyi
github
twitter
telegram
mastodon
bilibili
jike

Build Your Free Image Hosting System from Scratch (Cloudflare R2 + WebP Cloud + PicGo)

Introduction#

In the article "What Changes Have Happened to My Blog in 2024", I introduced the blog system I built using a Serverless platform and some open-source projects, and I started this series of tutorials to document the entire process of building and deploying.

This article is about the solution for an image hosting system.

Iteration of Image Hosting Solutions#

In fact, at the beginning of building the blog, there wasn't much content, and there were few illustrations, so most of the images were directly placed in the static directory of my Hugo blog repository, and I didn't find it inconvenient until there was a period when I needed to publish on multiple platforms. After copying the markdown source files of the blog, all the images could not be displayed because they were all relative paths to the blog, which meant I had to re-upload the images one by one, which was very tedious.

That was when I began to understand the concept of image hosting, which involves uploading images to a dedicated storage service and using public links for access. This not only allows for unified management but also effectively reduces the size of the blog repository files and improves the loading speed of the website.

GitHub + jsDelivr CDN + PicGo#

At first, I created a GitHub repository "GitHub - image-hosting", uploaded images directly to the repository via PicGo, and changed the image paths returned by PicGo to links accelerated by jsDelivr. This was quite convenient and also provided version management.

However, the good times didn't last long; jsDelivr suffered from DNS pollution and was blocked in mainland China, causing my blog images to be completely inaccessible for a long time. This made me concerned about relying solely on CDN. Additionally, since GitHub hosts images based on code repositories, uploading images relies on code commits, which can easily pollute commit records and is ultimately a form of abuse. If there are issues with account/repository access, all images could be lost, so I began to look for other solutions.

Alibaba Cloud OSS + PicGo#

The second option I thought of was object storage provided by cloud service providers, such as Amazon S3 and Alibaba Cloud OSS. These are object storage services offered by cloud vendors that provide accessible public links along with advantages like permission control, data backup, and scalability, offering a better solution for file data storage and management at a relatively low cost.

Since I wanted to optimize access for users in mainland China, I ultimately chose Alibaba Cloud OSS. The configuration wasn't too complicated, and I also used PicGo to upload and convert to Alibaba Cloud OSS links, resulting in a noticeable improvement in access speed.

aliyunoss_invoice

However, since it is mostly billed based on usage, the continuously rising costs are also a consideration for a non-profit personal blog. At the beginning of 2023, my blog traffic was relatively high, and the monthly bill kept increasing. Additionally, if Alibaba Cloud OSS requires a custom access domain, it needs to be filed for record, but my domain is hosted through Cloudflare, and I didn't consider filing. So after a few months, I started to consider changing the image hosting solution.

Chevereto + PicGo#

After some research, I deployed the free self-hosted version of Chevereto using a Docker image on my well-connected VULTR server (CN2GIA DC6 data center) and mounted the images as a Docker Volume on the host.

To be honest, the interface of Chevereto feels a bit outdated; it is still an old PHP service, and the free version hasn't been maintained or upgraded for a long time. However, it has complete functionality and can also use PicGo to interface with Chevereto's API for image uploads and other operations, and its stability is quite good, so I used it for a year and a half.

However, I was somewhat careless about the stability of self-hosted services and the preciousness of data. A few days ago, the server suddenly crashed, and the kernel reported an error that made it impossible to restart. While the service being down was manageable, I couldn't export the image data I had accumulated over the past year and a half. I contacted technical support through a ticket, and they replied to me only twice in a day—once asking me to restart and once suggesting I hire a network administrator to investigate.

I had to rely on myself, scouring various solutions online. After a day of tinkering, I finally managed to resolve the issue, but this experience gave me a new understanding of the importance of backing up services with critical data and the stability of self-hosting. Additionally, when I wanted to redeploy, I found that the free version image had been taken offline, leaving only a paid License version available, so I abandoned the original plan.

Cloudflare R2 + WebP Cloud + PicGo#

cloudflare_r2_free_tier

I then turned back to cloud service providers' object storage and discovered the R2 object storage service provided by Cloudflare. The free plan offers 10 GB of storage per month, which is more than enough for personal use, and the service and data security of a large company are guaranteed.

To optimize user access, I also used a service called "WebP Cloud" to proxy the images on R2, further reducing the image size at the proxy level. Although the speed for domestic users is certainly not as good as Alibaba Cloud OSS, under the conditions of no filing, stability, and being free, this was the best solution I could think of.

On the computer side, I also used the PicGo client to almost upload with one click and generate markdown image links that can be used directly in the blog. After the configuration was completed, it was very smooth to use.

Image Hosting Setup Instructions#

Although the Cloudflare R2 + WebP + PicGo solution involves multiple components and platforms, all operations are within the Free Plan, and it is the solution I ultimately chose. Below, I will introduce how to build this free image hosting system from scratch.

Cloudflare R2#

R2 is a free object storage service launched by Cloudflare. You need to register for a free Cloudflare account to use it. After registering and logging in, click on the R2 access service in the left sidebar. However, it is important to note that activating the R2 service requires binding a credit card (mainstream credit cards from both domestic and international sources are acceptable), but no charges will be made; this is mainly for user identity verification.

Create an Image Hosting Bucket#

cloudflare_r2_interview

After activating the R2 service, click the "Create Bucket" button in the upper right corner to create one.

cloudflare_r2_create_bucket

In the creation configuration interface, you need to fill in the bucket name. It is recommended to choose a name that is somewhat recognizable, as it will be used in subsequent upload configurations.

For the location, select "Automatic," but you can additionally configure a location hint. Since I will later use the West US data center of "WebP Cloud" for image proxy optimization, I chose "North America West (WNAM)" here. You can select other regions based on your needs, but Cloudflare does not guarantee that it will allocate to the specified region.

cloudflare_r2_create_done

Clicking the "Create Bucket" button completes the creation. At this point, we can upload files to our "yu-r2-test" bucket. You can choose to upload files or folders directly on the webpage.

You can also use the S3 API for uploads. We will rely on this method for uploading using the PicGo client, but some additional configuration is required. Click the "Settings" option in the navigation bar for configuration.

cloudflare_r2_config

First, we need to enable the "R2.dev Subdomain," which is needed for the public address when accessing images later. Click "Allow Access" and enter "allow" as prompted to enable it.

r2_dev_domain_allow

Once completed, a public URL ending with r2.dev will be displayed, which will be the address we use to access images later.

Custom Image Hosting Domain (Optional)#

However, the allocated URL is quite long and not easy to remember. We can bind our custom domain through "Custom Domain" by clicking the "Connect Domain" button.

r2_custom_domain_setup

Enter the domain you want to bind, such as yu-r2-test.pseudoyu.com, and click continue.

cloudflare_r2_custom_domain

r2_custom_domain_dns_wait

Connect the domain and wait for the DNS resolution to take effect.

r2_bucket_status

Once completed, the bucket status will show "Public URL Access" as "Allowed," and the "Domain" will display the custom domain we just set up, indicating successful configuration.

Configure Bucket Access API#

yu_bucket_preview

After completing the above configuration, we can return to the bucket's "Objects" interface, upload a sample image, and clicking on the details will show the access address of that image. At this point, we have an accessible image hosting service.

However, manually uploading images by opening the Cloudflare page each time is clearly not convenient enough. R2 provides S3-compatible APIs, making it easy to use some client/command-line tools for uploads, deletions, and other operations.

create_r2_api_token

create_r2_api_key

Return to the R2 main page, click "Manage R2 API Tokens" in the upper right corner, and then click "Create API Token."

r2_apikey_conifg

Enter the token name, select "Object Read and Write" for "Permissions," and specify the previously created Bucket for this API. This minimizes permissions while ensuring data security; the other options can remain as defaults.

api_key_config_details

After creation, all keys will be displayed. The three pieces of information we need for PicGo are shown below, but since they will only be displayed once, it is recommended to securely store these parameters in a password manager or elsewhere.

At this point, we have completed the configuration needed on Cloudflare R2, and next, we need to configure the PicGo client.

PicGo#

PicGo is a tool software for quickly uploading and obtaining image URLs, with a rich plugin ecosystem that supports various image hosting services. Its GitHub repository is "GitHub - Molunerfinn/PicGo," where you can download the client for the corresponding platform.

Configure R2 Image Hosting#

The PicGo core does not include S3 image hosting, but it can be supported through the "GitHub - wayjam/picgo-plugin-s3" plugin.

picgo_s3_plugin

In the "Plugin Settings," select to install it, and the Amazon S3 option will be added in the "Image Hosting Settings." Click to enter the configuration options.

r2_picgo_s3_config

There are a few configurations that need special attention here.

  • Application Key ID: Fill in the Access Key ID from R2 API.
  • Application Secret Key: Fill in the Secret Access Key from R2 API.
  • Bucket Name: Fill in the name of the Bucket created in R2, such as yu-r2-test from my previous text.
  • File Path: The file path to upload to R2. I chose to use {fileName}.{extName} to retain the original file name and extension.
  • Custom Endpoint: Fill in the "Region-specific endpoint for S3 clients" in R2 API, which is in the format of xxx.r2.cloudflarestorage.com.
  • Custom Domain: Fill in the generated domain in the format of xxx.r2.dev or the custom domain I configured, such as yu-r2-test.pseudoyu.com.

The other configurations can remain as defaults. After confirming the parameters are correct, click "OK" and "Set as Default Image Hosting."

Image Upload#

upload_r2_with_picgo

After completing the above configuration, we can directly drag files into the "Upload Area" for image uploads. If it displays correctly after uploading, the configuration is successful, and the generated link will automatically be in the system clipboard, ready to be pasted wherever needed.

picgo_custom_url_format

You can also choose the corresponding format in the link format section, such as URL or Markdown format links that can be used in the blog. Here, I made a small configuration in the left "PicGo Settings" - "Custom Link Format," changing it to ![$fileName]($url), and selected "Custom" in the link format section of the upload area, so that after uploading, it will generate a Markdown image link with the file name as the Alt text.

WebP Cloud Image Optimization#

At this point, we have completed the entire setup, configuration, and upload of the image hosting system. However, the images we typically capture locally or take with a camera tend to be large, which can lead to longer loading times for visitors and are not directly suitable for internet publishing.

tiny_png_compress

For a long time, I used a very cumbersome method, which involved using the API of the online website "TinyPNG" combined with an open-source macOS client application to drag images in for compression before uploading them to the image hosting via PicGo. This usually reduces the image size by more than 50% with minimal quality loss, which is cumbersome but effective.

After switching the image hosting solution, I also started looking for a more intelligent image optimization service and thought of "WebP Cloud".

I actually learned about this service one evening last year while watching someone play a rhythm game in an arcade in Hangzhou with STRRL. He showed me a blog post by Nova Kwok that had topped Hacker News, and we watched it for a while. However, at that time, I only knew it was an image optimization service and didn't delve into the details.

So I went to the official website "webp.se" to take a closer look at the detailed introduction.

webp_se_intro

In simple terms, this is a CDN-like image proxy SaaS service that can significantly reduce image size without changing the quality much, speeding up overall site loading times. Now, in addition to reducing image size, it also offers caching, watermarking, image filters, and more practical features, along with options for custom headers.

After reviewing it, I felt it could meet my blog's image optimization needs well, so I started tinkering with the configuration.

Configure WebP Cloud#

webp_cloud_login

First, log in to the WebP Cloud platform via GitHub authorization.

webp_cloud_overview

The page is very intuitive, mainly displaying the Free Quota and additional Quota data under the current Plan, along with some usage statistics.

Click the "Create Proxy" button to add a configuration.

webp_cloud_config

  • To optimize access in China, I chose the West US "Hillsboro, OR" region for "Proxy Region."
  • For "Proxy Name," just fill in a custom name.
  • For "Proxy Origin URL," which is quite important, fill in the custom domain we configured for R2, such as yu-r2-test.pseudoyu.com. If you haven't configured a custom domain, fill in the R2 provided domain in the format of xxx.r2.dev.

yu_webp_test

In the Basic info section, the "Visitor" under it shows the proxy address in the format of xxx.webp.li.

For example, the file we previously uploaded to R2 via PicGo yu-r2-test.pseudoyu.com/new_mbp_setup.jpg can be accessed via dc84642.webp.li/new_mbp_setup.jpg.

If you don't like the default proxy address, you can contact the developer via chat or email in the lower right corner to request a custom domain modification, and perhaps there will be a more automated configuration process in the future.

You can also adjust the image compression ratio using a slider, with the default set to 80%. A 5MB JPG image typically compresses to less than 1MB in WebP format, which generally meets the needs for internet dissemination. The other configurations can remain as defaults, but you can adjust them according to the documentation if needed.

Change PicGo Configuration#

change_pic_go_config

It is important to note that since the images we ultimately need to place in the blog are links that have been proxied through WebP Cloud, we need to return to the "Image Hosting Settings" in PicGo and change the "Custom Domain" to the proxy address we just configured, which is in the format of xxx.webp.li or another custom domain.

WebP Cloud Usage#

Free users have 2000 Free Quota per day, meaning they can proxy 2000 image access requests and provide 100MB of image caching, which is more than enough for general users. If there are specific periods of high traffic, additional Quota can be purchased at a very low price.

If the Quota is exceeded, access will be redirected to the source image address with a 301 redirect, bypassing the WebP Cloud service compression, but it will still be usable; if the cache exceeds 100MB, it will be cleaned according to the LRU algorithm, ensuring that frequently requested images still have a good access experience.

yu_webp_uasge

My blog's daily visit count is around 300-500 visits, plus some RSS subscriptions and crawler traffic. According to WebP Cloud's statistical estimates, the daily requests are around 4000-5000, and on the day of publishing a blog post, it can exceed 10,000.

webp_cloud_price

So for now, I chose the Lite plan, along with some additional usage to cover peak traffic, and I plan to observe for a while.

Conclusion#

This is my image hosting system setup plan. All the images in this article were uploaded using PicGo, stored in Cloudflare R2, and optimized through WebP Cloud.

This is one of my tutorials on building and deploying a blog. If you are interested in setting up comment systems, data statistics systems, etc., please stay tuned, and I hope it can serve as a reference for everyone.

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.