🔒 Repository is read-only – file editing is disabled.

pagan-web/install.sh main

575 linii Raw ← Powrót
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575
#!/bin/bash
# =============================================================================
# PaganOS Web v2 – Full Auto-Installer
#   bash install.sh [--domain paganlinux.eu] [--email admin@paganlinux.eu]
#   Wysyłasz z pagan-web-v2/, wpisujesz bash install.sh i wszystko samo działa.
# =============================================================================
set -euo pipefail

# ── Kolory ──
G='\033[32m'; C='\033[36m'; R='\033[31m'; Y='\033[33m'; B='\033[1m'; N='\033[0m'

banner() { echo -e "${C}═══ $* ${N}"; }
ok()    { echo -e "  ${G}${N} $*"; }
warn()  { echo -e "  ${Y}${N}  $*"; }
err()   { echo -e "  ${R}${N} $*"; }

# ── Opcje ──
DOMAIN="${DOMAIN:-paganlinux.eu}"
EMAIL="${EMAIL:-admin@paganlinux.eu}"
SETUP_SSL="${SETUP_SSL:-yes}"
SETUP_FIREWALL="${SETUP_FIREWALL:-yes}"
GPG_KEY_ID="${GPG_KEY_ID:-}"

while [[ $# -gt 0 ]]; do
    case "$1" in
        --domain)   DOMAIN="$2"; shift 2 ;;
        --email)    EMAIL="$2"; shift 2 ;;
        --no-ssl)   SETUP_SSL="no"; shift ;;
        --no-fw)    SETUP_FIREWALL="no"; shift ;;
        --gpg-key)  GPG_KEY_ID="$2"; shift 2 ;;
        -h|--help)
            echo "Użycie: bash install.sh [opcje]"
            echo "  --domain DOMAIN    Domena główna (domyślnie: paganlinux.eu)"
            echo "  --email EMAIL      Email do Let's Encrypt"
            echo "  --no-ssl           Pomiń SSL/Certbot"
            echo "  --no-fw            Pomiń firewall"
            echo "  --gpg-key KEYID    ID klucza GPG do podpisywania pakietów"
            exit 0 ;;
        *) echo "Nieznana opcja: $1"; exit 1 ;;
    esac
done

# ── Root check ──
if [[ $EUID -ne 0 ]]; then
    echo -e "${R}❌ Musisz uruchomić jako root: sudo bash install.sh${N}"
    exit 1
fi

echo -e "${C}"
echo "╔══════════════════════════════════════════════════╗"
echo "║   PaganOS Web v2 – Pełna Instalacja             ║"
echo "║   Domena: $DOMAIN"
echo "║   SSL:    $SETUP_SSL  |  FW: $SETUP_FIREWALL"
echo "╚══════════════════════════════════════════════════╝"
echo -e "${N}"

SRC="$(dirname "$(readlink -f "$0")")"
DST="/opt/pagan-web-v2"

# ═══════════════════════════════════════════════════════════════
# 1. Pakiety systemowe
# ═══════════════════════════════════════════════════════════════
banner "1/7 – Pakiety systemowe"

install_pkg() {
    if command -v apt &>/dev/null; then
        DEBIAN_FRONTEND=noninteractive apt install -y -qq "$@" 2>/dev/null || apt install -y "$@"
    elif command -v pacman &>/dev/null; then
        pacman -Sy --noconfirm "$@" 2>/dev/null || true
    elif command -v dnf &>/dev/null; then
        dnf install -y "$@" 2>/dev/null || true
    else
        warn "Nieznany menedżer pakietów – zainstaluj ręcznie: $*"
    fi
}

install_pkg python3 python3-pip git nginx sqlite3 curl certbot python3-certbot-nginx ufw

pip3 install --break-system-packages flask pygments requests pyyaml mistune 2>/dev/null || \
pip3 install flask pygments requests pyyaml mistune 2>/dev/null || true

ok "Pakiety gotowe"

# ═══════════════════════════════════════════════════════════════
# 2. Kopiowanie aplikacji
# ═══════════════════════════════════════════════════════════════
banner "2/7 – Kopiowanie aplikacji do $DST"

if [ "$SRC" != "$DST" ]; then
    rm -rf "$DST"
    cp -r "$SRC" "$DST"
    ok "Skopiowano → $DST"
