Previous Page

nihilist@mainpc - 2024-11-23

Forgejo .onion Setup (Anonymous Code Repositories and Collaboration)

In this tutorial we're going to take a look at how you can setup an anonymous Forgejo instance (which was previously known as Gitea before the hard fork) that is accessible over Tor, in order to be able to collaborate with people on projects, while maintaining everyone's anonymity.


Notes on why you should use Forgejo instead of Gitea: 

Forgejo was created in October 2022 after a for profit company took over the Gitea project. It exists under the umbrella of a non-profit organization, Codeberg e.V. and is developed in the interest of the general public. In the year that followed, this difference in governance led to choices that made Forgejo significantly and durably different from Gitea.

Disclaimer: If you are a developer working on projects that aim to reduce governmental control, such as working on privacy-cryptocurrency projects (ie Monero, Haveno, Crypto Mixers, etc), take some time to consider stopping maintaing/contributing to those projects under your public identity, and rather shift to maintaining those projects under an anonymous identity (which is the aim of the following Forgejo setup).

You never know when your tyrannical government is going to snap and decide to make an example out of you, just like what happened to Tornado Cash. It is a matter of adapting your OPSEC to the intended internet use. Don't paint a target on your back and give any ammunition to the adversary, because they're going to shoot you with everything you give them (your IRL name, what you contributed on the project, taking things you said out of context, etc). Tyrants don't care, even if it they have to step on your freedom of speech (as that's what developing code is) to keep their control over the masses, they will do anything to keep their control intact.

Sidenote: Help us improve this tutorial by letting us know if there's anything missing or incorrect on this git issue directly!

Why is this relevant ?

First of all, Git is a distributed version control system that tracks versions of files. It is often used to control source code by programmers who are developing software collaboratively. It is especially popular in the FOSS community as it allows anyone to contribute to projects.

The place where you can find the most repositories online is Github, but the problem is that Github has been purchased by Microsoft.

Now the problem with trusting a business to host your code repositories that reduces governmental control (such as Tornado Cash) is that those governments can use any company (such as Microsoft in particular) to do their bidding, such as infringing on your freedom of speech, censoring you and deleting your work from the platform.

The source code for crypto transaction mixer Tornado Cash has disappeared from Github barely 24 hours after the US Treasury Department added the privacy tool to its sanctions list. Highlighting how Microsoft is a proxy that the US Government uses (more often than you think) to persecute anyone they don't like.

That is why Github should not be relied on to host any code repository that threaten governmental control, we need an alternative that we can host ourselves, to break free from that governmental control. Which is where Forgejo comes in the picture.

Forgejo is a painless, self-hosted, all-in-one software development service. It includes Git hosting, code review, team collaboration, package registry, and CI/CD. It is similar to GitHub, Bitbucket and GitLab. The most important part being that it can be self-hosted.

Now let's suppose you setup your potentially sensitive repositories on a clearnet forgejo instance (meaning the server can be reached directly by a domain name, to it's public IP address. What is stopping the tyrannical government from ordering the VPS provider to shut down the server ? They know where it is located, what server it is on, so they can order it to be taken down all the same, as they will simply force another business to comply with their demands, and this time it will be the server itself that will be taken down.



OPSEC RECOMMENDATIONS:

This is why the Forgejo instance needs to be setup behind Tor, as a .onion hidden service. Now you have a few options as to where to host the the Forgejo service. It can be on a remote VPS that you acquired anonymously (where the cost will be the renting of that VPS, such as 5 euros per month):

Or it can simply be on a server that is running at your own home, at the cost of your own elecricity consumption, and internet connection:

Forgejo instance Setup



Now that we laid out the justifications for this setup, let's set it up on our server using Docker:


[ Datura ] [ /dev/pts/13 ] [/srv]
→ apt install docker.io docker-compose -y  ; systemctl enable --now docker
	
[ Datura ] [ /dev/pts/13 ] [/srv]
→ cd /srv

[ Datura ] [ /dev/pts/13 ] [/srv]
→ mkdir forgejo_onion

[ Datura ] [ /dev/pts/13 ] [/srv]
→ cd forgejo_onion

[ Datura ] [ /dev/pts/13 ] [/srv]
→ cat docker-compose.yml
version: "3"

networks:
  forgejo:
    external: false

