gitpages

A collection of scripts to securely webhost and publish git repositories.
git clone https://scm.kuandu.systems/git-raw/gitpages.git
Log | Files | Refs | README | LICENSE

install.sh (5195B)


      1 #!/bin/sh
      2 #
      3 # Copyright (c) 2026 Fred Großkopf
      4 #
      5 # Permission to use, copy, modify, and/or distribute this software for any
      6 # purpose with or without fee is hereby granted, provided that the above
      7 # copyright notice and this permission notice appear in all copies.
      8 #
      9 # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     10 # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     11 # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     12 # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     13 # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     14 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     15 # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     16 
     17 set -eu
     18 
     19 log() { printf 'info: %s\n' "$1"; }
     20 warn() { printf 'warning: %s\n' "$1" >&2; }
     21 error() {
     22   printf 'error: %s\n' "$1" >&2
     23   exit 1
     24 }
     25 
     26 usage() {
     27   printf 'usage: %s <git-user> <git-src> <web-root>\n' "$(basename "$0")"
     28   exit 1
     29 }
     30 
     31 setup_dirs() {
     32   install -d -m 755 -o "$USER_NAME" -g "$GROUP_NAME" "$VAR_DIR" "$LOG_DIR"
     33   install -d -m 755 "$BIN_DIR" "$SPOOL_DIR"
     34   install -d -m 755 -o "$USER_NAME" -g "$GROUP_NAME" "$VAR_DIR/staging"
     35 }
     36 
     37 setup_group() {
     38   if ! groupinfo "$GROUP_NAME" > /dev/null 2>&1; then
     39     if command -v groupadd > /dev/null 2>&1; then
     40       groupadd "$GROUP_NAME"
     41       log "Created group $GROUP_NAME"
     42     else
     43       error "Neither groupinfo nor groupadd found; cannot create group $GROUP_NAME. Please create it manually."
     44     fi
     45   fi
     46 }
     47 
     48 setup_user() {
     49   if ! id "$USER_NAME" > /dev/null 2>&1; then
     50     useradd -s /sbin/nologin \
     51       -d "$VAR_DIR" \
     52       -c "Gitpages service user" \
     53       -g "$GROUP_NAME" \
     54       -G "$GIT_USER" \
     55       "$USER_NAME"
     56     log "Created user $USER_NAME (primary group: $GROUP_NAME)"
     57   fi
     58 }
     59 
     60 setup_spool() {
     61   install -d -m 2775 -o "$GIT_USER" -g "$GROUP_NAME" "$QUEUE_DIR"
     62 }
     63 
     64 install_scripts() {
     65   for script in gitpages.sh gitpages-init.sh gitpages-mirror-git.sh gitpages-update.sh; do
     66     if [ -f "./$script" ]; then
     67       install -m 755 -o root -g wheel "./$script" "$BIN_DIR/$script"
     68       log "Installed $script to $BIN_DIR"
     69     else
     70       warn "$script not found, skipping."
     71     fi
     72   done
     73 }
     74 
     75 setup_config() {
     76   config="$ETC_DIR/gitpages.conf"
     77   backup="$config.bak"
     78 
     79   if [ -f "$config" ]; then
     80     n=1
     81     while [ -f "$backup.$n" ]; do
     82       n=$((n + 1))
     83     done
     84     cp -p "$config" "$backup.$n"
     85     log "Backed up $config to $backup.$n"
     86   fi
     87 
     88   tmp="$(mktemp "$ETC_DIR/gitpages.conf.XXXXXX")"
     89   trap 'rm -f "$tmp"' EXIT INT TERM
     90   cat > "$tmp" << EOF
     91 GIT_SRC=$GIT_SRC
     92 WEB_ROOT=$WEB_ROOT
     93 GIT_RAW=$GIT_RAW
     94 GIT_HTML=$GIT_HTML
     95 ASSETS_DIR=$ASSETS_DIR
     96 EOF
     97 
     98   mv "$tmp" "$config"
     99   trap - EXIT INT TERM
    100   log "Wrote config to $config"
    101 }
    102 
    103 setup_logrotation() {
    104   if ! grep -q "$LOG_DIR/updates.log" "$ETC_DIR"/newsyslog.conf; then
    105     echo "$LOG_DIR/updates.log ${USER_NAME}:${GROUP_NAME} 640 5 100 * J" >> "$ETC_DIR"/newsyslog.conf
    106     log "Log rotation appended to $ETC_DIR/newsyslog.conf."
    107   else
    108     log "Log rotation already configured in $ETC_DIR/newsyslog.conf."
    109   fi
    110 }
    111 
    112 setup_cron() {
    113   cron_line="*/5 * * * * $BIN_DIR/gitpages-update.sh"
    114 
    115   if [ ! -f "$BIN_DIR/gitpages-update.sh" ]; then
    116     error "Cannot setup cron: $BIN_DIR/gitpages-update.sh not found."
    117   fi
    118 
    119   if crontab -u "$USER_NAME" -l 2> /dev/null | grep -qF "$cron_line"; then
    120     log "Cronjob already exists and is configured correctly."
    121   else
    122     echo "$cron_line" | crontab -u "$USER_NAME" -
    123     log "Cronjob set for gitpages user."
    124   fi
    125 }
    126 
    127 setup_webroot() {
    128   install -d -m 755 -o "root" -g "wheel" "$WEB_ROOT"
    129   install -d -m 755 -o "$USER_NAME" -g "$GROUP_NAME" "$WEB_ROOT/git"
    130   install -d -m 755 -o "$USER_NAME" -g "$GROUP_NAME" "$WEB_ROOT/git-raw"
    131   log "Created web root and subdirectories under $WEB_ROOT"
    132 }
    133 
    134 main() {
    135   [ $# -ne 3 ] && usage
    136   GIT_USER="$1"
    137   GIT_SRC="$2"
    138   WEB_ROOT="$3"
    139 
    140   USER_NAME="_gitpages"
    141   GROUP_NAME="gitpages"
    142 
    143   GIT_RAW=git-raw
    144   GIT_HTML=git
    145   ASSETS_DIR=/var/gitpages/assets
    146 
    147   BIN_DIR="/usr/local/sbin"
    148   ETC_DIR="/etc"
    149   VAR_DIR="/var/gitpages"
    150   LOG_DIR="/var/log/gitpages"
    151   SPOOL_DIR="/var/spool"
    152   QUEUE_DIR="$SPOOL_DIR/gitpages/queue"
    153 
    154   # Validation
    155   if ! id "$GIT_USER" > /dev/null 2>&1; then
    156     error "User '$GIT_USER' does not exist."
    157   fi
    158 
    159   case "$GIT_SRC" in
    160     /*) : ;;
    161     *) error "GIT_SRC must be an absolute path" ;;
    162   esac
    163 
    164   [ -d "$GIT_SRC" ] || error "GIT_SRC directory '$GIT_SRC' not found"
    165 
    166   if ! su - "$GIT_USER" -c "test -r '$GIT_SRC'"; then
    167     error "GIT_USER '$GIT_USER' cannot read GIT_SRC '$GIT_SRC'"
    168   fi
    169 
    170   case "$WEB_ROOT" in
    171     /*) : ;;
    172     *) error "WEB_ROOT must be an absolute path" ;;
    173   esac
    174 
    175   log "Installing gitpages environment for git-user: $GIT_USER"
    176   log "Using WEB_ROOT: $WEB_ROOT"
    177 
    178   # Determine and switch to where this script resides
    179   # so ./gitpages-*.sh work no matter where script is invoked from
    180   SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd -P)"
    181   cd "$SCRIPT_DIR" || error "cannot cd to $SCRIPT_DIR"
    182 
    183   setup_group
    184   setup_user
    185   setup_dirs
    186   setup_spool
    187   install_scripts
    188   setup_config
    189   setup_webroot
    190   setup_logrotation
    191   setup_cron
    192 
    193   log "Installation complete."
    194 }
    195 
    196 main "$@"