Minimale git-remote met publiek/prive-toggle
Deze repository wordt als momentopname gepubliceerd: een clone bevat de volledige inhoud, maar geen commitgeschiedenis.
#!/bin/bash
# Provisionering van pub-repo op een Debian/Ubuntu-box met nginx en certbot.
# Idempotent: geheimen, certificaat en repo-map worden alleen aangemaakt als ze
# ontbreken.
#
# DOMAIN=git.voorbeeld.nl LE_EMAIL=jij@voorbeeld.nl \
# ssh root@server 'bash -s' < deploy/setup.sh
#
# Daarna vanaf je werkmachine:
# git remote add production ssh://root@server/srv/git/pub-repo.git
# git push production main
#
# De systemd-unit en de nginx-vhost worden pas geïnstalleerd als de code er is,
# dus draai dit script nog één keer na die eerste push.
set -euo pipefail
APP=pub-repo
USER_NAME=pubrepo
PORT=${PORT:-3300}
DOMAIN=${DOMAIN:?zet DOMAIN, bijvoorbeeld: DOMAIN=git.voorbeeld.nl}
LE_EMAIL=${LE_EMAIL:?zet LE_EMAIL voor de Let\'s Encrypt-registratie}
SITE_NAME=${SITE_NAME:-Repositories}
# --- gebruiker en mappen ------------------------------------------------------
if ! id -u "$USER_NAME" >/dev/null 2>&1; then
useradd --system --create-home --home-dir /var/lib/pub-repo --shell /bin/bash "$USER_NAME"
echo "-> gebruiker $USER_NAME aangemaakt"
fi
mkdir -p /opt/$APP /var/lib/pub-repo/repos /srv/git
chown -R "$USER_NAME:$USER_NAME" /opt/$APP /var/lib/pub-repo
# --- bare deploy-repo ---------------------------------------------------------
# Blijft root:root — je pusht als root over SSH. De app-gebruiker leest er alleen
# uit, en heeft daarvoor een safe.directory-uitzondering nodig (zie onder).
if [ ! -d /srv/git/$APP.git ]; then
git init -q --bare /srv/git/$APP.git
echo "-> /srv/git/$APP.git aangemaakt"
fi
cat > /srv/git/$APP.git/hooks/post-receive <<'HOOK'
#!/bin/bash
# Deploy bij push naar main: checkout bijwerken, deps installeren, herstarten.
# De gepubliceerde repositories staan in /var/lib/pub-repo/repos en blijven hier
# volledig buiten.
set -euo pipefail
unset GIT_DIR
while read -r old new ref; do
[ "$ref" = "refs/heads/main" ] || continue
echo "-> deploy $new"
sudo -u pubrepo -H bash -c '
set -e; cd /opt/pub-repo
git fetch -q origin main
git reset -q --hard origin/main
npm ci --omit=dev --no-audit --no-fund --loglevel=error
'
systemctl restart pub-repo
sleep 1
systemctl is-active pub-repo && echo "-> pub-repo running ($(sudo -u pubrepo -H git -C /opt/pub-repo log -1 --format=%h))"
done
HOOK
chmod +x /srv/git/$APP.git/hooks/post-receive
# --- werkkopie die de hook bijwerkt -------------------------------------------
if [ ! -d /opt/$APP/.git ]; then
sudo -u "$USER_NAME" -H bash -c "
set -e
git init -q -b main /opt/$APP
git -C /opt/$APP remote add origin /srv/git/$APP.git
"
echo "-> werkkopie /opt/$APP gekoppeld aan /srv/git/$APP.git"
fi
# Zonder dit faalt de fetch in de hook met 'detected dubious ownership':
# de bare repo is van root, de fetch draait als $USER_NAME.
sudo -u "$USER_NAME" -H git config --global --add safe.directory /srv/git/$APP.git
# --- omgeving -----------------------------------------------------------------
if [ ! -f /opt/$APP/.env ]; then
cat > /opt/$APP/.env <<ENV
REPO_ROOT=/var/lib/pub-repo/repos
PORT=$PORT
HOST=127.0.0.1
PUBLIC_URL=https://$DOMAIN
OWNER_TOKEN=$(openssl rand -hex 32)
SESSION_SECRET=$(openssl rand -hex 32)
SITE_NAME=$SITE_NAME
TRUST_PROXY=1
ENV
chown "$USER_NAME:$USER_NAME" /opt/$APP/.env
chmod 600 /opt/$APP/.env
echo "-> /opt/$APP/.env aangemaakt met verse geheimen"
fi
# --- systemd ------------------------------------------------------------------
if [ -f /opt/$APP/deploy/pub-repo.service ]; then
install -m 644 /opt/$APP/deploy/pub-repo.service /etc/systemd/system/$APP.service
systemctl daemon-reload
systemctl enable $APP >/dev/null 2>&1 || true
echo "-> systemd unit geïnstalleerd"
else
echo "-> unit overgeslagen: code nog niet gepusht, draai dit script opnieuw na de eerste push"
fi
# --- nginx: eerst alleen :80, zodat certbot een certificaat kan halen ---------
if [ ! -f /etc/letsencrypt/live/$DOMAIN/fullchain.pem ]; then
cat > /etc/nginx/sites-available/$APP <<NGINX
server {
listen 80;
listen [::]:80;
server_name $DOMAIN;
location / { return 404; }
}
NGINX
ln -sfn /etc/nginx/sites-available/$APP /etc/nginx/sites-enabled/$APP
nginx -t && systemctl reload nginx
certbot certonly --nginx -d "$DOMAIN" --non-interactive --agree-tos \
--email "$LE_EMAIL" --keep-until-expiring
echo "-> certificaat opgehaald"
fi
# --- nginx: definitieve vhost met TLS ----------------------------------------
# TLS staat hier inline: certbot vernieuwt alleen de certificaatbestanden op de
# paden hieronder en herschrijft deze vhost niet.
if [ -f /etc/letsencrypt/live/$DOMAIN/fullchain.pem ]; then
cat > /etc/nginx/sites-available/$APP <<NGINX
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name $DOMAIN;
ssl_certificate /etc/letsencrypt/live/$DOMAIN/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/$DOMAIN/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
# --- git transport ----------------------------------------------------
# Een push is één grote POST. Zonder deze twee regels breekt elke push van
# enige omvang: de standaardlimiet is 1 MB en nginx zou de hele pack eerst
# naar schijf bufferen.
location /git/ {
proxy_pass http://127.0.0.1:$PORT;
proxy_http_version 1.1;
client_max_body_size 0;
proxy_request_buffering off;
proxy_buffering off;
# Een grote clone of push mag langer duren dan de standaard 60 seconden.
proxy_read_timeout 600s;
proxy_send_timeout 600s;
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;
}
# --- webweergave en beheer --------------------------------------------
location / {
proxy_pass http://127.0.0.1:$PORT;
proxy_http_version 1.1;
client_max_body_size 1m;
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;
}
}
server {
listen 80;
listen [::]:80;
server_name $DOMAIN;
return 301 https://\$host\$request_uri;
}
NGINX
ln -sfn /etc/nginx/sites-available/$APP /etc/nginx/sites-enabled/$APP
nginx -t && systemctl reload nginx
echo "-> nginx vhost met TLS actief"
fi
echo "KLAAR"