services:
  server:
    #image: gitea/gitea:latest 
	# to migrate from an existing gitea instance to a forgejo one all you need is to simply comment this above line, and replace it with the one below:
    image: codeberg.org/forgejo/forgejo:9.0.3
	# but warning, this won't work anymore starting from 1.23.X, 1.22.X is the last version where you can do this seamlessly.
    container_name: forgejo
    environment:
      - USER_UID=1000
      - USER_GID=1000
    restart: always
    networks:
      - forgejo
      - tor-forgejo
    volumes:
      - ./forgejo:/data
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    ports:
      - "127.0.0.1:3009:3000"
      - "127.0.0.1:2222:22"

  tor-forgejo:
    image: osminogin/tor-simple
    container_name: tor-forgejo
    volumes:
      - ./tor-data:/var/lib/tor
      - ./tor-data/torrc:/etc/tor
    networks:
      - tor-forgejo

networks:
  tor-forgejo:
  forgejo:


Now let's setup a docker Tor daemon and the folder it needs to have, as we'll later need Forgejo to connect elsewhere through Tor :


[ Datura ] [ /dev/pts/13 ] [/srv/forgejo_onion]
→ mkdir -p tor-data/torrc

[ Datura ] [ /dev/pts/13 ] [/srv/forgejo_onion]
→ vim tor-data/torrc/torrc

[ Datura ] [ /dev/pts/13 ] [/srv/forgejo_onion]
→ cat tor-data/torrc/torrc
 SOCKSPort 0.0.0.0:9050

[ Datura ] [ /dev/pts/13 ] [/srv/forgejo_onion]
→ chown -R 100:65533 tor-data/

[ Datura ] [ /dev/pts/13 ] [/srv/forgejo_onion]
→ chmod 700 tor-data

now before we run the Forgejo instance, we need to make it reachable via a .onion domain, so let's install tor and generate a .onion domain by following this tutorial:


[ Datura ] [ /dev/pts/13 ] [/srv/mkp224o]
→ ls /var/lib/tor/onions/daturab6drmkhyeia4ch5gvfc2f3wgo6bhjrv3pz6n7kxmvoznlkq4yd.onion
authorized_clients  hostname  hs_ed25519_public_key  hs_ed25519_secret_key

[ Datura ] [ /dev/pts/13 ] [/srv/forgejo_onion]
→ cat /etc/tor/torrc | tail -n 5
HiddenServiceDir /var/lib/tor/onions/daturab6drmkhyeia4ch5gvfc2f3wgo6bhjrv3pz6n7kxmvoznlkq4yd.onion/
HiddenServicePort 80 127.0.0.1:3019
HiddenServicePort 2222 127.0.0.1:2222

[ Datura ] [ /dev/pts/13 ] [/srv/forgejo_onion]
→ systemctl restart tor@default

Now that's done, we launch Forgejo by using docker-compose:



[ Datura ] [ /dev/pts/13 ] [/srv/forgejo_onion]
→ docker-compose up
Creating forgejo-onion ... done
Attaching to forgejo-onion
forgejo-onion | Generating /data/ssh/ssh_host_ed25519_key...
forgejo-onion | Generating /data/ssh/ssh_host_rsa_key...
forgejo-onion | Generating /data/ssh/ssh_host_ecdsa_key...
forgejo-onion | Server listening on :: port 22.
forgejo-onion | Server listening on 0.0.0.0 port 22.
forgejo-onion | 2024/11/23 16:37:01 cmd/web.go:242:runWeb() [I] Starting Forgejo on PID: 15
forgejo-onion | 2024/11/23 16:37:01 cmd/web.go:111:showWebStartupMessage() [I] Forgejo version: 1.22.3 built with GNU Make 4.4.1, go1.22.8 : bindata, timetzdata, sqlite, sqlite_unlock_notify
forgejo-onion | 2024/11/23 16:37:01 cmd/web.go:112:showWebStartupMessage() [I] * RunMode: prod
forgejo-onion | 2024/11/23 16:37:01 cmd/web.go:113:showWebStartupMessage() [I] * AppPath: /usr/local/bin/gitea
forgejo-onion | 2024/11/23 16:37:01 cmd/web.go:114:showWebStartupMessage() [I] * WorkPath: /data/gitea
forgejo-onion | 2024/11/23 16:37:01 cmd/web.go:115:showWebStartupMessage() [I] * CustomPath: /data/gitea
forgejo-onion | 2024/11/23 16:37:01 cmd/web.go:116:showWebStartupMessage() [I] * ConfigFile: /data/gitea/conf/app.ini
forgejo-onion | 2024/11/23 16:37:01 cmd/web.go:117:showWebStartupMessage() [I] Prepare to run install page
forgejo-onion | 2024/11/23 16:37:01 cmd/web.go:304:listen() [I] Listen: http://0.0.0.0:3000
forgejo-onion | 2024/11/23 16:37:01 cmd/web.go:308:listen() [I] AppURL(ROOT_URL): http://localhost:3000/
forgejo-onion | 2024/11/23 16:37:01 ...s/graceful/server.go:50:NewServer() [I] Starting new Web server: tcp:0.0.0.0:3000 on PID: 15
	

