A bootstrapper's tech stack

At the start of 2020 I had no idea about or experience in building websites, managing databases or handling payments online.

For someone that wanted to start an online SaaS business, it meant learning all of these things and building the systems around them.

Luckily, I knew and had worked with someone who had - my friend Joe, from Var Digital. Joe's a freelance web guru with a ton of experience and helped me set up the initial stack.

I love reading about the internals of products - a lot can be learned by studying them. So this article aims to add to that collective knowledge. It will be useful to anyone planning to start their own online business or just to satisfy your curiosity about what makes such a startup tick.

So lets learn about the internals of Thankbox. As you're reading this, you'll see one word repeated often and that is speed. From starting to work on Thankbox to launching it took just 2 months. All of the tech choices listed here were implemented in that time and have hardly changed since.

Server hosting - Digital Ocean droplet

Starting with the lowest layer - Thankbox is (currently) hosted on a droplet (server) that Digital Ocean offer. 1CPU, 2GB RAM, 25GB SSD for $10 a month. I started off on their smallest $5/month one but had to upgrade since I needed more than 1GB of RAM.

I think it can run on this for quite a while, even with decent scale purely because Thankbox isn't the type of service that has continual, constant demand on the server. There are peak times but nothing that has forced me to upgrade so far.

The downside of a small machine like this is that new deployments spike memory and CPU usage up. I once crashed it by doing 3 consecutive ones 🙈. Thankfully I've since solved this in part by leveraging asset pre-compilation using Laravel Lasso.

My MySQL database also runs on the same droplet. Digital Ocean offer a separate DB cluster but that starts at $15/month and seemed overkill for what I need. I won't really need to host the DB separately until I have multiple droplets.

I can keep upgrading like that a few times before I consider going for multiple droplets + a load balancer or something more adventurous like serverless.

Image hosting - Cloudinary + S3

All user-uploaded images are hosted on Cloudinary or AWS S3. Cloudinary have a very liberal free tier which Thankbox was on until it started scaling massively in late 2020.

Cloudinary measures usage in "credits" - of which you get 25 a month for free. Doing image transformations (think dynamic resizing), storage and bandwidth use all use credits. I now pay for the $99/month Cloudinary tier, which is expensive but it's worth it for the awesome service it is. They actually have a cheaper startup plan with 60 credits at $29/month but I blasted past that very quickly.

30 days of usage in Cloudinary. 

Most people opt to attach a GIF to the messages they leave their friends, and those are just hosted by Giphy resulting in no hosting costs for me.

I don't want to store uploaded images on Cloudinary indefinitely since that will eat up credits. Instead what I do is move old media (older than 30 days) from Cloudinary into an Intelligently-Tiered S3 bucket for cheaper long term storage. This is fine since after a Thankbox is sent it's not really accessed again often, if at all, so I'm ok with non-optimized images loading a little slower then.

Apart from that I also use S3 to host regular database backups and to handle Thankbox image downloads. The latter is more interesting. When a recipient wants to download their Thankbox as an image, it's generated server side and it's stored in an S3 bucket for a day. The user is then given a link to it to download.

Web Framework - Laravel + Vue

Joe and I had a conversation about building and iterating fast and he said "For pure speed, nothing beats Laravel".

At its core Thankbox runs on Laravel, and is written in PHP 7.4. Laravel is an absolute delight to work with. From its great, fluent Eloquent ORM, to its really robust queue system and most especially, its diverse ecosystem that's developed great open source packages - I am absolutely in love with it. Main reason being is that building things feels fast with it. It's opinionated, and I like that. I like someone telling me "this is the way you should write to make most of the framework". It allows me to focus on the product I'm building, not so much on how it's built.

Laravel's documentation is some of the best I've seen

The frontend is mostly a Vue SPA (Single Page App), written in Typescript. I say mostly, because some server side rendering is used (in the form of Laravel blade templates) for things like the landing and about pages and a few other static ones. You can build your frontend in whatever you want with Laravel, but Vue is what they use most as an example. I like Vue, though it did take me awhile to understand how you're meant to use things like v-model correctly.

For CSS I use Tailwind. As someone who'd never used CSS before, Tailwind is a super friendly and easy way to get into it. All the class names make sense and you can make your pages looks nice very quickly.

