How to host your code: methods and philosophy
When reading the title you might think that the answer is pretty obvious: you just put your code repositories in GitHub and that's it.
However, when you think about what happened to PairDrop or spotizerr it becomes obvious that the answer is not so simple. On one hand you want to put your code in a place that is easy to reach and where your project will have exposure. On the other you don't want to rely on Big Tech to determine the future of your project. One false positive from an AI tool or one malicious DMCA request and all your hard work can just disappear. Unless your project has a big audience, nobody at Big Tech will listen to you and then it can take weeks or months until everything comes back to normal.
Mitigating risks
How do you mitigate this risk? The answer is self-hosting, before you draw the conclusion that such a thing is not feasible hear me out!
Everyone who is into self-hosting knows that it comes with its set of challenges.
By example your own domain will never have the exposure of GitHub. So you might think that self-hosting your code will reduce the exposure and viability of your project. Luckily such a thing as a push mirror exists! This means the following : first you commit your code on your self-hosted repository and then automatically the code gets pushed to another git repository. The mirror repositories can be hosted on any platform you want, like GitHub. This way you still have the exposure you want while your code is under your control.
Another challenge associated with self-hosting is managing security. If you don't want to take any risk you don't have to expose your self-hosted instance to the public. You just put the software locally and setup a push mirror to a provider that's publicly available, job done. Although with tools like pangolin exposing self-hosted services has become a breeze.
Maybe the last challenge is choosing the right software but that's what we are for.
Choosing the right software
Basically there are two options : gitea and forgejo. Personally, I use gitea, so this article only will include examples for that software. However due to the actions of the company behind it I would recommend to have a look at forgejo if you're starting out. Someday I will make the switch, but for now I'm holding out on that pending transition.
Build actions
Gitea provides a run agent that is very similar to GitHub actions. However there are some differences that need to be worked around.
Install docker
By default the gitea runner doesn't have Docker installed, in order to be able to do anything with Docker you need to install it yourself.
This can be done in the following way :
- name: Install Docker
run: |
echo "Checking docker installation"
if command -v docker &> /dev/null; then
echo "Docker installation found"
else
echo "Docker installation not found. Docker will be installed"
curl -fsSL https://get.docker.com | sh
fi
Update docker hub description
There is this action that enables you to automatically update descriptions on docker hub. However it requires some extra dependencies to be installed.
- name: Install npm dependencies
run: |
echo "Installing fetch"
install_node=$false
if ! command -v node &> /dev/null; then
echo "No version of NodeJS detected"
install_node=true
else
node_version=$(node -v)
node_version=${node_version:1} # Remove 'v' at the beginning
node_version=${node_version%\.*} # Remove trailing ".*".
node_version=${node_version%\.*} # Remove trailing ".*".
node_version=$(($node_version)) # Convert the NodeJS version number from a string to an integer.
if [ $node_version -lt 24 ]; then
echo "node version : " $node_version
echo $"removing outdated npm version"
install_node=true
apt-get update
apt-get remove nodejs npm
apt-get purge nodejs
rm -rf /usr/local/bin/npm
rm -rf /usr/local/share/man/man1/node*
rm -rf /usr/local/lib/dtrace/node.d
rm -rf ~/.npm
rm -rf ~/.node-gyp
rm -rf /opt/local/bin/node
rm -rf opt/local/include/node
rm -rf /opt/local/lib/node_modules
rm -rf /usr/local/lib/node*
rm -rf /usr/local/include/node*
rm -rf /usr/local/bin/node*
fi
fi
if $install_node; then
NODE_MAJOR=24
echo "Installing node ${NODE_MAJOR}"
if test -f /etc/apt/keyrings/nodesource.gpg; then
rm /etc/apt/keyrings/nodesource.gpg
fi
if test -f /etc/apt/sources.list.d/nodesource.list; then
rm /etc/apt/sources.list.d/nodesource.list
fi
apt-get update
apt-get install -y -q ca-certificates curl gnupg
mkdir -p /etc/apt/keyrings
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_${NODE_MAJOR}.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list
apt-get update
apt-get install -y -q nodejs
npm install npm --global
fi
echo "node version : " $(node -v)
package='node-fetch'
if [ `npm list -g | grep -c $package` -eq 0 ]; then
npm install -g $package
fi
- name: Docker Hub Description
uses: peter-evans/dockerhub-description@v5
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_PASSWORD }}
repository: ${{ repostitory }}