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 <user>, 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 <name> 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 is optional. Without it nobody receives notifications and password resets go through gitpocket passwd <name>. 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 <noreply@git.example.org>"}
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 <dir> 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 and copies new image attachments. 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/<owner>/<name>.git and copy attachments back. 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.