# Installation gitpocket installs either as a container built from this repository or as a single binary under systemd. Both keep every piece of state in one data directory, `/srv/gitpocket` by default, and both expect nginx or another TLS proxy in front and the host's own sshd for git over SSH. ## Requirements A Linux host with git 2.38 or newer, which `merge-tree --write-tree` needs, and OpenSSH. Building from source needs Go 1.27 or newer, and the container route needs Docker with the compose plugin. 512 MB of memory is enough for a small instance. ## Prepare the host Create the account that owns the data and receives SSH logins. Its name appears in clone URLs, so `git` is the usual choice. ``` useradd -r -m -d /srv/gitpocket -s /bin/sh git ``` ## Docker The compose file runs the server as the `git` account with a read only root filesystem, no capabilities, `no-new-privileges`, a 512 MB memory ceiling and the port bound to loopback only. It mounts `/srv/gitpocket` from the host, so the data outlives the container. ``` git clone https://gitpocket.io/~gitpocket/gitpocket /opt/gitpocket cd /opt/gitpocket printf 'GITPOCKET_HOST=git.example.org\nGITPOCKET_UID=%s\nGITPOCKET_GID=%s\n' $(id -u git) $(id -g git) > deploy/.env docker compose -f deploy/compose.yaml up -d --build ``` The server trusts `X-Forwarded-For` from loopback and from the compose network gateway, `172.31.255.1`, which is where connections from the host proxy appear. Change the subnet in `deploy/compose.yaml` if it collides with one you already use. SSH logins are answered on the host, so copy the binary out of the image to the same path it has inside it. Repository hooks name that path, and the container and the host must agree on it. ``` docker cp gitpocket:/usr/local/bin/gitpocket /usr/local/bin/gitpocket ``` ## Binary ``` git clone https://gitpocket.io/~gitpocket/gitpocket && cd gitpocket CGO_ENABLED=0 go build -trimpath -ldflags='-s -w' -o gitpocket . install -m 755 gitpocket /usr/local/bin/gitpocket install -m 644 deploy/gitpocket.service /etc/systemd/system/ ``` Replace `git.example.org` in `/etc/systemd/system/gitpocket.service` with your hostname, then start it. ``` systemctl daemon-reload systemctl enable --now gitpocket ``` The unit sets `GOMEMLIMIT` to 192 MiB, caps the server and every git it starts at 512 MB, and allows writes only beneath `/srv/gitpocket`. ## Reverse proxy `deploy/nginx.conf` is a complete site. Set `server_name` and the certificate paths, then install it. ``` cp deploy/nginx.conf /etc/nginx/sites-available/gitpocket ln -s ../sites-available/gitpocket /etc/nginx/sites-enabled/ certbot certonly --nginx -d git.example.org nginx -t && systemctl reload nginx ``` Whatever proxy you use has to forward `Host` and `X-Forwarded-Proto`, set `X-Forwarded-For` to the client address, turn request buffering off and allow large bodies, otherwise bigger HTTPS pushes are cut short. The server takes the last address in `X-Forwarded-For`, so a client cannot pick its own rate limit bucket. ## SSH Add this to the end of `/etc/ssh/sshd_config` and reload sshd. ``` Match User git AuthenticationMethods publickey PasswordAuthentication no AuthorizedKeysFile none AuthorizedKeysCommand /usr/local/bin/gitpocket -root /srv/gitpocket keys %u %h %t %k AuthorizedKeysCommandUser root PermitTTY no DisableForwarding yes ``` `keys` opens the database read only and answers with a forced command of `gitpocket shell `, which checks the requested repository and permission before it execs `git upload-pack` or `git receive-pack`. Nothing is left running after the push. If the account is not called `git`, pass `-ssh-user` to `serve` so the clone URLs match. ## First run Open the site, sign up, then grant yourself administration and choose how others join. ``` sudo -u git gitpocket admin you sudo -u git gitpocket registration invite ``` Under Docker the same commands run as `docker exec gitpocket gitpocket admin you`. Registration starts open, `invite` hands out single use links from `/admin`, and `closed` leaves `gitpocket user ` as the only way in, with the password read from stdin. ## Configuration `serve` takes its settings as flags. | Flag | Default | Meaning | |---|---|---| | `-host` | `localhost` | public hostname used in clone URLs, mail and feeds | | `-name` | `gitpocket` | site name shown in the header | | `-listen` | `127.0.0.1:3200` | address the HTTP server binds | | `-ssh-user` | `git` | account shown in SSH clone URLs | | `-proxy` | none | comma separated networks, besides loopback, whose `X-Forwarded-For` is trusted | The data directory holds a few optional files, each read once at startup. `logo.png` replaces the header logo and `icon.png` the favicon. `smtp.json` enables mail, and `gitpocket quota 2G` sets a per owner disk quota that pushes are checked against. ## Mail Mail is optional. Without it nobody receives notifications and password resets go through `gitpocket passwd `. Plain SMTP takes `host`, `port`, `user`, `password`, `from` and `starttls`. Many VPS providers block outbound submission ports, so `api` and `key` post to a Resend compatible endpoint instead, and `account` and `token` use the Cloudflare email API. ``` {"api": "https://api.resend.com/emails", "key": "re_...", "from": "gitpocket "} ``` Save it as `/srv/gitpocket/smtp.json`, readable only by `git`, restart the server and send a test with `gitpocket mail you@example.org`. ## Backups `gitpocket backup ` writes a dated copy of the database with `vacuum into`, keeps the last fourteen, and bundles every repository whose refs changed since its previous bundle. The supplied timer runs it nightly into `/srv/gitpocket/backups`, which should then be copied off the host. ``` install -m 644 deploy/gitpocket-backup.service deploy/gitpocket-backup.timer /etc/systemd/system/ systemctl enable --now gitpocket-backup.timer ``` To restore, stop the server, put the newest database back as `gitpocket.db`, and `git clone --mirror` each bundle to `repos//.git`. The server reinstalls repository hooks when it starts. ## Upgrading Back up first. Schema changes are applied automatically when the server starts. ``` cd /opt/gitpocket && git pull docker compose -f deploy/compose.yaml up -d --build docker cp gitpocket:/usr/local/bin/gitpocket /usr/local/bin/gitpocket ``` For a binary install, rebuild, `install` the new binary over the old one and `systemctl restart gitpocket`.