diff --git a/.gitea/workflows/build.yaml b/.gitea/workflows/build.yaml index 7b49593..001dd44 100644 --- a/.gitea/workflows/build.yaml +++ b/.gitea/workflows/build.yaml @@ -45,9 +45,39 @@ jobs: ${{ env.REGISTRY }}/${{ env.IMAGE_PREFIX }}/spacesh-landing:${{ steps.version.outputs.VERSION }} ${{ env.REGISTRY }}/${{ env.IMAGE_PREFIX }}/spacesh-landing:latest + # Push the compose stack to the prod host and roll the landing container. + # (DMG is uploaded separately from macOS via `make deploy-dmg`.) + deploy: + name: Deploy to prod + needs: landing + runs-on: ubuntu-22.04 + container: catthehacker/ubuntu:act-latest + steps: + - uses: actions/checkout@v3 + - name: Setup SSH + run: | + which ssh || (apt-get update && apt-get install -y openssh-client) + mkdir -p ~/.ssh && chmod 700 ~/.ssh + printf '%s\n' "${{ secrets.SSH_KEY }}" > ~/.ssh/id_deploy + chmod 600 ~/.ssh/id_deploy + ssh-keyscan "${{ secrets.SSH_HOST }}" >> ~/.ssh/known_hosts 2>/dev/null || true + - name: Sync compose stack + run: | + ssh -i ~/.ssh/id_deploy "${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}" \ + "mkdir -p '${{ secrets.SSH_REMOTE_DIR }}/download'" + # Pin the exact image CI just pushed so the server pulls the right path/tag. + printf 'LANDING_IMAGE=%s/%s/spacesh-landing:%s\n' \ + "${{ env.REGISTRY }}" "${{ env.IMAGE_PREFIX }}" "${{ needs.landing.outputs.version }}" > .env + scp -i ~/.ssh/id_deploy deploy/docker-compose.yaml deploy/proxy.conf .env \ + "${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}:${{ secrets.SSH_REMOTE_DIR }}/" + - name: Pull & up + run: | + ssh -i ~/.ssh/id_deploy "${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}" \ + "cd '${{ secrets.SSH_REMOTE_DIR }}' && docker compose pull && docker compose up -d" + notify: name: Notify Max - needs: landing + needs: [landing, deploy] if: always() runs-on: ubuntu-22.04 container: catthehacker/ubuntu:act-latest @@ -59,6 +89,12 @@ jobs: failure) line="❌ spacesh-landing — ошибка сборки";; *) line="❔ spacesh-landing — ${{ needs.landing.result }}";; esac + case "${{ needs.deploy.result }}" in + success) dline="🚀 задеплоен на прод";; + failure) dline="❌ деплой упал";; + *) dline="❔ деплой — ${{ needs.deploy.result }}";; + esac + line="$line"$'\n'"$dline" url="${{ gitea.server_url }}/${{ gitea.repository }}/actions/runs/${{ gitea.run_number }}" text=$(printf '**Build landing**\n\n%s\n\n[лог](%s)' "$line" "$url") curl -s -X POST "https://platform-api.max.ru/messages?chat_id=${{ secrets.MAX_CHAT_ID }}" \ diff --git a/Makefile b/Makefile index ed9cb31..605d6be 100644 --- a/Makefile +++ b/Makefile @@ -17,6 +17,13 @@ LANDING_VERSION := $(shell cat landing/VERSION 2>/dev/null || echo 0.0.0) REGISTRY ?= git.realmanual.ru REPO ?= spacesh +# ---- Prod deploy (SSH) ---- +SSH_HOST ?= 192.168.8.5 +SSH_USER ?= deploy +SSH_REMOTE_DIR ?= /opt/spacesh +SSH_KEY ?= $(HOME)/.ssh/id_rsa +SSH_OPTS := -i $(SSH_KEY) -o StrictHostKeyChecking=accept-new + .DEFAULT_GOAL := help .PHONY: help @@ -109,6 +116,20 @@ landing-push: landing-image ## tag & push the landing image to the registry docker push $(REGISTRY)/$(REPO)/$(LANDING_IMAGE):$(LANDING_VERSION) docker push $(REGISTRY)/$(REPO)/$(LANDING_IMAGE):latest +# ---- Prod deploy ---- + +.PHONY: deploy-dmg +deploy-dmg: dmg ## upload the universal .dmg to the prod download dir (stable spacesh.dmg) + ssh $(SSH_OPTS) $(SSH_USER)@$(SSH_HOST) "mkdir -p $(SSH_REMOTE_DIR)/download" + scp $(SSH_OPTS) $(DMG_DIR)/*.dmg "$(SSH_USER)@$(SSH_HOST):$(SSH_REMOTE_DIR)/download/spacesh.dmg" + @echo "Uploaded → https://spaceshell.ru/download/spacesh.dmg" + +.PHONY: deploy-stack +deploy-stack: ## sync compose+proxy.conf to prod and pull/up (manual; CI does this on push) + ssh $(SSH_OPTS) $(SSH_USER)@$(SSH_HOST) "mkdir -p $(SSH_REMOTE_DIR)/download" + scp $(SSH_OPTS) deploy/docker-compose.yaml deploy/proxy.conf "$(SSH_USER)@$(SSH_HOST):$(SSH_REMOTE_DIR)/" + ssh $(SSH_OPTS) $(SSH_USER)@$(SSH_HOST) "cd $(SSH_REMOTE_DIR) && docker compose pull && docker compose up -d" + # ---- Clean ---- .PHONY: clean diff --git a/deploy/README.md b/deploy/README.md new file mode 100644 index 0000000..0ba2aa9 --- /dev/null +++ b/deploy/README.md @@ -0,0 +1,31 @@ +# Deploy — spaceshell.ru + +Front nginx (`proxy`) → landing container, plus `/download/spacesh.dmg`. + +## Layout on the server (`$SSH_REMOTE_DIR`, e.g. `/opt/spacesh`) + +``` +docker-compose.yaml # synced by CI +proxy.conf # synced by CI +download/spacesh.dmg # uploaded locally via `make deploy-dmg` +``` + +## One-time server setup + +```bash +# The landing image lives in a private registry — log the server in once: +docker login git.realmanual.ru +mkdir -p $SSH_REMOTE_DIR/download +``` + +## What runs where + +- **Landing image + compose deploy** → automatic in `.gitea/workflows/build.yaml` + on push to `landing/**`. CI builds/pushes the image, scps `deploy/*` to the + server, then `docker compose pull && up -d`. +- **DMG** → built on macOS, uploaded by hand: `make deploy-dmg` + (sets the stable `download/spacesh.dmg`). Tauri can't build a macOS bundle in CI. + +## Gitea secrets required + +`SSH_HOST`, `SSH_USER`, `SSH_REMOTE_DIR`, `SSH_KEY` (private key, key-based auth). diff --git a/deploy/docker-compose.yaml b/deploy/docker-compose.yaml new file mode 100644 index 0000000..05222d3 --- /dev/null +++ b/deploy/docker-compose.yaml @@ -0,0 +1,32 @@ +# spacesh prod — front nginx proxies to the landing container and serves the DMG. +# Deployed by .gitea/workflows/build.yaml (image + this file); the DMG is uploaded +# separately via `make deploy-dmg` (Tauri can't cross-compile a macOS bundle in CI). +services: + landing: + # LANDING_IMAGE is written to .env by the CI deploy job (exact registry path + tag). + image: ${LANDING_IMAGE:-git.realmanual.ru/spacesh/spacesh-landing:latest} + restart: unless-stopped + expose: + - "80" + + proxy: + image: nginx:1.27-alpine + restart: unless-stopped + depends_on: + - landing + ports: + - "80:80" + volumes: + - ./proxy.conf:/etc/nginx/conf.d/default.conf:ro + - ./download:/srv/download:ro + networks: + spaceshell-network: + webproxy: + ipv4_address: 172.18.0.28 + +networks: + spaceshell-network: + driver: bridge + webproxy: + name: webproxy + external: true \ No newline at end of file diff --git a/deploy/proxy.conf b/deploy/proxy.conf new file mode 100644 index 0000000..201ce82 --- /dev/null +++ b/deploy/proxy.conf @@ -0,0 +1,30 @@ +# Front nginx for spaceshell.ru — reverse-proxies the landing container and +# serves macOS .dmg downloads from the host-mounted ./download volume. +upstream landing_upstream { + server landing:80; +} + +server { + listen 80; + listen [::]:80; + server_name spaceshell.ru www.spaceshell.ru; + + # Stable download URL: /download/spacesh.dmg → ./download/spacesh.dmg on host. + location /download/ { + alias /srv/download/; + autoindex off; + default_type application/octet-stream; + add_header Content-Disposition "attachment"; + types { + application/x-apple-diskimage dmg; + } + } + + location / { + proxy_pass http://landing_upstream; + 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; + } +} diff --git a/landing/index.html b/landing/index.html index 712e1bc..5b73aed 100644 --- a/landing/index.html +++ b/landing/index.html @@ -1098,7 +1098,7 @@

Готов гонять агентов пачками?

- +