Chỉnh form auth dùng placeholder #13
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build and deploy | |
| on: | |
| push: | |
| branches: | |
| - master | |
| workflow_dispatch: | |
| concurrency: | |
| group: deploy-master | |
| cancel-in-progress: true | |
| jobs: | |
| build: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Set up Go | |
| uses: actions/setup-go@v6 | |
| with: | |
| go-version-file: backend/go.mod | |
| cache-dependency-path: backend/go.mod | |
| - name: Test backend | |
| working-directory: backend | |
| run: go test ./... | |
| - name: Build backend | |
| working-directory: backend | |
| run: | | |
| mkdir -p dist | |
| go build -o dist/mergeos ./cmd/mergeos | |
| - name: Set up Node | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: 22 | |
| cache: npm | |
| cache-dependency-path: | | |
| frontend/package-lock.json | |
| admin/package-lock.json | |
| scan/package-lock.json | |
| - name: Install frontend dependencies | |
| working-directory: frontend | |
| run: npm ci | |
| - name: Build frontend | |
| working-directory: frontend | |
| run: npm run build | |
| - name: Install admin dependencies | |
| working-directory: admin | |
| run: npm ci | |
| - name: Build admin | |
| working-directory: admin | |
| run: npm run build | |
| - name: Install scan dependencies | |
| working-directory: scan | |
| run: npm ci | |
| - name: Build scan | |
| working-directory: scan | |
| run: npm run build | |
| - name: Package release | |
| run: | | |
| mkdir -p release/frontend/dist | |
| mkdir -p release/admin/dist | |
| mkdir -p release/scan/dist | |
| cp backend/dist/mergeos release/mergeos | |
| cp -R frontend/dist/. release/frontend/dist/ | |
| cp -R admin/dist/. release/admin/dist/ | |
| cp -R scan/dist/. release/scan/dist/ | |
| cp frontend/server.js frontend/package.json frontend/package-lock.json release/frontend/ | |
| tar -czf mergeos-release.tar.gz -C release . | |
| - name: Upload release artifact | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: mergeos-release | |
| path: mergeos-release.tar.gz | |
| deploy: | |
| needs: build | |
| runs-on: ubuntu-latest | |
| if: github.ref == 'refs/heads/master' | |
| steps: | |
| - name: Download release artifact | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: mergeos-release | |
| - name: Validate deploy secrets | |
| env: | |
| DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} | |
| DEPLOY_USER: ${{ secrets.DEPLOY_USER }} | |
| DEPLOY_PASSWORD: ${{ secrets.DEPLOY_PASSWORD }} | |
| DEPLOY_PORT: ${{ secrets.DEPLOY_PORT }} | |
| run: | | |
| test -n "$DEPLOY_HOST" | |
| test -n "$DEPLOY_USER" | |
| test -n "$DEPLOY_PASSWORD" | |
| test -n "$DEPLOY_PORT" | |
| - name: Prepare deploy directory | |
| uses: appleboy/ssh-action@v1.0.3 | |
| env: | |
| DEPLOY_PATH: ${{ secrets.DEPLOY_PATH }} | |
| with: | |
| host: ${{ secrets.DEPLOY_HOST }} | |
| username: ${{ secrets.DEPLOY_USER }} | |
| password: ${{ secrets.DEPLOY_PASSWORD }} | |
| port: ${{ secrets.DEPLOY_PORT }} | |
| envs: DEPLOY_PATH | |
| script: | | |
| set -e | |
| APP_DIR="${DEPLOY_PATH:-$HOME/mergeos}" | |
| mkdir -p "$APP_DIR" | |
| - name: Upload release to server | |
| uses: appleboy/scp-action@v0.1.7 | |
| with: | |
| host: ${{ secrets.DEPLOY_HOST }} | |
| username: ${{ secrets.DEPLOY_USER }} | |
| password: ${{ secrets.DEPLOY_PASSWORD }} | |
| port: ${{ secrets.DEPLOY_PORT }} | |
| source: mergeos-release.tar.gz | |
| target: ${{ secrets.DEPLOY_PATH }} | |
| - name: Activate release | |
| uses: appleboy/ssh-action@v1.0.3 | |
| env: | |
| DEPLOY_PATH: ${{ secrets.DEPLOY_PATH }} | |
| with: | |
| host: ${{ secrets.DEPLOY_HOST }} | |
| username: ${{ secrets.DEPLOY_USER }} | |
| password: ${{ secrets.DEPLOY_PASSWORD }} | |
| port: ${{ secrets.DEPLOY_PORT }} | |
| envs: DEPLOY_PATH | |
| script: | | |
| set -e | |
| APP_DIR="${DEPLOY_PATH:-$HOME/mergeos}" | |
| cd "$APP_DIR" | |
| rm -rf frontend | |
| rm -rf admin | |
| rm -rf scan | |
| tar -xzf mergeos-release.tar.gz | |
| chmod +x mergeos | |
| DATABASE_URL_VALUE="" | |
| if command -v sudo >/dev/null 2>&1; then | |
| wait_for_apt() { | |
| if ! command -v fuser >/dev/null 2>&1; then | |
| return 0 | |
| fi | |
| for _ in $(seq 1 60); do | |
| if ! sudo -n fuser /var/lib/dpkg/lock-frontend /var/lib/dpkg/lock /var/lib/apt/lists/lock /var/cache/apt/archives/lock >/dev/null 2>&1; then | |
| return 0 | |
| fi | |
| sleep 2 | |
| done | |
| sudo -n fuser /var/lib/dpkg/lock-frontend /var/lib/dpkg/lock /var/lib/apt/lists/lock /var/cache/apt/archives/lock | |
| return 1 | |
| } | |
| apt_update() { | |
| wait_for_apt | |
| sudo -n apt-get update | |
| } | |
| apt_install() { | |
| wait_for_apt | |
| sudo -n env DEBIAN_FRONTEND=noninteractive apt-get install -y "$@" | |
| } | |
| DB_NAME="mergeos" | |
| DB_USER="mergeos" | |
| DB_PASSWORD_FILE="$APP_DIR/.postgres-password" | |
| if ! command -v psql >/dev/null 2>&1 || ! command -v openssl >/dev/null 2>&1; then | |
| apt_update | |
| apt_install postgresql openssl | |
| fi | |
| if command -v systemctl >/dev/null 2>&1; then | |
| sudo -n systemctl enable postgresql >/dev/null 2>&1 || true | |
| sudo -n systemctl start postgresql | |
| else | |
| sudo -n service postgresql start | |
| fi | |
| if [ ! -s "$DB_PASSWORD_FILE" ]; then | |
| umask 077 | |
| openssl rand -hex 32 > "$DB_PASSWORD_FILE" | |
| fi | |
| DB_PASSWORD="$(tr -d '\r\n' < "$DB_PASSWORD_FILE")" | |
| sudo -n -u postgres psql -v ON_ERROR_STOP=1 <<SQL | |
| DO \$\$ | |
| BEGIN | |
| IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = '${DB_USER}') THEN | |
| CREATE ROLE ${DB_USER} LOGIN PASSWORD '${DB_PASSWORD}'; | |
| ELSE | |
| ALTER ROLE ${DB_USER} LOGIN PASSWORD '${DB_PASSWORD}'; | |
| END IF; | |
| END | |
| \$\$; | |
| SQL | |
| if ! sudo -n -u postgres psql -tAc "SELECT 1 FROM pg_database WHERE datname = '${DB_NAME}'" | grep -q 1; then | |
| sudo -n -u postgres createdb -O "$DB_USER" "$DB_NAME" | |
| fi | |
| sudo -n -u postgres psql -v ON_ERROR_STOP=1 -d "$DB_NAME" -c "ALTER DATABASE ${DB_NAME} OWNER TO ${DB_USER};" | |
| DATABASE_URL_VALUE="postgres://${DB_USER}:${DB_PASSWORD}@127.0.0.1:5432/${DB_NAME}?sslmode=disable" | |
| fi | |
| if command -v systemctl >/dev/null 2>&1; then | |
| SERVICE_DIR="$HOME/.config/systemd/user" | |
| SERVICE_FILE="$SERVICE_DIR/mergeos.service" | |
| mkdir -p "$SERVICE_DIR" | |
| loginctl enable-linger "$USER" 2>/dev/null || true | |
| cat > "$SERVICE_FILE" <<SERVICE | |
| [Unit] | |
| Description=MergeOS production service | |
| After=network.target | |
| [Service] | |
| Type=simple | |
| WorkingDirectory=$APP_DIR | |
| Environment=MERGEOS_ENV=production | |
| Environment=PORT=8080 | |
| Environment=DATABASE_URL=$DATABASE_URL_VALUE | |
| ExecStart=$APP_DIR/mergeos | |
| Restart=always | |
| RestartSec=5 | |
| [Install] | |
| WantedBy=default.target | |
| SERVICE | |
| systemctl --user daemon-reload | |
| systemctl --user enable mergeos.service | |
| systemctl --user restart mergeos.service | |
| systemctl --user is-active --quiet mergeos.service | |
| else | |
| pkill -f "$APP_DIR/mergeos" || true | |
| MERGEOS_ENV=production PORT=8080 DATABASE_URL="$DATABASE_URL_VALUE" nohup "$APP_DIR/mergeos" > "$APP_DIR/mergeos.log" 2> "$APP_DIR/mergeos.err.log" & | |
| fi | |
| if command -v sudo >/dev/null 2>&1; then | |
| NODE_MAJOR=22 | |
| if ! command -v node >/dev/null 2>&1 || ! node -e "process.exit(Number(process.versions.node.split('.')[0]) >= 22 ? 0 : 1)"; then | |
| apt_update | |
| apt_install ca-certificates curl gnupg | |
| sudo -n install -d -m 0755 /etc/apt/keyrings | |
| curl -fsSL "https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key" | gpg --dearmor | sudo -n tee /etc/apt/keyrings/nodesource.gpg >/dev/null | |
| echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_${NODE_MAJOR}.x nodistro main" | sudo -n tee /etc/apt/sources.list.d/nodesource.list >/dev/null | |
| apt_update | |
| apt_install nodejs | |
| fi | |
| cd "$APP_DIR/frontend" | |
| node -v | |
| npm -v | |
| npm ci --omit=dev | |
| cd "$APP_DIR" | |
| if command -v systemctl >/dev/null 2>&1; then | |
| SERVICE_DIR="$HOME/.config/systemd/user" | |
| FRONTEND_SERVICE_FILE="$SERVICE_DIR/mergeos-frontend.service" | |
| NPM_BIN="$(command -v npm)" | |
| mkdir -p "$SERVICE_DIR" | |
| cat > "$FRONTEND_SERVICE_FILE" <<SERVICE | |
| [Unit] | |
| Description=MergeOS SSR frontend | |
| After=network.target mergeos.service | |
| [Service] | |
| Type=simple | |
| WorkingDirectory=$APP_DIR/frontend | |
| Environment=MERGEOS_ENV=production | |
| Environment=NODE_ENV=production | |
| Environment=FRONTEND_HOST=127.0.0.1 | |
| Environment=FRONTEND_PORT=8081 | |
| Environment=API_TARGET=http://127.0.0.1:8080 | |
| ExecStart=$NPM_BIN run production | |
| Restart=always | |
| RestartSec=5 | |
| [Install] | |
| WantedBy=default.target | |
| SERVICE | |
| systemctl --user daemon-reload | |
| systemctl --user enable mergeos-frontend.service | |
| systemctl --user restart mergeos-frontend.service | |
| systemctl --user is-active --quiet mergeos-frontend.service | |
| else | |
| pkill -f "$APP_DIR/frontend/server.js" || true | |
| cd "$APP_DIR/frontend" | |
| MERGEOS_ENV=production NODE_ENV=production FRONTEND_HOST=127.0.0.1 FRONTEND_PORT=8081 API_TARGET=http://127.0.0.1:8080 nohup node server.js --mode production --prod > "$APP_DIR/frontend.log" 2> "$APP_DIR/frontend.err.log" & | |
| cd "$APP_DIR" | |
| fi | |
| if ! command -v nginx >/dev/null 2>&1; then | |
| apt_update | |
| apt_install nginx | |
| fi | |
| if ! command -v certbot >/dev/null 2>&1; then | |
| apt_update | |
| apt_install certbot python3-certbot-nginx | |
| fi | |
| sudo -n tee /etc/nginx/sites-available/mergeos >/dev/null <<NGINX | |
| server { | |
| listen 80; | |
| listen [::]:80; | |
| server_name scan.mergeos.shop; | |
| root $APP_DIR/scan/dist; | |
| index index.html; | |
| client_max_body_size 30m; | |
| location /api/ { | |
| proxy_pass http://127.0.0.1:8080; | |
| proxy_http_version 1.1; | |
| 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; | |
| } | |
| location /assets/ { | |
| try_files \$uri =404; | |
| access_log off; | |
| expires 1h; | |
| } | |
| location / { | |
| try_files \$uri \$uri/ /index.html; | |
| } | |
| } | |
| server { | |
| listen 80; | |
| listen [::]:80; | |
| server_name mergeos.shop _; | |
| root $APP_DIR/frontend/dist/client; | |
| index index.html; | |
| client_max_body_size 30m; | |
| location /api/ { | |
| proxy_pass http://127.0.0.1:8080; | |
| proxy_http_version 1.1; | |
| 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; | |
| } | |
| location /assets/ { | |
| try_files \$uri =404; | |
| access_log off; | |
| expires 1h; | |
| } | |
| location / { | |
| proxy_pass http://127.0.0.1:8081; | |
| proxy_http_version 1.1; | |
| 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 uta.mergeos.shop; | |
| root $APP_DIR/admin/dist; | |
| index index.html; | |
| client_max_body_size 30m; | |
| location /api/ { | |
| proxy_pass http://127.0.0.1:8080; | |
| proxy_http_version 1.1; | |
| 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; | |
| } | |
| location /assets/ { | |
| try_files \$uri =404; | |
| access_log off; | |
| expires 1h; | |
| } | |
| location / { | |
| try_files \$uri \$uri/ /index.html; | |
| } | |
| } | |
| NGINX | |
| sudo -n ln -sf /etc/nginx/sites-available/mergeos /etc/nginx/sites-enabled/mergeos | |
| sudo -n rm -f /etc/nginx/sites-enabled/default | |
| sudo -n nginx -t | |
| sudo -n systemctl enable nginx | |
| sudo -n systemctl restart nginx | |
| CERTBOT_CONTACT_ARGS="--register-unsafely-without-email" | |
| sudo -n certbot --nginx --non-interactive --agree-tos $CERTBOT_CONTACT_ARGS --redirect --keep-until-expiring --expand -d mergeos.shop -d uta.mergeos.shop -d scan.mergeos.shop | |
| sudo -n nginx -t | |
| sudo -n systemctl restart nginx | |
| sudo -n systemctl is-active --quiet nginx | |
| fi |