Bye Bye Imgur

My self-hosted image host is live! Or about as live as it will ever be. That’s because it’s literally something I built for just me! (I’m not selfish but build your own). I wrote part I last week, trashed part II in favor of using it a few days. Well…here we go.

Most of my using imgur dates back to that pesky spinal injury and not having money to buy a VPS. For the previous 10 years, if I wanted to share any kind of file; I’d just upload it to my server. This actually made sense for the longest time; smartphones were not a thing. Anything I’d be able to upload, it’d be from the computer.

But losing the hosting back in 2013; I still needed some place to keep images. It was around this period that I started using Reddit; and just about everything on Reddit used imgur. Even after I got a server back in 2017; out of both habit and lazy ease I kept using imgur. Just drag the file from explorer. Sure, I could drag from explorer in to WinsCP; but I still had to do a lot of URL parsing myself. With Imgur I just right click on the page that pops up with the uploaded image and right click to “copy image location”. When I pull one up from a gallery later; I can just click “copy direct link”.

But those nice features and mobile app for easy uploading couldn’t make up for the constant changes that made it more of a pain to use. Since the vast majority of my uploads come from my phone, having that be a major pain is enough to make the “ok” desktop experience no longer matter.

How The Hell Am I Gonna Do This?

Like anything you’re going to build, you need to figure out what I’m going to build. Saying I want an Imgur clone is fine; but there’s a lot of stuff it does I don’t need or want, stuff I can do without, and probably only a few basic requirements. I ultimately would keep changing the specs as I went along; I’d be lying if I said I already had this set of criteria worked out.

I started in the obvious place by looking at a couple of photo managent systems. There’s no shortage of recommendations; the two biggest being ZenPhotoCenter and Piwigo. ZPC looked like it could probably do what I want; but more than I wanted to dive in to. So I decided to give Piwigo a….go.

That was a lousy attempt at a Piwigo pun.

So Piwigo was a pretty nice overall package and I think I found a mobile app I could set-up. But it would have an issue I didn’t like; and that was how image links were generated. What I wanted was something similar to imgur

https://img.pickmy.org/i/image.jpg

or

https://img.pickmy.org/image.jpg

But Piwigo stored the images in a fashion similar to how WordPress stores them; it stuffs them in folders organized by date and serves them through a php file. 🙁 In fact, most of the systems I found tended to work that way.

Linx-server

So after a while I figured I was probably better off hacking something together than looking for an all-in-one package. Afterall, so much of Linux is just taking multiple programs and stringing them together; so let me just slightly over-complicate it by attacking it this way:

  • have one thing handle uploads (linx-server)
  • have something else generate a gallery
  • figure out how many pieces I can fit without breaking things

As I wrote in my first post, I was quite impressed with linx-server; especially the upload. I wasn’t entirely happy about how it handled images post upload or the lack of a gallery; which lead me to figuring out how to bolt that on. But it was capable of doing a few things I wanted, providing files with randomized filenames (like imgur) that I can directly hotlink to.

See, the way linx-server was designed to run is different than I’m using it. For starters (in case you didn’t read the first post), it’s a self-contained binary that is generating and serving data through nginx via fastcgi. When you upload an image, it actually serves up a page with a file embedded; which is actually similar to what imgur does. If you have hotlinking enabled in linx, you can then access the file directly at whatever path you configure. I had mine set-up for all of img.pickmy.org with this location directive in nginx:

location / {
        fastcgi_pass 127.0.0.1:8080;
        include fastcgi_params;
    }

So one thing I did with my linx-server configuration was set it up to store both the files and generated meta-data within the www-root for the virtual server. In a typical installation, this is probably not what you’re doing. In fact most are probably wanting to use linx-server for everything. For starters, by storing them there I don’t have to modify the server backup script; as it automatically backs up the root folder that everything is hosted out of. But this would lead me down both the path of redundancy, and what I ultimately came up with.

Do Not Taunt Happy Nginx Conf

Before I started figuring out what to use for a gallery; I needed to figure out if I could actually serve one up without breaking linx-server. At the time, linx-server was serving up it’s raw images at /s. Of course; I kinda wanted to unify the URL’s I’d use for images, just to look snazzy in someone’s history; so I changed it to /i in the configuration.

At this point I started poking around what documentation I could find for the location directive. nginx.org has been down for…a while. I seem to recall I wanted to look something up a couple of weeks ago and it was down. So I played around with a configuration and, after a couple of attempts, came up with this goal-reaching directive:

location  /i {
        index index.html index.htm index.php;
                location ~ \.php$ {
                include snippets/fastcgi-php.conf;
                fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
     }
    }

Ok…it’s actually copied and pasted from this morning’s post with a modified location; but after figuring out I could further nest location directives, I successfully had /i behaving like a normal directory serving an index.php file. All I had to do now, was find a gallery program.

Before I went any further, I wasted a little bit of time on something that ultimately would up being really, really stupid:

  location  /i {
        index index.html index.htm index.php;
                location ~ \.php$ {
                include snippets/fastcgi-php.conf;
                fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
     }
              location ~* \.(png|gif|jpg|jpeg)$ {
                fastcgi_pass 127.0.0.1:8080;
                include fastcgi_params;
}
}

While I explain what this does, the way I explain it; you’ll figure out why I can’t even begin to remember why I wanted to do it this way. But the extra location directive, basically passes any request to /i/image.(png/gif/jpg/jpeg)…which is already where the fscking file exists…back to linx-server so it can serve it.

