---
title: "#1 - The Great Gitea Migration"
slug: "1-the-great-gitea-migration"
published: true
date: "2025-08-27 20:19:51 UTC"
tags: ["CampfireLogs", "SelfHosting", "Devops", "gitea", "Campfire-Logs"]
canonical_url: "https://campfire.dlseitz.dev/1-the-great-gitea-migration"
header:
    image: "assets/header/1-the-great-gitea-migration.jpg"
    attribution: 'Photo by <a href="https://unsplash.com/@lc_photography?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash">Leon Contreras</a> on <a href="https://unsplash.com/photos/selective-focus-photography-of-marshmallows-on-fire-pit-YndHL7gQIJE?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash">Unsplash</a>'
---

Hey everyone! Welcome to my first *full* blog post for ***Campfire Logs: The Art of Trial & Error***. My initial post, [#0 - Setting Up Camp: A Backstory](https://hashnode.com/post/cmeqsflzr002h02jrgpsrdcxe), introduced me a little and talked some about my goals and vision for this blog. I’ll admit that when I began thinking about the direction I wanted to take this, I was worried that I wouldn’t be able to come up with engaging content consistently (and maybe I haven’t yet).

I quickly realized, though, that topics to write about can and will “just fall into your lap” very easily and repeatedly. This can be especially true when learning to use different tools and techniques with your existing workflow—or if you’re like me, you look at something and think, “Sure! How hard could it possibly be?”

**The Universe to me**: “Well I’m glad you asked…”

Fair warning: this post is longer than my usual campfire chats will be—it’s a full story with a few twists. So you may want to grab a coffee (or some marshmallows and a stick), and if you’re short on time, I’ve included a [TL;DR](#tldr) section just in case. Let’s get to it!

## **The First Server of My Very Own**

Around the end of February, 2025, I spent a lot of time exploring the free-tier offerings of [AWS](https://aws.com) and its services ([EC2](https://aws.amazon.com/ec2/), [RDS](https://aws.amazon.com/rds/), [S3](https://aws.amazon.com/s3/), etc.). I still had just under 6 months of school left, but I was applying to tech-job after tech-job anyway because I knew it was (and still is) a long road. At the time, being 37 and still in college, transitioning from the food- and public-service industries into Tech was (and still is) pretty intimidating and overwhelming. So I was trying hard to find something (anything) that might help make me look attractive to potential employers.

At the same time, I was learning to use [Git](https://git-scm.com/) more consistently, and because of my natural tendency to look for alternatives to the mainstream options (yeah, I’m rebellious like that), I stumbled upon [Gitea](https://about.gitea.com). For those who aren’t familiar with Gitea, it’s an open-source, self-hosted Git service that has a similar feel and functionality to [GitHub](https://github.com/). If you’re privacy-conscious or simply just want better control over your projects and codebase, it’s a great alternative to the more popular Git services available. But I digress…

Thinking that a self-hosted Gitea server could be a step toward standing out more and because I was already becoming more familiar with cloud infrastructure, I started [Googling](https://google.com/) and [ChatGPT-ing](https://chatgpt.com/) where to start. It turns out that setting up the server really wasn’t all that difficult, but that doesn’t mean I was confident building it out.

Long story short, I registered a cheap domain with [Porkbun.com](https://porkbun.com/), installed Gitea on a free-tier EC2 instance, pointed new domain’s [A Records](https://www.cloudflare.com/learning/dns/dns-records/dns-a-record/) to the IP address I reserved for the server, and set up a [reverse proxy](https://www.cloudflare.com/learning/cdn/glossary/reverse-proxy/) using [NGINX](https://nginx.org/). I won’t lie—I felt like a million bucks because I accomplished something through my own undertaking that, up until that point, I had only studied about in school.  
  
I played around with it for a couple of weeks, and then, just like you did with that new toy you got for Christmas when you were 10, I didn’t touch it again for months.

## **‘The Ecosystem’**

Fast-forward to the near-present, and with my bachelor’s degree finally in hand (exactly twenty years after high school), all I have to show for a nine-month-long job search is an inbox full of rejection emails. Got it. A degree isn’t enough to get a job anymore. That’s not really how they market this at universities these days, but something will come along. No rush, right?

Well, not exactly. You see, I can’t just sit still. I have to keep moving, to keep doing, to keep building something… I decided that I needed to build my own experience to—you guessed it—try and make myself more attractive to potential employers AND *potential clients*. How, you ask?

Well I’m glad you asked…

Being the resourceful person that I am—or being a “MacGyver” of my generation, rather—I can be pretty good at doing the most while having very little to work with. So what did I have to work with? A laptop with [VS Code](https://code.visualstudio.com/), an internet connection, and a free domain through [Name.com’](https://name.com)s partnership with [GitHub Education’s Student Developer Pack](https://education.github.com/pack)… I’d find a way to make it work. Why not pull my long-forgotten Gitea server out of the back of the closet too? The [EC2](https://aws.amazon.com/ec2/) instance was still running, and I still had that domain for a few months longer. This was shaping up better than I thought already!

Cue the registration of [dlseitz.dev](https://dlseitz.dev), a sort of live portfolio that I could expand on as I go. What better way to show I can build something with modern tools and the skills I just spent four years developing, right? It didn’t take long, though, before I realized just a website wasn’t going to be enough.

Over the next few weeks, I decided to explore what a static site generator (SSG), particularly [11ty](https://www.11ty.dev), could do to improve my website coding. From there, I decided I needed a backend application built on [Node.js](https://nodejs.org/) with [Express](https://expressjs.com/) to securely process the contact form on the site, store it in a [PostgreSQL](https://www.postgresql.org) database, and email me the user’s inquiry. I also needed to come up with a way to present live demo sites, each being designed with specific business needs in mind, in a way that wouldn’t complicate the website itself. Hosting them as subdomains of my site was my answer. From there, I wanted a way to share my experiences with others (my work is only possible by building from the work others put in first), but I want the solution to be my own (I’m really into self-hosting if you can’t tell by now). With that still being in the planning and discovery phase, I also wanted to be able to chronicle the journey of building it as I went (thanks [Hashnode](https://hashnode.com)!).

So clearly, in the natural progression of things, and with my Gitea server’s domain expiring in a few short months, I decided this was the perfect time for pulling the server into the ecosystem by migrating it to its own dlseitz.dev subdomain.

Now, with all of this going on, you may be wondering if I’m only saying things at this point just to say them, but I’m not. I guess I’ve finally started to lean into a passion for developing (we already established that I’m a late bloomer). Right now, at this point at least, I *don’t* feel like I’ve bitten off more than I can chew, but don’t we all feel that way right before we *really* get going on a project?

## **‘Domain-Level Migration’… Sounds kind of scary, huh?**

### **What a Domain-Level Migration Really Means**

So what exactly is a domain-level migration? It’s a pretty broad term, but simply put, it’s moving something like a website, a web app, or even an entire Active Directory from one domain to another. This can range in scope from physically migrating from one infrastructure to another to simply changing which domain’s DNS records point to a particular server where a website or web app is hosted, and of course, everything in between.

### **Planning the Changes**

When performing a migration of any kind, you should always start by writing (or typing, if you prefer) a well-informed, step-by-step action plan, including contingencies for any points of failure that you can identify. Having a Plan C or D can often be just as important as Plan A is. I can’t stress that enough. For my migration, I had a few options to consider, and to be honest, I’m not really sure if I’m happy with the route I chose, at least as a long-term solution. That doesn’t mean I chose the wrong option, but it can end up affecting my other projects down the road.

### **Choosing My Migration Path**

Given my remaining time on [AWS](https://aws.com)'s fairly generous 12-month free tier, I had no immediate need to decide on a long-term home for my Gitea server. This was the main reason I opted for a simple, in-place migration, focusing on changing the domain and internal configurations. I also prefer having my ecosystem spread across multiple cloud providers to avoid vendor lock-in, as I use a [DigitalOcean](https://www.digitalocean.com) droplet (similar to an AWS EC2 instance) for the server hosting my web app . For my use case, the networking overhead is negligible, and a distributed setup helps keep me in a "separation of concerns" mindset. I believe maintaining this mindset at a more abstract level influences how I approach developing solutions as a whole, so I figure why not give it the best shot possible. I know this might sound silly to some, but I'd rather not get stuck with all my eggs in one basket.

With a simple plan for this migration (an in-place transition) now in place I was ready to get started.

### **Step One: Update DNS Records**

First, I had to update the DNS records for the new subdomain. Normally I would have done this through my domain registrar (Name.com for this particular domain), but I had just swapped to letting [Cloudflare](https://www.cloudflare.com/) manage my DNS for the domain and subdomains because they will automatically renew your [SSL](https://aws.amazon.com/what-is/ssl-certificate/) certificates from [Let’s Encrypt](https://letsencrypt.org/) every 90 days. Once I configured the new A Record (DNS) to point my subdomain to the static IP address of my EC2 instance, it didn’t take long to propagate. I won’t lie--I was a little sad to have to say goodbye to the old domain. It was a bittersweet moment (I’m not crying… you’re crying).

### **Step Two: Hunting Down Config Files**

My next step was to stop the Gitea process running on the server, and then get ready to make some edits to some config files. It was about now that I remembered I never got around to documenting where I installed everything on my EC2 instance back in February. Of course, me being me, I didn't use their default locations, either, so I had to go on a digital scavenger hunt to find the app.ini and the correct NGINX server block. After a good bit of searching, I finally found them (and documented their whereabouts in my dedicated [Notion](https://www.notion.so/) dashboard: Derek’s Dev Infrabase… catchy, right?). Now for the nerve-racking part.

I've broken a system or two by messing up a config file, so even something as small as a single out-of-place comma or semicolon can cause a total catastrophe. With that in mind, I quite anxiously tiptoed through the configuration files, changing only the settings necessary so that Gitea would recognize its new home. To my dismay, this part actually went off without a hitch. You can imagine the relief.

### **Step Three: SSL Certificate Troubles**

The real test came when I tried to download and install my Let’s Encrypt [wildcard SSL certificate](https://www.digicert.com/faq/public-trust-and-certificates/what-is-a-wildcard-certificate) to secure the new [gitea.dlseitz.dev](http://gitea.dlseitz.dev) subdomain. The dominoes started to fall immediately. First, trying to install [Certbot](https://certbot.eff.org/) and the [certbot-dns-cloudflare plugin](https://certbot-dns-cloudflare.readthedocs.io/) resulted in a Python versioning issue. I had to install [pip3](https://pypi.org/project/pip/) on its own because it didn’t install with Python. But even after that, getting the plugin to work was like trying to drop a toddler off at daycare—SO MANY DEPENDENCY ISSUES.

To resolve this, I had to install [snapd](https://snapcraft.io/docs/installing-snapd), a separate package manager for Linux, to correctly install the plugin. Once all of that was done, I realized the config file with my Cloudflare API token had a small syntax error that was keeping Certbot from obtaining my SSL/TLS certificate. When I realized what the issue was, it was an easy thing to fix.

### **Final Hiccup: SSH Blocked by Cloudflare**

With the certificate installed and the Gitea process restarted, I was very happy that the updated domain directed as expected. I wasn’t quite finished yet, though. I tried to push test commits from my local repos to the remote server, but it wouldn't work. I kept getting a rather nerve-racking error that used alarming terms like “Fatal,” “access rights,” and “make sure the repository exists.” After a few failed attempts and a good bit of head scratching and grounding exercises (therapy finally came in handy), I finally asked [Gemini](https://gemini.google.com/) (Google’s generative AI model), explaining what I had just done with the server. It quickly told me the likely reason I couldn’t push was because I was doing so using [SSH](https://www.cloudflare.com/learning/access-management/what-is-ssh/), and that Cloudflare blocks SSH connections on port 22 on all proxied subdomains for security reasons.

The solution was literally as simple as flipping a switch. I just had to turn off Cloudflare's proxy for my Gitea subdomain. And with two clicks, it was done.

### **Made It Out Alive**

All in all, the migration really wasn’t that problematic. A few frustrating hiccups happened, but a good rule of thumb is to always expect that something will stray from even the most well-laid out plan.

***The end.***

## TL;DR

I migrated my old self-hosted Gitea server onto my [dlseitz.dev](http://dlseitz.dev) subdomain. DNS went smooth, configs weren’t too scary, SSL certs gave me grief, and Cloudflare blocked my SSH until I flipped a switch. Lessons learned: always document installs, expect dependency hell, and don’t panic when you see “fatal” in error logs.

## **Before You Go**

I want to say thanks again to everyone for reading this. I appreciate you sticking around for this campfire story. I know it is a little on the hefty side, but I really hope it wasn’t too much of a snooze-fest to you.

I encourage you to tell me what you thought about the article (what worked for you, what didn’t) in the comments. Or perhaps you have some suggestions on how I could have handled the migration better—let me know that, too. I’m always looking to learn and improve.

Also, be sure to check back soon for the next installment. I will be talking about how easy it can be to overlook a needed component of a project, what that can mean down the road, and you can bet that I have a story to go along with it!