[17may2026] setting up git on a cloud host
Table of Contents
1. Problem
Github increasingly flaky, want to have an alternative.
2. Plan
Setup git hosting on a rented droplet.
Ingredients:
| DNS | register.com | conybeare.us |
| host | digitalocean.com | 159.203.164.149 |
2.1. DNS
login to
register.comaccount. drop register.com's nameservers, replace them with digital ocean'sNS ns1.digitalocean.com NS ns2.digitalocean.com NS ns3.digitalocean.com login to
digitalocean.comconsole, under Networking add similar domain records alogn with anArecordsA conybeare.us 159.203.164.149 NS conybeare.us directs to ns1.digitalocean.com NS conybeare.us directs to ns2.digitalocean.com NS conybeare.us directs to ns3.digitalocean.com I created record at domain root, so everything forwards to the chosen address
confirm working
$ nslookup conybeare.us Server: 127.0.0.53 Address: 127.0.0.53#53 Non-authoritative answer: Name: conybeare.us Address: 159.203.164.149
2.2. Nix
Setup nixpkgs.
# on 159.203.164.149 $ sh <(curl --proto '=https' --tlsv1.2 -L https://nixos.org/nix/install) --daemon
We will also want system services to be able to use flakes
# /etc/nix/nix.conf build-users-group = nixbld trusted-users = root @wheel experimental-features = nix-command flakes # <-- adding this
2.3. Forgejo
2.3.1. Forgejo user
Add user
$ sudo useradd --system --shell /bin/false --home /var/lib/forgejo forgejo $ sudo mkdir -p /var/lib/forgejo /var/log/forgejo $ sudo mkdir -p /var/lib/forgejo/lfs $ sudo mkdir -p /var/lib/forgejo/gitea-repositories $ sudo chown -R forgejo:forgejo /var/lib/forgejo /var/log/foregejo
Forgejo setup
$ sudo mkdir -p /etc/forgejo
create /etc/foregejo/app.ini:
[server] ROOT_URL = https://conybeare.us/git/ APP_DATA_PATH = /var/lib/forgejo HTTP_ADDR = 127.0.0.1 HTTP_PORT = 3000 START_SSH_SERVER = true SSH_LISTEN_PORT = 2222 SSH_USER = forgejo SSH_PORT = 2222 [database] DB_TYPE = sqlite3 PATH = /var/lib/forgejo/forgejo.db [repository] ROOT = /var/lib/forgejo/gitea-repositories [ui] DEFAULT_THEME = forgejo-dark INSTANCE_SLOGAN = Mad Science, all the way down [lfs] PATH = /var/lib/forgejo/lfs STORAGE_TYPE = local [log] ROOT_PATH = /var/log/forgejo MODE = file LEVEL = info [mailer] ENABLED = false
$ sudo chown forgejo:forgejo /etc/forgejo/app.ini $ sudo chmod 600 /etc/forgejo/app.ini
2.3.2. Runtime environment for forgejo
We want to use nix for this:
# /etc/forgejo/nix/flake.nix
{
description = "Forgejo environment";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils }:
flake-utils.lib.eachDefaultSystem (system :
let pkgs = nixpkgs.legacyPackages.${system};
in {
packages.default = pkgs.forgejo;
apps.forgejo = {
type = "app";
program = "${pkgs.forgejo}/bin/forgejo";
};
devShells.default = pkgs.mkShell {
buildInputs = [ pkgs.forgejo ];
};
}
);
}
To verify syntax (will also fetch all the deps)
$ nix flake show /etc/forgejo/nix $ ls /etc/forgejo/nix/flake.lock # now pinned
2.3.3. Systemd setup (Forgejo)
[Unit] Description=Forgejo After=network.target [Service] Type=simple User=forgejo Group=forgejo WorkingDirectory=/var/lib/forgejo ExecStart=/nix/var/nix/profiles/default/bin/nix run /etc/forgejo/nix#forgejo -- -c /etc/forgejo/app.ini web Restart=always RestartSec=5 Environment="HOME=/var/lib/forgejo" [Install] WantedBy=multi-user.target
then setup
$ sudo systemctl daemon-reload $ sudo systemctl enable forgejo $ sudo systemctl start forgejo
2.3.4. Verify status
$ sudo systemctl status forgejo $ sudo journalctl -u forgejo -n 3 May 18 02:16:21 vpn1 nix[1043231]: Listen: http://127.0.0.1:3000 May 18 02:16:21 vpn1 nix[1043231]: AppURL(ROOT_URL): https://conybeare.us/ May 18 02:16:21 vpn1 nix[1043231]: Starting new Web server: tcp:127.0.0.1:3000 on PID: 1043231
2.4. Proxy Magic
2.4.1. Certificates
$ sudo /nix/var/nix/profiles/default/bin/nix run nixpkgs#certbot -- certonly --standalone -d conybeare.us
$ tree /etc/letsencrypt
/etc/letsencrypt/
├── accounts [error opening dir]
├── archive [error opening dir]
├── live [error opening dir]
├── renewal
│ └── conybeare.us.conf
└── renewal-hooks
├── deploy
├── post
└── pre
2.4.2. Nginx user
Add user
$ sudo useradd --system --shell /bin/false --home /var/cache/nginx nginx
Also working directories
$ sudo mkdir -p /var/cache/nginx $ sudo chown nginx:nginx /var/cache/nginx $ sudo chmod 755 /var/cache/nginx $ sudo mkdir -p /var/log/nginx $ sudo chown nginx:nginx /var/log/nginx $ sudo chmod 755 /var/log/nginx
2.4.3. Nginx
/etc/nginx/nginx.conf:
events { }
http {
server {
listen 80;
server_name conybeare.us:
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name conybeare.us;
ssl_certificate /etc/letsencrypt/live/conybeare.us/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/conybeare.us/privkey.pem;
location /git/ {
proxy_pass http://127.0.0.1:3000/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
}
2.4.4. Runtime environment for nginx
Using nix again:
/etc/nginx/nix/flake.nix:
{
description = "Nginx environment";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils }:
flake-utils.lib.eachDefaultSystem (system:
let pkgs = nixpkgs.legacyPackages.${system};
in {
packages.default = pkgs.nginx;
apps.nginx = {
type = "app";
program = "${pkgs.nginx}/bin/nginx";
};
}
);
}
To verify syntax (and fetch deps)
$ nix flake show /etc/nginx/nix $ ls /etc/nginx/nix/flake.lock
2.4.5. Systemd setup (Nginx)
/etc/systemd/system/nginx.service:
[Unit] Description=Nginx After=network.target [Service] Type=forking # User=nginx # start as root, bind to ports 80/443; then drop to nginx user for workers ExecStart=/nix/var/nix/profiles/default/bin/nix run /etc/nginx/nix#nginx -- -c /etc/nginx/nginx.conf ExecReload=/nix/var/nix/profiles/default/bin/nix run /etc/nginx/nix#nginx -- -c /etc/nginx/nginx.conf -s reload ExecStop=/nix/var/nix/profiles/default/bin/nix run /etc/nginx/nix#nginx -- -s quit [Install] WantedBy=multi-user.target
then ssetup
$ sudo systemctl daemon-reload $ sudo systemctl restart nginx $ sudo systemctl status nginx
$ systemctl status nginx
● nginx.service - Nginx
Loaded: loaded (/etc/systemd/system/nginx.service; disabled; preset: enabled)
Active: active (running) since Mon 2026-05-18 04:13:51 UTC; 4s ago
Process: 1045381 ExecStart=/nix/var/nix/profiles/default/bin/nix run /etc/nginx/nix#nginx -- -c /etc/nginx/nginx.conf (code=exited, status=0/SUCCESS)
Main PID: 1045385 (nginx)
Tasks: 2 (limit: 9489)
Memory: 2.9M (peak: 145.4M)
CPU: 1.281s
CGroup: /system.slice/nginx.service
├─1045385 "nginx: master process /nix/store/6xi5jqgw6mqdvzk36285ywc17wnx1548-nginx-1.30.1/bin/nginx -c /etc/nginx/nginx.conf"
└─1045386 "nginx: worker process"
May 18 04:13:50 vpn1 systemd[1]: Starting nginx.service - Nginx...
May 18 04:13:51 vpn1 nix[1045381]: nginx: [warn] the "listen ... http2" directive is deprecated, use the "http2" directive instead in /etc/nginx/nginx.conf:11
May 18 04:13:51 vpn1 systemd[1]: Started nginx.service - Nginx.
2.5. Enable-on-boot
$ sudo systemctl enable nginx forgejo
2.6. Testing
$ curl https://conybeare.us <!DOCTYPE html> <html lang="en-US" data-theme="forgejo-auto"> ...
2.6.1. Forgejo install (web)
Now setup forgejo by visiting https://conybeare.us
| Instance Slogan | It's mad science, all the way down |
| Repository root path | /var/lib/forgejo/gitea-repositories |
| Git LFS root path | /var/lib/forgejo/lfs |
| Log path | /var/log/forgejo |
| Administrator Account | username, email, … |