Owning Your Infrastructure
Tying every side project to Big Tech platforms feels convenient until it isn’t. Terms of service change, outages happen, and eventually, you realize you don’t actually own your workflow. If you are running a HomeLab, you probably want a Git server that lives on your hardware and doesn’t swallow 4GB of RAM just to sit idle. GitHub and GitLab are excellent, but they are overkill for many self-hosted setups.
I hit my breaking point when a GitLab instance started choking my VPS. I needed a tool that felt like GitHub but ran with the efficiency of a native binary. That is where Forgejo shines. It is a community-driven fork of Gitea, created in late 2022 to ensure the project remains truly open-source. In my testing, Forgejo handles dozens of repositories while consuming less than 500MB of RAM, making it perfect for modest hardware.
Why Forgejo Instead of Gitea or GitLab?
You might wonder why we are picking Forgejo over Gitea. After Gitea transitioned to a commercial model, the community launched Forgejo to prioritize users over corporate interests. It maintains 100% compatibility with Gitea but stays focused on the “Free Software” mission.
Compared to GitLab, Forgejo is a lightweight champion. While GitLab is a powerful beast requiring significant CPU and memory, Forgejo delivers the essentials—issue tracking, pull requests, wikis, and basic CI/CD (Actions)—at a fraction of the cost. It runs perfectly on a Raspberry Pi 4 or a basic $5-per-month cloud instance.
Preparing the Environment
Before jumping into the terminal, ensure you have Docker and Docker Compose ready. We will use PostgreSQL instead of the default SQLite. While SQLite is fine for one-person setups, PostgreSQL handles concurrent connections much better as your repository count grows. It also makes your backup strategy more professional.
Start by creating a structured directory to keep your configuration and data together:
mkdir -p ~/homelab/forgejo
cd ~/homelab/forgejo
mkdir data db
The Docker Compose Configuration
We will define two services: the Forgejo application and a PostgreSQL 15 database. This separation is a standard DevOps practice. It ensures your data lives in a managed environment, making updates and migrations significantly safer.
Create your docker-compose.yml file:
services:
server:
image: code.forgejo.org/forgejo/forgejo:latest
container_name: forgejo
restart: always
environment:
- USER_UID=1000
- USER_GID=1000
- FORGEJO__database__DB_TYPE=postgres
- FORGEJO__database__HOST=db:5432
- FORGEJO__database__NAME=forgejo
- FORGEJO__database__USER=forgejo
- FORGEJO__database__PASSWD=your_secure_password
networks:
- forgejo
volumes:
- ./data:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- "3000:3000"
- "2222:22"
depends_on:
- db
db:
image: postgres:15-alpine
restart: always
environment:
- POSTGRES_USER=forgejo
- POSTGRES_PASSWORD=your_secure_password
- POSTGRES_DB=forgejo
networks:
- forgejo
volumes:
- ./db:/var/lib/postgresql/data
networks:
forgejo:
external: false
Crucial Config Notes
- USER_UID/GID: Set these to match your Linux user (usually 1000) to prevent permission errors when Forgejo tries to write to your
./datafolder. - SSH Mapping: We map port
2222to the container’s port 22. This prevents conflicts with your host machine’s primary SSH service. - Database: The
alpineimage variant keeps your total disk footprint under 300MB.
Launching the Server
Spinning up the server takes a single command. Run this and wait for the containers to initialize:
docker compose up -d
Once the command finishes, keep an eye on the logs to ensure the database connection is healthy:
docker compose logs -f
Now, point your browser to http://[your-server-ip]:3000. You will see the setup screen. Because we defined the database credentials in the environment variables, Forgejo will pre-fill most of the technical fields for you.
The “Must-Fix” First Steps
Do not just blast through the installation. A few small tweaks now will save you hours of troubleshooting later:
- SSH Port: Change the SSH server port in the UI to
2222. This ensures the clone URLs match our Docker setup. - Root URL: Use your actual domain or local IP (e.g.,
http://git.home.arpa:3000). If you leave this as localhost, clone links won’t work from other computers. - Admin User: Set up your primary account here. In Forgejo, the very first user created is granted full administrator privileges.
Configuring SSH for Fast Commits
Pushing code via HTTPS gets annoying quickly. SSH is faster and more secure. Since Forgejo is listening on port 2222, you should tell your local Git client how to find it. Update your ~/.ssh/config file:
Host forgejo
HostName 192.168.1.100
User git
Port 2222
IdentityFile ~/.ssh/id_rsa
With this config, you can clone using git clone forgejo:username/project.git. It eliminates the need for passwords and makes the workflow feel identical to GitHub.
Backups and Maintenance
Backing up your server is simple because we used Docker volumes. Just stop the containers and compress the forgejo directory. I recommend a nightly cron job to rsync these folders to an external drive or NAS.
Updates are just as easy. Pull the new image and restart the containers:
docker compose pull
docker compose up -d
Forgejo manages database migrations automatically. I have jumped through three major version updates without a single database error. It is remarkably stable.
Final Thoughts
Building your own Forgejo server is one of the most practical HomeLab projects you can tackle. You gain total control over your code, a familiar interface for collaboration, and a system that respects your hardware. Whether you are storing private scripts or complex dev projects, owning your Git server is a massive win for digital sovereignty.
Try it for a week. The speed of a local Git server and the peace of mind that comes with local storage are hard to give up once you have experienced them.

