Introduction
I've always wanted my own pastebin-like service, for reasons difficult to explain besides “being cool” and more importantly learning purposes, but I never got around to making it because I always thought it'd be a chore. But I can say, after making one, that it was an awesome project.
I don't think it's something that has a lot of uses for most people in the modern-day landscape, with big tech cloud services on every corner of the internet and messaging platforms having their own way of attaching things already. Nonetheless, it is very cool to just send an image with your domain name attached to it, right? Well, at least I've always wanted that.
I first learned about these when I started going to support channels, namely Gentoo Linux's. When there, users will send log outputs of programs, files, or whatever it is that they're having problems with, and that is, I think, the main use of pastebins today—at least in the IT area.
Getting Down to Actually Doing It
As I said, it took me a while to actually start writing it. I procrastinated for several reasons, but mostly because nowadays I wasn't really using IRC all that much anymore and so I had no reason to start doing it. I did try to write a basic one in Python, but that didn't go all that well, mostly because I didn't really know what I was doing and I started by tackling the most annoying things (which I'll explain later).
The push to get me started, though, was when I started getting involved in Chimera Linux's IRC channel. There was a developer there that had their own pastebin-like service, and that finally gave me the confirmation inside my head that it would be something cool to do. I asked about it to them, and they said that it was just a POST handler. Indeed, at its core, it's simply that. That sort of paved the way for me to know what I needed to search for to start doing it on my own, so after that, it was mostly just about doing it.
Writing the Server
Choosing the right language for your project can often be daunting. In my case, I opted for Go. Why? Simply because it feels right. Go, with its simplicity and efficiency, makes building HTTP servers a breeze, which is perfect for a project like this. It’s highly readable, compiles to a single binary and it's very performant. These factors made it an ideal choice for building my paste service.
The heart of the paste service is just handling HTTP POST
requests. These requests contain the data that needs to be uploaded and stored, like text snippets, logs, or files. Once uploaded, the server generates a unique URL that points to the content.
Here’s a simplified version of how I handled the core functionality:
Setting Up the Server
In Go, setting up a basic HTTP server is straightforward:
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/upload", uploadHandler)
fmt.Println("Server started at :8080")
http.ListenAndServe(":8080", nil)
}
This sets up an HTTP server listening on port 8080. Whenever a user makes a POST request to the /upload route, the server will trigger the uploadHandler function, which we’ll define next.
Handling File Uploads
To store uploaded content, we need to handle POST requests properly. Here's a basic function to do that:
func uploadHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
file, handler, err := r.FormFile("file")
if err != nil {
http.Error(w, "Error retrieving the file", http.StatusBadRequest)
return
}
defer file.Close()
fmt.Fprintf(w, "Uploaded File: %v\n", handler.Filename)
// ...
}
This handler checks if the request is a POST method, then parses the form to get the file. After retrieving the file, you can store it in a directory and return a unique URL for accessing it later
Generating the URL
Once you have the file uploaded, the next step is to generate a link to access it. This is where things can be a bit more flexible. You could store the file on your server or even upload it to a cloud service like AWS S3 if you want to get fancy. In this case, I stored the files locally and generated a simple link:
func generateLink(filename string) string {
return fmt.Sprintf("https://yourdomain.com/uploads/%s", filename)
}
Now, when someone uploads a file, they get a URL to access it directly.
In my project I used a different format from what I'm doing here, but the gist of it is mostly the same.
Serving Uploaded Files
To serve the uploaded files, you need to create a new route that serves static content. Here’s how you can serve files from an uploads directory:
func main() {
http.Handle("/uploads/", http.StripPrefix("/uploads/", http.FileServer(http.Dir("./uploads"))))
http.HandleFunc("/upload", uploadHandler)
fmt.Println("Server started at :8080")
http.ListenAndServe(":8080", nil)
}
This code ensures that any file placed in the uploads
directory can be accessed via https://yourdomain.com/uploads/filename
.
Lessons Learned
Building this project was a lot of fun and came with many “aha!” moments. One of the key things I learned was the importance of breaking down the problem. At first glance, creating a paste service seemed complex, but once I broke it down into handling uploads, serving files, and generating links, it became manageable.
Another big lesson was how easy Go makes it to build web servers. The standard library provides all the tools you need, without overcomplicating things. There’s no need for external frameworks (unless you want to), and that’s one of the beauties of Go—simplicity without sacrificing performance.
This project wouldn't have been possible without the many resources available out there like for example for encrypting and middleware logic that I wouldn't have known how to use without those articles. Also big thanks to the awesome Go documentation!
This is the link: https://github.com/jabuxas/abyss to my project in case you wanna check it out! I made it for myself but it has all things one would need for an awesome paste service in case you want to self-host it yourself. Thanks for reading.
written by jabuxas
contact info: jabuxas@proton.me