Now that's done, let's access our Forgejo instance from the tor browser at the .onion domain we set for it, to setup the initial configuration:

Take note that you can leave everything as it is by default here, except if you want to change the Site Title, take note that there is no need for https in the URL, it is normal for it to remain http. And lastly let's disable registrations, as users won't be using emails to register since we're not going to use the clearnet at all.

Lastly don't forget to create the administrator account at the bottom, and click "Install Forgejo":

Wait a bit for the Forgejo instance to finish setup, and you're done!

Now we need to tweak the instance a bit, so let's edit the app.ini file that is located in /srv/forgejo_onion/gitea/gitea/conf/app.ini:


[ Datura ] [ /dev/pts/6 ] [/srv/forgejo_onion]
→ ls
docker-compose.yml  gitea

[ Datura ] [ /dev/pts/6 ] [/srv/forgejo_onion]
→ cd gitea

[ Datura ] [ /dev/pts/6 ] [/srv/forgejo_onion/gitea]
→ ls
git  gitea  ssh

[ Datura ] [ /dev/pts/6 ] [/srv/forgejo_onion/gitea]
→ cd gitea

[ Datura ] [ /dev/pts/6 ] [forgejo_onion/gitea/gitea]
→ ls
actions_artifacts  attachments  conf      home      jwt  packages  repo-archive  sessions
actions_log        avatars      gitea.db  indexers  log  queues    repo-avatars  tmp

[ Datura ] [ /dev/pts/6 ] [forgejo_onion/gitea/gitea]
→ cd conf

[ Datura ] [ /dev/pts/6 ] [gitea/gitea/conf]
→ ls
app.ini

[ Datura ] [ /dev/pts/6 ] [gitea/gitea/conf]
→ vim app.ini
	

now the first thing i like to do here is to set the default gitea theme to "gitea-dark" by adding the [ui] section at the bottom:


[ Datura ] [ /dev/pts/6 ] [gitea/gitea/conf]
→ cat app.ini | tail -n 3

[ui]
DEFAULT_THEME = gitea-dark

dont forget to restart the gitea docker everytime you edit the app.ini config file:


[ Datura ] [ /dev/pts/13 ] [/srv/forgejo_onion]
→ docker-compose down ; docker-compose up -d
Stopping forgejo-onion ... done
Removing forgejo-onion ... done
Removing network forgejo_onion_gitea
Creating network "forgejo_onion_gitea" with the default driver
Creating forgejo-onion ... done

then on the webpage, hit "Ctrl+F5" to refresh the page and see the new theme:

Forgejo mirroring Github repositories through Tor



Now in order to make sure our Forgejo instance is able to mirror external git repositories from other websites such as github, we need to make sure it goes through Tor to do so, so we need to make sure the gitea container can reach the docker tor daemon, so have to make sure it uses it by adding the [proxy] section in the app.ini config file (Sidenote: the Forgejo container will know that the "tor" hostname refers to the tor docker container, so it is totally intentional as written below):


[ Datura ] [ /dev/pts/13 ] [/srv/forgejo_onion]
→ vim gitea/gitea/conf/app.ini

[ Datura ] [ /dev/pts/13 ] [/srv/forgejo_onion]
→ cat gitea/gitea/conf/app.ini | tail -n 4
[proxy]
PROXY_ENABLED = true
PROXY_URL = socks://tor-forgejo:9050/
PROXY_HOSTS = *

[ Datura ] [ /dev/pts/13 ] [/srv/forgejo_onion]
→ docker-compose down ; docker-compose up -d

And now from there, we should be able to mirror external repositories on gitea by making the traffic go through Tor aswell. As an example, let's create a git mirror of the official Monero repository that currently sits on Github:

Now be aware that it's going to take longer than it usually would to get the repository due to the low bandwidth that Tor has, so be be patient and wait until it finishes:

And there you go! you just managed to mirror a github repository while still making sure the connections go through Tor.

Handling Forgejo repositories through Tor



