Minimale git-remote met publiek/prive-toggle

main

Deze repository wordt als momentopname gepubliceerd: een clone bevat de volledige inhoud, maar geen commitgeschiedenis.

6.4 kB Ruw bestand
#!/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"