Using Vue together with Tailwind encourages you to do really small, self-contained components that hold their own CSS so as to not have a bunch of html with really long class descriptors in your pages. Adam Wathan (Tailwind's author) has numerous talks on this topic.

Deployments & server management - Laravel Forge

Laravel is open source and the primary way it makes money is by having a lot of first-party paid integrations you can use. The main one being Forge, which provides really easy server management and deployment for your Laravel project. I'm on the basic tier at $12/month and it's totally worth it. You just point it to your Github repo, connect your Digital Ocean or AWS server & off you go. Anytime you push up a new version of your code, Forge will deploy it. If there's any issues, it'll ping you on Slack. It makes it super easy to manage your .env variables, any running daemons (which you need for the Laravel queue) & setting up cron jobs. I'm OK at the command line but not fantastic, so I like a nice UI around my Linux box.

Higher tiers let you manage more servers and offer automated database backups and uptime monitoring. The latter two I've handled myself so the only reason I'd consider upgrading is if I have to manage another server.

Admin & database analytics - Laravel Nova

As my main concern is growing my product, I need reliable analytics. I also need some basic admin functionality for editing, deleting, etc...

Here is where another sweet Laravel product, called Nova helps me out. For just $99, it's a really slick, easily configurable admin panel.

Like Laravel itself, Nova has an opinion about how your admin panel should look and be styled. That allows you to, guess what, go fast! You write absolutely no frontend code. Instead, you hook it up to your Eloquent Models (database) via its own concepts called Resources and it just shows you what you want.

Want to track a metric? You run php artisan nova:metric MyMetric and half the code is written for you. You can make it as simple or as complicated as you like.

When I needed to add coupon code functionality to Thankbox, it took me 5 minutes to add some code in Nova to generate new codes I could give away. I love it.

I've spent collectively less than a week on Admin code. Nova is just so nice.

Sending emails - Mailgun

Thankbox relies heavily on emails for its functionality. The most important part is that once a creator pays, their Thankbox is delivered via email to the recipient. For handling transactional emails, Mailgun was my choice. There's probably cheaper alternatives, but its free(flex) tier is pretty generous and Laravel has direct framework support for it.

I've achieved sufficient mail volume now so I am on their first tier at $35/month. I'll soon probably be moving to the one up from that.

Mailgun's webhooks are a great feature, too - and, thankfully, available on the free tier. I use one to track failed delivery of Thankbox emails to a recipient, in which case I email the creator to let them know.

Payments - Stripe

Not even sure I need to mention this, but obviously Thankbox uses Stripe for handling payments. Top of the line documentation, really easy to use SDK and a provided sandbox layer for testing payments is what I love best about it.

Laravel has a wrapper around it, called Cashier, but it's mostly around making subscription-code easier. Seeing as I just handle one-off payments in Thankbox for now, I just use the Stripe PHP and JS SDKs directly.

I heavily rely on Stripe's webhooks to make sure all payment-related actions are only executed once Stripe verifies a payment has been made.

Website Analytics - Fathom

I really, really dislike Google Analytics and what it has done to the web. It's great to see that in the last few years there have been a number of new, privacy focused analytics solutions that are being adopted at an increasing rate. Fathom is one of those solutions. They are aggressively privacy-focused, meaning I don't need to have an annoying cookie-banner on my landing pages.

They also don't burden you with the crazy GA dashboard. Instead, they offer a really simple one that just gives you the info you need. I only track visits on my static and landing pages, so I appreciate the simplicity.

It's not the cheapest, compared to some other similar alternatives, but it's one I feel I can rely on. Oh, and it's actually also built in Laravel!

I am not fully against user tracking. I've written about how to conditionally track users coming off search ads without letting trackers take over your site.

Error Reporting & Uptime - Honeybadger

It's always, always a good idea to have an external error & crash reporting tool. I opted to use Honeybadger. You get quite a bit on their free tier, which provides crash reporting, uptime monitoring & up to 5 check-ins.

They've got a Laravel plugin, which makes setup really easy on the server side. With a bit of config, I also use it to report frontend errors that occur in Vue.

The check-ins feature is quite cool. With Laravel, you can have scheduled commands that run on a set interval - think of it like a wrapper around a cron job. With the Honeybadger plugin you can ping Honeybadger to let it know when a command is completed. If any fail to check-in, Honeybadger will let you know, similar to server uptime monitoring.

Log monitoring - Papertrail

Logging is probably the least exciting job for any programmer, but it's an important one. Laravel has a handy Log wrapper which you can use to log whatever you want, like Log::info or Log::error .

Apart from being stored on the server, for production, I've instructed all logs to also get sent to Papertrail. They give you a simple log visualisation in their app and allow you to set alarms when certain words are found in your logs. For example, any time a warning or error log is sent to Papertrail I've got an alert that pings me on Slack to let me know.

The free version gives a log storage of 7 days, though only the last 48 hours are searchable. The next tier over starts at $7/month so I might consider upgrading if I find myself needing the extra storage. I doubt it, though, since I don't actually send a huge amount of logs over to it.

Conclusion

As you might have seen, a lot of my service choices were made on how easy they are to integrate with my web framework of choice. I understand that this blog post can read like love letter to Laravel, but you could do the same with Ruby on Rails, Django or any other established framework.

Established is the key word here. It's important pick something that's been around for a while, has a good community around it & ideally has integrations with the services you'd need so that you can set up quickly and get going. As a technical startup founder your aim isn't to reinvent the wheel - it's to leverage your skills and what's already available in order to build and iterate quickly.