So now let's create our first Forgejo repository from the web interface:

Now that the repository has been created, we need to push our first commit there so let's follow the instructions:


[ mainpc ] [ /dev/pts/9 ] [~/Documents]
→ mkdir my-very-cool-repository

[ mainpc ] [ /dev/pts/9 ] [~/Documents]
→ cd my-very-cool-repository
	
[ mainpc ] [ /dev/pts/9 ] [~/Documents/my-very-cool-repository]
→ touch README.md

[ mainpc ] [ /dev/pts/9 ] [~/Documents/my-very-cool-repository]
→ git init
hint: Using 'master' as the name for the initial branch. This default branch name
hint: is subject to change. To configure the initial branch name to use in all
hint: of your new repositories, which will suppress this warning, call:
hint:
hint:   git config --global init.defaultBranch 
hint:
hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and
hint: 'development'. The just-created branch can be renamed via this command:
hint:
hint:   git branch -m 
Initialized empty Git repository in /home/nihilist/Documents/my-very-cool-repository/.git/

[ mainpc ] [ /dev/pts/9 ] [~/Documents/my-very-cool-repository]
→ git checkout -b main
Switched to a new branch 'main'

[ mainpc ] [ /dev/pts/9 ] [~/Documents/my-very-cool-repository]
→ git add README.md

[ mainpc ] [ /dev/pts/9 ] [~/Documents/my-very-cool-repository]
→ git commit -m "first commit"
[main (root-commit) b090f42] first commit
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 README.md

Then we can proceed with the rest of the instructions to push the commit to the repository via the .onion Forgejo domain, with the exception of the git push command, where we need to use the torsocks in front of it, because otherwise it won't be able to resolve the .onion domain:


[ mainpc ] [ /dev/pts/9 ] [~/Documents/my-very-cool-repository]
→ git remote add origin http://daturab6drmkhyeia4ch5gvfc2f3wgo6bhjrv3pz6n7kxmvoznlkq4yd.onion/nihilist/my-very-cool-repository.git

[ mainpc ] [ /dev/pts/9 ] [~/Documents/my-very-cool-repository]
→ torsocks git push -u origin main
Username for 'http://daturab6drmkhyeia4ch5gvfc2f3wgo6bhjrv3pz6n7kxmvoznlkq4yd.onion': nihilist
Password for 'http://nihilist@daturab6drmkhyeia4ch5gvfc2f3wgo6bhjrv3pz6n7kxmvoznlkq4yd.onion':
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Writing objects: 100% (3/3), 212 bytes | 16.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
remote: . Processing 1 references
remote: Processed 1 references in total
To http://daturab6drmkhyeia4ch5gvfc2f3wgo6bhjrv3pz6n7kxmvoznlkq4yd.onion/nihilist/my-very-cool-repository.git
 * [new branch]      main -> main
branch 'main' set up to track 'origin/main'.

And that's it! You managed to do your first git commit via Tor !

Sidenote: in the same way you also need to use torsocks to git clone repositories that are on .onion domains:


[ mainpc ] [ /dev/pts/9 ] [~/Documents]
→ torsocks git clone http://daturab6drmkhyeia4ch5gvfc2f3wgo6bhjrv3pz6n7kxmvoznlkq4yd.onion/nihilist/my-very-cool-repository
Cloning into 'my-very-cool-repository'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
Receiving objects: 100% (3/3), done.

Next, if you want other people to contribute to your Forgejo projects, you'll have to do manual registrations as they can't use email to register new accounts:

Once created, simply send the credentials to login to the user that needs them in a private chat (see our recommendation to use SimpleX chat).

BONUS: Customizing Forgejo's appearance



Now if you want to customize your Forgejo instance like i did at https://git.nowhere.moe you'll can first create the templates folder to change the homepage:


[ Datura ] [ /dev/pts/13 ] [/srv/forgejo_onion]
→ cd gitea/gitea

[ Datura ] [ /dev/pts/13 ] [forgejo_onion/gitea/gitea]
→ mkdir templates

[ Datura ] [ /dev/pts/13 ] [forgejo_onion/gitea/gitea]
→ cd templates

[ Datura ] [ /dev/pts/6 ] [gitea/gitea/templates]
→ wget https://git.nowhere.moe/nihilist/Datura-Network/raw/branch/main/2-Decentralization/gitea/gitea/gitea/templates/home.toml -O home.tmpl

[ Datura ] [ /dev/pts/13 ] [gitea/gitea/templates]
→ vim home.tmpl