else
    ok "Już w $DST"
fi

# Nadaj uprawnienia wykonywalne
chmod +x "$DST/app.py" "$DST/pagbuild" "$DST/pagsync" "$DST/pag" 2>/dev/null || true

# ═══════════════════════════════════════════════════════════════
# 3. Katalogi i symlinki
# ═══════════════════════════════════════════════════════════════
banner "3/7 – Katalogi i struktura"

mkdir -p /var/lib/pagan-web
mkdir -p /var/lib/pagan-sync
mkdir -p /var/lib/pagan-build/rootfs
mkdir -p /var/cache/pagbuild/{sources,output}
mkdir -p /var/git
mkdir -p /var/www/repo.paganlinux.eu/stable
mkdir -p /var/www/repo.paganlinux.eu/sources
mkdir -p /etc/pagan

# Symlink recipes
if [ ! -d "/var/lib/pagan-sync/recipes/core" ]; then
    RECIPES_SRC="$(readlink -f "$SRC/../recipes")"
    if [ -d "$RECIPES_SRC" ]; then
        ln -sf "$RECIPES_SRC" /var/lib/pagan-sync/recipes
        ok "recipes → $(basename "$RECIPES_SRC") (symlink)"
    else
        mkdir -p /var/lib/pagan-sync/recipes
        warn "Brak katalogu recipes/ obok pagan-web-v2/ – utworzono pusty"
    fi
else
    ok "recipes już istnieje"
fi

# Symlink narzędzi do /usr/bin
ln -sf "$DST/pagbuild" /usr/bin/pagbuild 2>/dev/null || true
ln -sf "$DST/pagsync"  /usr/bin/pagsync  2>/dev/null || true
ln -sf "$DST/pag"      /usr/bin/pag      2>/dev/null || true
ok "Symlinki: pagbuild, pagsync, pag → /usr/bin"

# ═══════════════════════════════════════════════════════════════
# 4. GPG – klucz do podpisywania pakietów
# ═══════════════════════════════════════════════════════════════
banner "4/7 – GPG (podpisywanie pakietów)"

if [[ -n "$GPG_KEY_ID" ]]; then
    echo "PAGAN_DO_SIGN=1" > /etc/pagan/build.conf
    echo "PAGAN_GPG_KEY=$GPG_KEY_ID" >> /etc/pagan/build.conf
    ok "GPG: klucz $GPG_KEY_ID – podpisywanie włączone"
elif gpg --list-secret-keys 2>/dev/null | grep -q "^sec"; then
    KEY_ID=$(gpg --list-secret-keys --with-colons 2>/dev/null | grep "^sec:" | head -1 | cut -d: -f5)
    echo "PAGAN_DO_SIGN=1" > /etc/pagan/build.conf
    echo "PAGAN_GPG_KEY=$KEY_ID" >> /etc/pagan/build.conf
    ok "GPG: wykryto klucz $KEY_ID – podpisywanie włączone"
else
    echo "PAGAN_DO_SIGN=0" > /etc/pagan/build.conf
    warn "Brak klucza GPG – podpisywanie wyłączone"
    warn "Wygeneruj: gpg --gen-key  |  potem: bash install.sh --gpg-key KLUCZ"
fi

# ═══════════════════════════════════════════════════════════════
# 5. Nginx – konfiguracja tymczasowa (HTTP only, dla certbota)
# ═══════════════════════════════════════════════════════════════
banner "5/7 – Nginx (konfiguracja tymczasowa HTTP)"

NGINX_CONF="/etc/nginx/sites-available/pagan-web"

cat > "$NGINX_CONF" << 'NGINXHTTP'
# ═══════════════════════════════════════════════════════════════
# PaganOS Web v2 – Tymczasowy HTTP (do czasu uzyskania certyfikatu)
# ═══════════════════════════════════════════════════════════════
upstream pagan_web {
    server 127.0.0.1:8000 fail_timeout=0;
}

