I’ve wanted to get rid of Wordpress for a while now. It’s more of a hassle than anything else, really. And who on earth still uses PHP? Anyway, a while ago I embarked on the journey to find a good replacement. First, I looked at other CMS systems that are similar to Wordpress, but soon realized that they’d all require me to keep them up-to-date all the time, and they’d likely be just about as annoying. At the same time, I’ve gotten so used to creating web content using markdown, that I hoped I could find something where markdown indeed plays a significant role in building the content. In addition, being a developer at heart, I was hoping to also find something with a decent version control system for history and rollbacks (whenever necessary) and the likes.

Hugo - a modern content management framework

That’s when I ran across Hugo and almost instantaneously fell in love with it: with its simplicty, its flexibility, its speed, and what I considered its focus on what’s truly important. Who cares if you can edit pages and posts in the browser? I know I don’t. Hugo produces static assets: HTML files and such, that can just be uploaded to virtually any web server for static serving of these assets. It can minify those assets too. It won’t get any faster than that. And then, when you combine this with a CDN, you usually get blazing speeds. Accordingly, I’m also considering Hugo for the documentation efforts for the product I work on, well, at work.

Now, I’m sure that what I have to say (or write) is not that important for millions of people to look at it every month, so I don’t need a CDN. But I’m always looking for inexpensive ways to achieve my goals; it’s easy to spend a lot of money and achieve something - the opposite is usually more challenging and thus more interesting. 😄

I’ve been a fan of the Swiss web hosting company Infomaniak for a while, and I’m using it for quite a few things. Hosting this page is just one of them. They do have a free Starter offering for web hosting. It’s very limited (10 MB space, no server-side code), but for a Hugo-powered page, this is quite enough. I’m probably not going to produce content taking up that much space in the next 50 years, so I figured I give it a shot.

I’ve spent the first few days and weeks creating content and uploading things manually, because you know, there wasn’t that much yet. One of the downsides of Infomaniak’s free offering however is, that they do not enable SFTP or SSH access for the hosted space. But they do offer their own FTP Manager, a browser tool to help with uploads (and downloads) of content to the hosted space, through HTTPS. So that’s what I used to upload content manually.

Securly upload content via Infomaniak’s FTP Manager

Next, I looked at bit more at the APIs that the FTP Manager browser GUI was using to navigate, upload, and delete data. It turns out that the API is relatively easy to use, but there’s no documentation, so I had to reverse engineer it. That was still simple enough, so I started crafting some TypeScript code that helps me automatically upload an entire directory structure to an FTP server hosted by Infomaniak, using the APIs offered by their FTP Manager.

Ultimately, my goal was to use GitHub workflows to build the static assets with Hugo and publish them to this site, so I knew that it would probably also make sense to build a GitHub action that uses the TypeScript implementation of uploading through the FTP Manager.

The result of that is infomaniak-uploader, publicly available to anybody who cares.

Usage

Usage of the uploader action is actually quite simple. You need to provide the basics, like the apex domain aka FTP server, the user and password, as well as a local path to take data to upload.

- uses: rokeller/infomaniak-uploader@v1
  with:
    # (Required) The domain name of the FTP server for which to upload the files.
    ftpServer: 'my-domain.com'

    # (Required) The user name of the FTP user to use for login.
    ftpUser: 'my-user'

    # (Required) The password of the FTP user to use for login.
    ftpPassword: ${{ secrets.FTP_PASSWORD }}

    # (Required) The path to a local folder containing the files and sub-folders
    #            to be uploaded. All files and folders from this folder will
    #            be uploaded and the structure is kept. Files that already exist
    #            on the server will be overwritten. Files that exist on the
    #            server but do not exist locally will *not* be touched.
    localRoot: path/to/local/root

    # (Optional) The path on the FTP server to upload to. Defaults to '/'
    remoteRoot: '/about'

One thing though: please do not expect blazing speeds when uploading. While I tried to parallelize as much as possible, the reality is, that the FTP Manager’s APIs are stateful. They seem to keep the current directory in the session, which means that in order to upload files in different directories, one first needs to change directories - or login to multiple sessions, something I didn’t want to implement (yet). That of course makes it impossible to upload files from different directories in parallel currently. However, parallel uploads of files in the same directory are still possible, and so the action does that whenever possible.

Conclusion

Using Hugo to manage and build content, as well as some time to reverse engineer and use the Infomaniak FTP Manager’s APIs, I’ve managed to build a automatic flow for taking markdown based content, versioning through git, and automatic deployments through my own GitHub workflow action. For this site, currently it takes about 2-3 minutes to upload all content (currently roughly 2MB in size). That may seem like a long time, but given that the goal was automation, I would argue that the goal was achieved 😉

What’s left to do is take down my old site (eventually) and be free from Wordpress, finally. 😉