name: Deploy on: pull_request: types: - closed branches: - master - main workflow_dispatch: inputs: tag: description: 'Image tag to deploy' required: false default: 'latest' environment: description: 'Deployment environment' required: true default: 'production' type: choice options: - production - staging env: REGISTRY: code.littlelan.cn IMAGE_NAME: carrot_bbs/backend SERVER_HOST: 111.170.19.33 SERVER_USER: root CONTAINER_NAME: carrot_bbs CONTAINER_NETWORK: 1panel-network jobs: deploy: runs-on: ubuntu-latest if: ${{ (github.event.pull_request.merged == true) || (github.event_name == 'workflow_dispatch') }} environment: production steps: - name: Deploy via SSH uses: appleboy/ssh-action@v1.0.3 with: host: ${{ env.SERVER_HOST }} username: ${{ env.SERVER_USER }} password: ${{ secrets.SERVER_PASSWORD }} script: | set -e IMAGE="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.event.inputs.tag || 'latest' }}" CONTAINER="${{ env.CONTAINER_NAME }}" NETWORK="${{ env.CONTAINER_NETWORK }}" echo "=== Pulling image: ${IMAGE} ===" docker pull ${IMAGE} echo "=== Stopping old container ===" docker stop ${CONTAINER} 2>/dev/null || true docker rm ${CONTAINER} 2>/dev/null || true echo "=== Starting new container ===" docker run -d \ --name ${CONTAINER} \ --network ${NETWORK} \ --restart unless-stopped \ -p 8080:8080 \ -p 50051:50051 \ -e APP_DATABASE_TYPE=postgres \ -e APP_DATABASE_POSTGRES_HOST=1Panel-postgresql-t0g7 \ -e APP_DATABASE_POSTGRES_PORT=5432 \ -e APP_DATABASE_POSTGRES_USER=carrot_bbs \ -e "APP_DATABASE_POSTGRES_PASSWORD=${{ secrets.DB_PASSWORD }}" \ -e APP_DATABASE_POSTGRES_DBNAME=carrot_bbs \ -e APP_REDIS_TYPE=redis \ -e APP_REDIS_REDIS_HOST=1Panel-redis-dfmM \ -e APP_REDIS_REDIS_PORT=6379 \ -e "APP_REDIS_REDIS_PASSWORD=${{ secrets.REDIS_PASSWORD }}" \ -e APP_REDIS_REDIS_DB=0 \ -e APP_S3_ENDPOINT=files.littlelan.cn \ -e "APP_S3_ACCESS_KEY=${{ secrets.S3_ACCESS_KEY }}" \ -e "APP_S3_SECRET_KEY=${{ secrets.S3_SECRET_KEY }}" \ -e APP_S3_BUCKET=test \ -e APP_S3_DOMAIN=files.littlelan.cn \ -e APP_S3_USE_SSL=true \ -e "APP_JWT_SECRET=${{ secrets.JWT_SECRET }}" \ -e APP_ENCRYPTION_ENABLED=true \ -e "APP_ENCRYPTION_KEY=${{ secrets.ENCRYPTION_KEY }}" \ -e APP_ENCRYPTION_KEY_VERSION=1 \ -e APP_GORSE_ENABLED=true \ -e APP_GORSE_ADDRESS=http://111.170.19.33:8088 \ -e "APP_GORSE_IMPORT_PASSWORD=${{ secrets.GORSE_IMPORT_PASSWORD }}" \ -e "APP_GORSE_EMBEDDING_API_KEY=${{ secrets.GORSE_EMBEDDING_API_KEY }}" \ -e APP_GORSE_EMBEDDING_URL=https://api.littlelan.cn/v1/embeddings \ -e APP_GORSE_EMBEDDING_MODEL=BAAI/bge-m3 \ -e APP_OPENAI_ENABLED=true \ -e APP_OPENAI_BASE_URL=https://api.littlelan.cn/ \ -e "APP_OPENAI_API_KEY=${{ secrets.OPENAI_API_KEY }}" \ -e APP_OPENAI_MODERATION_MODEL=qwen3.5-plus \ -e APP_OPENAI_MODERATION_MAX_IMAGES_PER_REQUEST=3 \ -e APP_OPENAI_REQUEST_TIMEOUT=30 \ -e APP_OPENAI_STRICT_MODERATION=false \ -e APP_EMAIL_ENABLED=true \ -e APP_EMAIL_HOST=smtp.exmail.qq.com \ -e APP_EMAIL_PORT=465 \ -e APP_EMAIL_USERNAME=no-reply@qczlit.cn \ -e "APP_EMAIL_PASSWORD=${{ secrets.EMAIL_PASSWORD }}" \ -e APP_EMAIL_FROM_ADDRESS=no-reply@qczlit.cn \ -e APP_EMAIL_FROM_NAME=Carrot_BBS \ -e APP_EMAIL_USE_TLS=true \ -e APP_EMAIL_TIMEOUT=15 \ -e APP_GRPC_ENABLED=true \ -e APP_GRPC_PORT=50051 \ -e APP_SERVER_MODE=release \ ${IMAGE} echo "=== Waiting for startup ===" sleep 5 echo "=== Health check ===" for i in 1 2 3; do if curl -sf http://localhost:8080/health; then echo "Health check passed!" break fi echo "Attempt $i failed, retrying..." sleep 3 done echo "=== Container logs ===" docker logs ${CONTAINER} --tail 20 echo "=== Deployment completed ==="