server {
    listen 80;
    server_name _;

    # Let's Encrypt challenge
    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }

    location /repo/download/ {
        alias /var/www/repo.paganlinux.eu/;
        expires 30d;
    }

    location /static/ {
        alias /opt/pagan-web-v2/static/;
        expires 7d;
    }

    location /build/api/stream {
        proxy_pass http://pagan_web;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_buffering off;
        proxy_cache off;
        proxy_read_timeout 3600s;
        chunked_transfer_encoding on;
    }

    location / {
        proxy_pass http://pagan_web;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}
NGINXHTTP

ln -sf "$NGINX_CONF" /etc/nginx/sites-enabled/pagan-web 2>/dev/null || true
rm -f /etc/nginx/sites-enabled/default 2>/dev/null || true

nginx -t && systemctl restart nginx 2>/dev/null || nginx -s reload 2>/dev/null || warn "nginx – sprawdź konfigurację"
ok "Nginx HTTP – uruchomiony"

# ═══════════════════════════════════════════════════════════════
# 6. SSL – Let's Encrypt (Certbot)
# ═══════════════════════════════════════════════════════════════
banner "6/7 – SSL / Let's Encrypt"

CERT_OK=false

if [[ "$SETUP_SSL" == "yes" ]]; then
    if [[ -f "/etc/letsencrypt/live/${DOMAIN}/fullchain.pem" ]]; then
        ok "Certyfikat SSL już istnieje dla $DOMAIN"
        CERT_OK=true
    else
        mkdir -p /var/www/certbot
        sleep 2

        echo -e "  ${Y}${N} Pobieranie certyfikatu SSL..."

        # Najpierw spróbuj certonly (bez ingerencji w nginx config)
        certbot certonly --webroot \
            --non-interactive --agree-tos \
            -m "$EMAIL" \
            -w /var/www/certbot \
            -d "${DOMAIN}" \
            -d "www.${DOMAIN}" \
            -d "git.${DOMAIN}" \
            -d "repo.${DOMAIN}" \
            -d "build.${DOMAIN}" \
            -d "docs.${DOMAIN}" \
            2>&1 | sed 's/^/  │ /' || {

            warn "certonly nie zadziałał, próbuję --nginx..."
            certbot --nginx \
                --non-interactive --agree-tos \
                -m "$EMAIL" \
                -d "${DOMAIN}" \
                -d "www.${DOMAIN}" \
                -d "git.${DOMAIN}" \
                -d "repo.${DOMAIN}" \
                -d "build.${DOMAIN}" \
                -d "docs.${DOMAIN}" \
                2>&1 | sed 's/^/  │ /' || true
        }

        if [[ -f "/etc/letsencrypt/live/${DOMAIN}/fullchain.pem" ]]; then
            ok "Certyfikat SSL pobrany!"
            CERT_OK=true

            # Cron do auto-odnawiania
            cat > /etc/cron.daily/pagan-cert-renew << 'CRONEOF'
#!/bin/bash
certbot renew --quiet --webroot -w /var/www/certbot
systemctl reload nginx
CRONEOF
            chmod +x /etc/cron.daily/pagan-cert-renew
            ok "Auto-renew SSL dodany (cron.daily)"
        else
            warn "Certbot nie mógł pobrać certyfikatu."
            warn "Sprawdź DNS (wszystkie subdomeny muszą wskazywać na ten VPS) i port 80."
            warn "Potem uruchom: certbot certonly --webroot -w /var/www/certbot -d paganlinux.eu"
        fi
    fi
else
    warn "SSL pominięte (--no-ssl)"
fi

# ═══════════════════════════════════════════════════════════════
# 5b. Nginx – pełna konfiguracja HTTPS (po uzyskaniu certyfikatu)
# ═══════════════════════════════════════════════════════════════
banner "5b – Nginx (konfiguracja HTTPS)"

if [[ "$CERT_OK" == "true" ]]; then
    cat > "$NGINX_CONF" << NGINXHTTPS
# ═══════════════════════════════════════════════════════════════
# PaganOS Web v2 – Pełna konfiguracja HTTPS
# Auto-generated: $(date)
# ═══════════════════════════════════════════════════════════════

upstream pagan_web {
    server 127.0.0.1:8000 fail_timeout=0;
}

# ── HTTP → HTTPS redirect ──
server {
    listen 80;
    server_name ${DOMAIN} www.${DOMAIN}
                git.${DOMAIN} repo.${DOMAIN}
                build.${DOMAIN} docs.${DOMAIN};

    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }

    location / {
        return 301 https://\$host\$request_uri;
    }
}

