# The Premis Last week I started hosting my own git-forge to track sync all of my git projects. Between school, open-source communities, and personal projects, I have accumulated a dubious amount of git projects. Although most of my content gets hosted on Github, I also had a fair quantity of local projects, stuff on scattered GitLab instances, and other places. I decided to use Gitea to mirror all of my repositories and keep them in a central location that I can quickly search for them. ![High Level Flow Diagram](media/gitea/giteaFlow.svg) For simplicity, I decided to host my Gitea instance on a DigitalOcean droplet using docker and add SSL encryption using a reverse Nginx proxy using a let's encrypt. # Installation The first step was to set up a VM in the cloud. I used a base Debian server on Digital Ocean. I tend to use Debian for servers because it is stable and has an extensive collection of packages. ## Docker and Docker Compose I included the commands necessary to install docker bellow. These instructions may get stale, but the gist is going to remain the same for the foreseeable future. We are adding the docker's certificates to our package manager and then installing it. ``` apt update apt upgrade apt install apt-transport-https ca-certificates curl software-properties-common gnupg2 curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add - add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable" apt update apt install docker-ce ``` Install Docker-Compose ``` curl -L https://github.com/docker/compose/releases/download/1.25.0-rc2/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose chmod +x /usr/local/bin/docker-compose ``` ## Gitea over Docker Compose For simplicity, I am running Gitea using docker-compose because it makes it portable between systems and makes for a straightforward install. You can find the official Gitea instructions on this [here](https://docs.gitea.io/en-us/install-with-docker/). The just of the running entails creating a file called docker-compose.yml with the following contents: ```yml version: "2" networks: gitea: external: false services: server: image: gitea/gitea:latest environment: - USER_UID=1000 - USER_GID=1000 restart: always networks: - gitea volumes: - ./gitea:/data - /etc/timezone:/etc/timezone:ro - /etc/localtime:/etc/localtime:ro ports: - "3000:3000" - "222:22" ``` Once we have our docker-compose.yml saved, we can launch it when we are in the same directory as it using docker-compose. After this launches we now have our Gitea server running on port 3000 ``` docker-compose build docker-compose up ``` ## Nginx and Let's Encrypt Although our server is running publicly on port 3000, we don't want to use it yet because, by default, it is running on HTTP, which is not encrypted. HTTP makes it possible for people sitting in the middle of your connection to listen to your traffic and see all the passwords and data that you send to your Gitea server. We are going to be using a [Nginx](https://nginx.org/) reverse proxy with [Let's Encrypt](https://letsencrypt.org/) to add HTTPS encryption. Installing Nginx is easy because it is in most Linux package managers. ``` apt-get install nginx ``` Next, we tell Systemd to start Nginx on startup. ``` systemctl enable nginx ``` Next we modify the Nginx config file to add a reverse proxy. This will forward all traffic on git.jrtechs.net to the localhosts's port 3000. ``` vim /etc/nginx/sites-available/default ``` Add this content to the very bottom of the default config file changing "git.jrtechs.net." ``` server { listen 80; server_name git.jrtechs.net; location / { proxy_pass http://localhost:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; } } ``` This command tests the Nginx file you just modified to make sure it is syntactically correct. ``` nginx -t ``` Next, we reload Nginx starting the reverse Nginx proxy we just created. ``` /etc/init.d/nginx reload ``` Now that Nginx got configured, we can set-up Certbot for encryption. ``` sudo add-apt-repository ppa:certbot/certbot sudo apt install python-certbot-nginx ``` This step is beautiful because it has the Let's Encrypt Certbot modify the Nginx configuration files to make it work over https. When prompted, select the option that redirects all HTTP traffic to https. ``` systemctl stop nginx certbot --authenticator standalone --installer nginx -d git.jrtechs.net systemctl start nginx ``` Now you should be able to access your Gitea instance using your domain name. By default, the first user that logs into the Gitea instance becomes an administrator. # Results Now you have a private git-forge that you can access anywhere in the world over HTTPS and quickly search and display all your git profiles. ![](media/gitea/teaSearch.png) The profile for each user you create on Gitea looks shockingly similar to Github's. ![](media/gitea/profile.png) One beautiful thing about Gitea is that you can easily import and mirror git repositories from other sources. ![](media/gitea/migration.png) # Transferring Github Projects to Gitea Instance Although it is possible to import every single repository you have in Github manually, this quickly becomes a nuisance if you have 60+ repositories on Github like me. I found and modified a python script that imports all your Github repositories into Gitea. What is particularly dandy about this script is that it uses the Github API to get both your public and private repositories. If the repository is private on Github, it gets transferred over as a private repository into Gitea. This script also mirrors in every repo from your organizations. I posted this script on my [Github](https://github.com/jrtechs/dot_files/tree/master/docker/gitea). To run this script, you need to generate API tokens for both Github and Gitea. Instructions for the Gitea API tokens are found [here](https://docs.gitea.io/en-us/api-usage/), and the Github token can be found [here](https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line). The generated tokens get placed in ".gitea-api" and ".github-token" ```python #!/usr/bin/env python -B from github import Github # https://github.com/PyGithub/PyGithub import requests import json import sys import os gitea_url = "http://127.0.0.1:3000/api/v1" # generage gitea token https://docs.gitea.io/en-us/api-usage/ gitea_token = open(os.path.expanduser("~/.gitea-api")).read().strip() session = requests.Session() # Gitea session.headers.update({ "Content-type" : "application/json", "Authorization" : "token {0}".format(gitea_token), }) r = session.get("{0}/user".format(gitea_url)) if r.status_code != 200: print("Cannot get user details", file=sys.stderr) exit(1) gitea_uid = json.loads(r.text)["id"] github_username = "jrtechs" github_token = open(os.path.expanduser("~/.github-token")).read().strip() gh = Github(github_token) for repo in gh.get_user().get_repos(): m = { "repo_name" : repo.full_name.replace("/", "-"), "description" : repo.description or "not really known", "clone_addr" : repo.clone_url, "mirror" : True, "private" : repo.private, "uid" : gitea_uid, } if repo.private: m["auth_username"] = github_username m["auth_password"] = "{0}".format(github_token) jsonstring = json.dumps(m) r = session.post("{0}/repos/migrate".format(gitea_url), data=jsonstring) if r.status_code != 201: # if not CREATED if r.status_code == 409: # repository exists continue print(r.status_code, r.text, jsonstring) ``` Sit back and have some tea because this script can take a hot second to run.