>
B2B SaaS

I built my own Imgur because I stopped trusting other services

When you work on multiple projects, you generate a lot of images. Screenshots of bugs. Mockups of interfaces. Photos of whiteboards with architecture diagrams. User-submitted content that needs a temporary home. The obvious answer is using a service like Imgur, but I have used it for years and I never quite trusted it. Files vanishing. URLs going dead. The occasional surprise ad on a link I thought was private. I finally got tired of it and built my own.

The build took a weekend. The trick was finding the right pieces and gluing them together. If you are the kind of person who runs a homelab and is comfortable with a docker-compose file, you can do this in an afternoon. Here is what I used and why I chose each piece.

What I actually need from an image host

I started by listing what I really needed. The list was shorter than I expected.

  • Direct image URLs that I can paste into a Markdown file, a chat, or a forum.
  • A way to upload from the macOS clipboard with a keyboard shortcut.
  • No tracking pixels, no third-party analytics, no ads.
  • Files that persist for years, not weeks.
  • A way to delete images when I am done with them.

I did not need a social feed. I did not need comments. I did not need a public gallery. The 90% of Imgur’s surface area I never used is the reason I built my own. Less is more.

The pieces I ended up with

I spent Saturday morning reading the self-hostable image host landscape. I tried three before I landed on the one I kept.

  • Chevereto looked the most polished. I spent two hours configuring it and gave up when I realized the free version injects a “powered by” footer. The paid version is a one-time $60 license, which is reasonable, but I do not want a one-time license to be the thing I depend on in 2028.
  • Imgproxy is not a host. It is an image processing proxy. I kept it in mind but it does not solve the storage problem.
  • Picsur is a small Python app that does exactly what I needed. Upload, get a URL, delete later. It uses PostgreSQL (an open-source relational database) for metadata and MinIO (an open-source object storage server that speaks the same API as Amazon S3) for the files. The whole stack is four Docker containers.

I went with Picsur. The code is small enough that I read the whole thing over coffee and felt comfortable running it. That is the test I apply to anything self-hosted. If the source is too big to read in a sitting, I do not run it on a server I care about.

The upload workflow

The real win was the macOS upload shortcut. I wrote a 30-line Raycast extension (a small script that ties into the Raycast launcher for macOS) that takes the screenshot on my clipboard, POSTs it to my Picsur instance, and copies the direct image URL back to my clipboard. The whole thing takes under a second on a local network.

I keep the keyboard shortcut mapped to Cmd+Shift+U. When I take a screenshot with Cmd+Shift+4, the file lands on my clipboard. Then Cmd+Shift+U pushes it to my server and gives me back a URL I can paste anywhere. The image stays on my server until I delete it, and I can browse the uploads at a private admin page.

I also wrote a tiny shell alias that does the same thing from the command line. upload-image path/to/file.png returns a URL. I use that one in shell scripts when I am doing batch uploads.

The cost of running it

The whole stack runs on the same Raspberry Pi 4 (a small, cheap single-board computer) that hosts my other homelab services. Total disk usage after 14 months of daily use is 4.2GB. I run a daily backup to my NAS using restic (an open-source incremental backup tool), which adds 800MB of backup storage for the delta. Both numbers are well below what I would spend on Imgur Pro, which was $8 per month when I last checked.

The single point of failure is the Pi itself. If the SD card dies, I lose every image. That has not happened yet, and I have a 3-2-1 backup rule (three copies of your data, on two different media, with one copy offsite) in place: the primary copy on the Pi, a second copy on the NAS, and an offsite copy on Backblaze B2 (a cheap cloud object storage service). I can rebuild the whole thing in about an hour if the worst happens.

I have considered using Cloudflare R2 (a cloud object storage service with no egress fees, meaning you do not pay to retrieve your own files) for the storage instead of MinIO on my own hardware. R2 has no egress fees, which would matter if I started sharing images publicly at scale. For my use case, mostly internal, the cost is not worth the dependency on a third party.

Trade-offs

Maintenance is the first cost. I am now on the hook for keeping Picsur updated, backing it up, and patching it if a CVE (a public security vulnerability with an assigned identifier) drops. Picsur has had two releases in the last year, both small bug fixes. I spend about ten minutes per month on maintenance. For a service I use daily, that is acceptable. For a side project, it would not be.

Sharing is the second cost. When I send a Picsur URL to someone, the image is served from my home internet connection. I do not have a business-class upstream, so a Slack channel full of people clicking the same link at the same time will be slow. For one-to-one sharing, this never matters. For sharing a screenshot in a public forum with high traffic, I would still use a third-party host.

The upload shortcut is the third cost. Raycast extensions are JavaScript or TypeScript, and I am not a JavaScript developer. I borrowed most of the code from a public example and adapted it. If Raycast changes its extension API in a future release, I will need to maintain it again. I have accepted this.

If you want an image host that just works, and you do not care about privacy or permanence, Imgur is still the right answer. If you have been burned by a vanishing image or a dead link, and you already run a homelab, building your own is a weekend well spent. The migration took me about four hours, including the Raycast extension. Most of that was reading Picsur’s README.

What I would tell past me

If I could send a message back to the version of me that first pasted an Imgur link into a client deliverable in 2017, I would say three things.

  • Self-hosting small utilities is easier than you think. The 30-line Raycast extension is the only custom code. Everything else is a Docker container from a project with active maintainers.
  • Read the source before you run it. Picsur is small enough to read in one sitting. If a project is too big to read, that is a yellow flag, not a green one.
  • Backups before cleverness. I would have skipped the offsite copy for a year if I had not been burned by an SD card failure in 2022. The 3-2-1 rule is not optional.

If you have a homelab and a weekend, give this a try. The hardest part is finding the right tool, and I just saved you the search.

Filed under: #file-sharing

Leave a comment