# ── HTTPS: Główna + www ──
server {
    listen 443 ssl;
    http2 on;
    server_name ${DOMAIN} www.${DOMAIN};

    ssl_certificate     /etc/letsencrypt/live/${DOMAIN}/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/${DOMAIN}/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
    ssl_prefer_server_ciphers off;

    client_max_body_size 500m;

    location /download/ {
        alias /var/www/repo.paganlinux.eu/;
        autoindex on;
        autoindex_format html;
        expires 30d;
        add_header Cache-Control "public, immutable";
    }

    location /sources/ {
        alias /var/www/repo.paganlinux.eu/sources/;
        expires 7d;
    }

    location /static/ {
        alias /opt/pagan-web-v2/static/;
        expires 7d;
    }

    location /build/api/stream {
        proxy_pass http://pagan_web;
        proxy_http_version 1.1;
        proxy_set_header Host \$host;
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header X-Real-IP \$remote_addr;
        proxy_buffering off;
        proxy_cache off;
        proxy_read_timeout 3600s;
        chunked_transfer_encoding on;
    }

    location / {
        proxy_pass http://pagan_web;
        proxy_http_version 1.1;
        proxy_set_header Host \$host;
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header X-Real-IP \$remote_addr;
        proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
    }
}

# ── HTTPS: Git ──
server {
    listen 443 ssl;
    http2 on;
    server_name git.${DOMAIN};

    ssl_certificate     /etc/letsencrypt/live/${DOMAIN}/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/${DOMAIN}/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;

    client_max_body_size 500m;

    location / {
        proxy_pass http://pagan_web;
        proxy_http_version 1.1;
        proxy_set_header Host git.${DOMAIN};
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header X-Real-IP \$remote_addr;
        proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
    }
}

# ── HTTPS: Repo ──
server {
    listen 443 ssl;
    http2 on;
    server_name repo.${DOMAIN};

    ssl_certificate     /etc/letsencrypt/live/${DOMAIN}/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/${DOMAIN}/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;

    location /download/ {
        alias /var/www/repo.paganlinux.eu/;
        autoindex on;
        autoindex_format html;
        expires 30d;
        add_header Cache-Control "public, immutable";
    }

    location / {
        proxy_pass http://pagan_web;
        proxy_http_version 1.1;
        proxy_set_header Host repo.${DOMAIN};
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header X-Real-IP \$remote_addr;
    }
}

# ── HTTPS: Build ──
server {
    listen 443 ssl;
    http2 on;
    server_name build.${DOMAIN};

    ssl_certificate     /etc/letsencrypt/live/${DOMAIN}/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/${DOMAIN}/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;

    location /api/stream {
        proxy_pass http://pagan_web;
        proxy_http_version 1.1;
        proxy_set_header Host build.${DOMAIN};
        proxy_set_header X-Forwarded-Proto https;
        proxy_buffering off;
        proxy_cache off;
        proxy_read_timeout 3600s;
        chunked_transfer_encoding on;
    }

    location / {
        proxy_pass http://pagan_web;
        proxy_http_version 1.1;
        proxy_set_header Host build.${DOMAIN};
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header X-Real-IP \$remote_addr;
    }
}

# ── HTTPS: Docs ──
server {
    listen 443 ssl;
    http2 on;
    server_name docs.${DOMAIN};

    ssl_certificate     /etc/letsencrypt/live/${DOMAIN}/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/${DOMAIN}/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;

    location / {
        proxy_pass http://pagan_web;
        proxy_http_version 1.1;
        proxy_set_header Host docs.${DOMAIN};
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header X-Real-IP \$remote_addr;
    }
}
NGINXHTTPS

    nginx -t && systemctl reload nginx 2>/dev/null || nginx -s reload 2>/dev/null || warn "nginx reload – sprawdź"
    ok "Nginx HTTPS – pełna konfiguracja z subdomenami"
else
    # SSL się nie udał – zostawiamy HTTP
    warn "SSL niedostępne – zostawiam konfigurację HTTP"
    warn "Po uzyskaniu certyfikatu uruchom ponownie install.sh"
fi

# ═══════════════════════════════════════════════════════════════
# 7. Systemd + Firewall + Start
# ═══════════════════════════════════════════════════════════════
banner "7/7 – Usługi i finalizacja"

# ── Systemd service ──
cat > /etc/systemd/system/pagan-web.service << UNITEOF
[Unit]
Description=PaganOS Web v2 – Unified Platform
After=network.target nginx.service
Wants=network.target