[ Datura ] [ /dev/pts/13 ] [gitea/gitea/templates]
→ cat home.tmpl | grep pain
                                

A painful, self-inflicted Nightmare

[ Datura ] [ /dev/pts/13 ] [gitea/gitea/templates] → cd /srv/forgejo_onion [ Datura ] [ /dev/pts/13 ] [/srv/forgejo_onion] → docker-compose down ; docker-compose up -d

then to change the logo you can drop your own custom logos in the /srv/forgejo_onion/gitea/gitea/public/assets/img/ directory:


[ Datura ] [ /dev/pts/6 ] [forgejo_onion/gitea/gitea]
→ mkdir public/assets/img

[ Datura ] [ /dev/pts/6 ] [forgejo_onion/gitea/gitea]
→ cd public/assets/img

[ Datura ] [ /dev/pts/6 ] [public/assets/img]
→ ls
apple-touch-icon.png  favicon.png  gitea-192.png  gitea-lg.png      gitea-sm.png  img.tar
favicon.ico           favicon.svg  gitea-512.png  gitea-safari.svg  gitea.svg     logo.svg
	
[ Datura ] [ /dev/pts/6 ] [public/assets/img]
→ cd /srv/forgejo_onion

[ Datura ] [ /dev/pts/6 ] [/srv/forgejo_onion]
→  docker-compose down ; docker-compose up -d

Then, simply refresh the page to see the changes:

Next, if you want a custom CSS theme like the one i have, first be aware that as Forgejo continues to be updated, the CSS theme may break depending on the breaking changes that gitea introduces, it is safer to keep using the default gitea-dark theme. If that's not a problem for you, you can download it from here and put it in the /srv/forgejo_onion/gitea/gitea/public/assets/css/ directory:


[ Datura ] [ /dev/pts/6 ] [/srv/forgejo_onion]
→ cd gitea/gitea/public/assets

[ Datura ] [ /dev/pts/6 ] [gitea/public/assets]
→ mkdir css

[ Datura ] [ /dev/pts/6 ] [gitea/public/assets]
→ cd css

[ Datura ] [ /dev/pts/6 ] [public/assets/css]
→ wget https://git.nowhere.moe/nihilist/Datura-Network/raw/branch/main/2-Decentralization/gitea/gitea/gitea/public/assets/css/theme-space.css
--2024-11-23 20:25:50--  https://git.nowhere.moe/nihilist/Datura-Network/raw/branch/main/2-Decentralization/gitea/gitea/gitea/public/assets/css/theme-space.css
Resolving git.nowhere.moe (git.nowhere.moe)... 65.109.30.253
Connecting to git.nowhere.moe (git.nowhere.moe)|65.109.30.253|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 22754 (22K) [text/plain]
Saving to: ‘theme-space.css’

theme-space.css                100%[=================================================>]  22.22K  --.-KB/s    in 0s

2024-11-23 20:25:50 (310 MB/s) - ‘theme-space.css’ saved [22754/22754]

	

Then make sure this is the default theme that is used, from the app.ini config file, and restart the Forgejo instance to refresh the configuration:


[ Datura ] [ /dev/pts/6 ] [public/assets/css]
→ cd ../../../

[ Datura ] [ /dev/pts/6 ] [forgejo_onion/gitea/gitea]
→ cd conf

[ Datura ] [ /dev/pts/6 ] [gitea/gitea/conf]
→ ls
app.ini

[ Datura ] [ /dev/pts/6 ] [gitea/gitea/conf]
→ vim app.ini

[ Datura ] [ /dev/pts/6 ] [gitea/gitea/conf]
→ cat app.ini  | tail -n 9

[ui]
DEFAULT_THEME = space
THEMES = space, gitea-dark

[ Datura ] [ /dev/pts/6 ] [gitea/gitea/conf]
→ cd ../../..

[ Datura ] [ /dev/pts/6 ] [/srv/forgejo_onion]
→ docker-compose down ; docker-compose up -d

And that's it! You managed to get a customized .onion-only Forgejo instance, effectively forcing whoever that wants to use it to remain anonymous, if they want to deanonymize themselves, it will be out of their own accord later on.

Nihilism

Until there is Nothing left.



Creative Commons Zero: No Rights Reserved

About nihilist

Donate XMR: 8AUYjhQeG3D5aodJDtqG499N5jXXM71gYKD8LgSsFB9BUV1o7muLv3DXHoydRTK4SZaaUBq4EAUqpZHLrX2VZLH71Jrd9k8