You know the worst part is..it wouldn’t be until after I hacked together one more change and then started writing a now trashed Part II that I smacked the shit out of myself. What I was doing was quite literally the most redundant thing I could do. The files literally already exist at /i/file.ext; why the hell am I redirecting those requests to linx-server.

To further prove how fucking stupid that actually is, here’s the other modification I made to the nginx config:

 location / {
                fastcgi_pass 127.0.0.1:8080;
                include fastcgi_params;
                location ~* \.(png|gif|jpg|jpeg)$ {
                root /var/www/imghost/i;
}
 }

So what’s going on here? When you upload a file to linx-server; it basically returns you a url in the format of https://img.pickmy.org/file.ext. The thing is, as I mentioned; this serves up the linx-server generated page for the image. Now adding /i/ to the URL isn’t the end of the world; but LinxShare (which I’ll talk about), basically automatically copies this URL to the clipboard after uploading. I can make my life even easier using this.

So what do I do? Any request for one of those file extensions triggers a change in root to /i…which is where the file lives…and it loads. Of course as I look at this and look at the location directive for /i; I really start cussing myself out for falling in to the common trap of single-track building. Is there any reason I need Linx-server actually serving the images? I can understand why I would if I was running it like a normal person would.

So, ultimately, I would delete the location directive under /i/ that sent image requests to linx-share; just serve the damn things with nginx. Linx-share is literally just used to provide upload capability.

h5ai (HTML5 Advanced Index)

I looked at numerous options for generating an image gallery; and for reasons I’ve since forgotten, none of them fit my bill. It largely boiled down to either being more static than I wanted, or having some convoluted code that makes getting a direct image link a PITA.

In some forum thread for someone looking for a similar thing, h5ai was mentioned. It’s actually designed to be a replacement for the autoindex option built in to a web-browser. One of the things it will do is generate a thumbnail of an image file. Perfect! In fact; I liked the way it looked. Simple to an insane degree; but got the job done. It did however require some…extra configuration to get working.

        location  /i {
	        root /var/www/imghost;
                index /_h5ai/public/index.php;
                location ~ \.php$ {
		include snippets/fastcgi-php.conf;
                fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
     }
    }
        location /_h5ai {
               root /var/www/imghost;
	       index /_h5ai/public/index.php;
               location ~ \.php$ {
                include snippets/fastcgi-php.conf;
                fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;

I will spare you all the various revisions and commented out lines it took me to get this working. I really should sit down one day and go back to “Muntzing” my configuration. But what I found I had to do was add the location directive for php to the /i block; as well as add a block for /_h5ai with the php directive. I seem to recall not defining /h5ai would cause issues, and not defining PHP within it caused issues.

So with these blocks modified/added-in; nginx was doing exactly what I wanted; img.pickmy.org loads linx-server’s default page; img.picky.org/i/ loads an h5ai generated index of the image folder. Instant gallery.

Mobile Uploading (LinxShare)

So what about getting the images from my phone to my server? How am I going to handle that? There’s an app for it! LinxShare is an Android app that supports uploading directly to your Linx-server installation; you just specify the URL, your API key, share your image with the app, pick your upload options, and hit upload! Once the image is uploaded; the app copies the URL to your clipboard.

This makes uploading an image a three click experience; share on the image, LinxShare in the app menu, then upload. It works so much better than the imgur app for this purpose; less over head. The app doesn’t even require any special permissions or has much of a UI. This is a stark comparison to imgur app which is bloated and always running.

The downside is that LinxShare is not on Google Play store and the developer doesn’t provide a binary. So I actually had to build my own APK from the sources. This wasn’t really that difficult and just took time installing android-studio. I did this on a VM on my home-server since I could give it lots of processor, ram, and a bit of disk space on a RAID 1 array. The phone complained, Android complained, Google Play store really complained; but after swearing on my unborn children I wanted it to install; the app has worked really well. It’s never crashed and failed uploads have been due to lousy network conditions causing a time out.

But I will point out that getting this app working is probably the main reason I went with this setup. In fact, before I even bothered working on the image gallery portion; I knew I needed to have the mobile app. That was about 80% of what was driving my project design. I share a lot of images from my phone to IRC or web-forums and the entire point was to make the process of uploading the image and getting an address easier.

Additional Notes/Mods

Since I haven’t yet moved linx-server’s upload page to a sub-directory; I downloaded the source and added a Gallery link to the page. Realistically; this doesn’t need to be the front page. I’m the only one that can actually make use of it. I made some quick attempts to move the upload page, failed, and decided to just run with it for a while. While I had a pretty good idea this would work the way I wanted; now that I had it fully-functional, I should actually use it before starting to make any other changes.

I’m excited to say in the four days I’ve been using this; it’s worked almost flawlessly. I had a few failed uploads on the app, but I’ve determined this was likely a network issue. Every upload I’ve made on wifi has worked. Every upload from home has worked fantastically too. I’m surprised that I’ve had zero issues with the current configuration; and zero reasons to fire up the imgur app.

My next step will be moving all this stuff around and seeing if I can still make it work. I think I figured out what I was missing when trying to move linx-server’s main page; so I can jump in to the conf and make both that change; and move the storage of photos to the webroot. Some minor changes on the client side will be required as well. Hopefully, the end result is that the main page of img.pickmy.org will be a gallery of images; and the linx-server interface will be “hidden” behind an additional “sub-directory”.

Site comments disabled. Please use Twitter.