[Service]
Type=simple
ExecStart=/usr/bin/python3 /opt/pagan-web-v2/app.py
WorkingDirectory=/opt/pagan-web-v2
Restart=always
RestartSec=5
User=root
EnvironmentFile=-/etc/pagan/build.conf
Environment=PYTHONUNBUFFERED=1
StandardOutput=journal
StandardError=journal

# Bezpieczeństwo
NoNewPrivileges=false
PrivateTmp=false

[Install]
WantedBy=multi-user.target
UNITEOF

systemctl daemon-reload
systemctl enable pagan-web 2>/dev/null || true
ok "systemd: pagan-web.service"

# ── Firewall ──
if [[ "$SETUP_FIREWALL" == "yes" ]] && command -v ufw &>/dev/null; then
    ufw --force reset >/dev/null 2>&1 || true
    ufw default deny incoming >/dev/null 2>&1 || true
    ufw default allow outgoing >/dev/null 2>&1 || true
    ufw allow 22/tcp comment "SSH" >/dev/null 2>&1 || true
    ufw allow 80/tcp comment "HTTP" >/dev/null 2>&1 || true
    ufw allow 443/tcp comment "HTTPS" >/dev/null 2>&1 || true
    ufw --force enable >/dev/null 2>&1 || true
    ok "Firewall (ufw): SSH + HTTP + HTTPS"
fi

# ── Cron – auto-build co 6h + codzienne czyszczenie cache ──
cat > /etc/cron.d/pagan-build << 'CRONBUILD'
# PaganOS – auto-build brakujących pakietów co 6 godzin
0 */6 * * * root /opt/pagan-web-v2/pagsync --once --missing >> /var/log/pagan-auto-build.log 2>&1
# Codzienne czyszczenie cache źródeł o 3:00
0 3 * * * root /opt/pagan-web-v2/pagsync --clean-cache >> /var/log/pagan-auto-build.log 2>&1
CRONBUILD
chmod 644 /etc/cron.d/pagan-build
ok "Cron: auto-build co 6h + clean-cache codziennie"

# ── Restart usług ──
nginx -t 2>/dev/null && systemctl restart nginx 2>/dev/null || nginx -s reload 2>/dev/null || warn "nginx restart – sprawdź konfigurację"
systemctl restart pagan-web 2>/dev/null || warn "pagan-web restart – sprawdź: systemctl status pagan-web"

# ═══════════════════════════════════════════════════════════════
# Podsumowanie
# ═══════════════════════════════════════════════════════════════
echo ""
echo -e "${G}╔══════════════════════════════════════════════════════════╗${N}"
echo -e "${G}║  ✅ PaganOS Web v2 – Instalacja zakończona!             ║${N}"
echo -e "${G}╚══════════════════════════════════════════════════════════╝${N}"
echo ""
echo -e "  ${B}🌐 Strony:${N}"
echo -e "     Główna:     https://${DOMAIN}"
echo -e "     Git:        https://git.${DOMAIN}"
echo -e "     Repo:       https://repo.${DOMAIN}"
echo -e "     Build:      https://build.${DOMAIN}"
echo -e "     Docs:       https://docs.${DOMAIN}"
echo ""
echo -e "  ${B}🔧 Zarządzanie:${N}"
echo -e "     Status:     systemctl status pagan-web"
echo -e "     Logi:       journalctl -u pagan-web -f"
echo -e "     Restart:    systemctl restart pagan-web"
echo -e "     Nginx:      nginx -t && systemctl reload nginx"
echo ""
echo -e "  ${B}📦 Budowanie pakietów:${N}"
echo -e "     Wszystkie:  pagsync --once"
echo -e "     Force:      pagsync --once --force"
echo -e "     Jeden:      pagsync --build nazwa"
echo -e "     Z GPG:      pagsync --once --sign"
echo ""
echo -e "  ${B}🔑 Panel admin:${N}"
echo -e "     Login:      admin  /  paganadmin2024"
echo -e "     Build:      https://build.${DOMAIN}"
echo -e ""
if [[ -f "/etc/pagan/build.conf" ]]; then
    echo -e "  ${B}📋 Konfiguracja build:${N} /etc/pagan/build.conf"
    cat /etc/pagan/build.conf | sed 's/^/     /'
fi
echo ""