From 68a90349bb809a0a0dbc36a96cab915073ea38d0 Mon Sep 17 00:00:00 2001 From: moarshy Date: Sat, 22 Feb 2025 13:58:46 +0800 Subject: [PATCH 01/22] feat: Add GitHub Actions workflow for automated EC2 deployment - Created deploy.yml workflow for deploying application to multiple EC2 instances - Added deploy-readme.md with comprehensive documentation for deployment process - Configured workflow to trigger on push or merge to feat/deploy-actions branch - Implemented multi-instance deployment strategy with SSH-based deployment steps --- .github/workflows/deploy-readme.md | 83 ++++++++++++++++++++++++++++++ .github/workflows/deploy.yml | 52 +++++++++++++++++++ 2 files changed, 135 insertions(+) create mode 100644 .github/workflows/deploy-readme.md create mode 100644 .github/workflows/deploy.yml diff --git a/.github/workflows/deploy-readme.md b/.github/workflows/deploy-readme.md new file mode 100644 index 0000000..6839eb4 --- /dev/null +++ b/.github/workflows/deploy-readme.md @@ -0,0 +1,83 @@ +# Application Deployment Workflow + +This repository contains a GitHub Actions workflow for automated deployment to an Amazon EC2 instance. The workflow is triggered either by pushing to the `feat/deploy-actions` branch or when a pull request to this branch is merged. + +## Workflow Overview + +The deployment workflow automates the following steps: +1. Checks out the repository +2. Sets up SSH access to the EC2 instance +3. Deploys the application to EC2 +4. Reports the deployment status + +## Prerequisites + +Before using this workflow, ensure you have the following setup: + +1. An Amazon EC2 instance running Ubuntu +2. The following GitHub repository secrets configured: + - `EC2_SSH_KEY`: The private SSH key for connecting to the EC2 instance + - `EC2_HOST`: The hostname or IP address of your EC2 instance + - `DEPLOY_PATH`: The path on the EC2 instance where the application should be deployed + +## Trigger Conditions + +The workflow triggers under two conditions: +- On push to the `feat/deploy-actions` branch +- When a pull request to the `feat/deploy-actions` branch is merged + +## Deployment Process + +The deployment process follows these steps: + +1. **Repository Checkout**: Fetches the latest code from the repository +2. **SSH Setup**: + - Creates SSH directory + - Installs the SSH private key + - Adds the EC2 host to known hosts +3. **Application Deployment**: + - Connects to EC2 via SSH + - Navigates to the deployment directory + - Stashes any local changes + - Fetches and resets to the latest code + - Attempts to reapply stashed changes + - Stops the existing service + - Launches the new version +4. **Status Reporting**: Reports whether the deployment was successful or failed + +## Required Files + +The workflow expects the following files to exist in your repository: +- `stop_service.sh`: Script to stop the currently running service +- `launch.sh`: Script to start the application + +## Usage + +No manual intervention is needed for deployment. The workflow will automatically run when: +- Code is pushed to the `feat/deploy-actions` branch +- A pull request to the `feat/deploy-actions` branch is merged + +## Monitoring + +You can monitor deployments in the GitHub Actions tab of your repository. Each deployment will show: +- Complete logs of the deployment process +- Final deployment status (✅ success or ❌ failure) + +## Note + +Currently, the workflow is configured to use the `feat/deploy-actions` branch. This will be updated to use the `main` branch once testing is completed. + +## Troubleshooting + +If deployment fails, check: +1. EC2 instance is running and accessible +2. SSH key is correctly configured in GitHub secrets +3. All required scripts (`stop_service.sh` and `launch.sh`) exist and are executable +4. Deployment path exists on the EC2 instance +5. GitHub Actions logs for specific error messages + +## Security Considerations + +- The SSH key is stored securely in GitHub secrets +- SSH key permissions are set to 600 (read/write for owner only) +- Host key verification is enabled for the EC2 instance diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..f5f2aaa --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,52 @@ +name: Deploy Application + +on: + push: + branches: + - feat/deploy-actions + pull_request: + types: + - closed + branches: + - feat/deploy-actions + +jobs: + deploy: + if: github.event.pull_request.merged == true || github.event_name == 'push' + runs-on: ubuntu-latest + strategy: + matrix: + instance: [1, 2] + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Install SSH key + run: | + mkdir -p ~/.ssh + echo "${{ secrets.EC2_SSH_KEY }}" > ~/.ssh/daimon.pem + chmod 600 ~/.ssh/daimon.pem + ssh-keyscan -H "${{ secrets.EC2_HOST_${{ matrix.instance }} }}" >> ~/.ssh/known_hosts + + - name: Deploy to EC2 Instance ${{ matrix.instance }} + run: | + ssh -i ~/.ssh/daimon.pem ubuntu@${{ secrets.EC2_HOST_${{ matrix.instance }} }} << 'EOF' + cd ${{ secrets.DEPLOY_PATH }} + git stash + git fetch origin feat/deploy-actions # TODO: Change this to main once testing is done + git reset --hard origin/feat/deploy-actions # TODO: Change this to main once testing is done + git stash pop || true + bash stop_service.sh + bash launch.sh + echo "Deployment completed to Instance ${{ matrix.instance }} at $(date)" + EOF + + - name: Deployment Status + if: always() + run: | + if [ ${{ job.status }} == 'success' ]; then + echo "✅ Deployment successful to Instance ${{ matrix.instance }}" + else + echo "❌ Deployment failed for Instance ${{ matrix.instance }}" + fi \ No newline at end of file From 512185bd4c4450153748f605918074bc0b9bcabb Mon Sep 17 00:00:00 2001 From: moarshy Date: Sat, 22 Feb 2025 14:02:04 +0800 Subject: [PATCH 02/22] docs: Add comprehensive deployment documentation for GitHub Actions workflow --- .github/{workflows => }/deploy-readme.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/{workflows => }/deploy-readme.md (100%) diff --git a/.github/workflows/deploy-readme.md b/.github/deploy-readme.md similarity index 100% rename from .github/workflows/deploy-readme.md rename to .github/deploy-readme.md From c3f68e1c49b81026f9828d54da98c9a3391c2ad3 Mon Sep 17 00:00:00 2001 From: moarshy Date: Sat, 22 Feb 2025 14:04:00 +0800 Subject: [PATCH 03/22] fix: Improve EC2 deployment workflow with dynamic host and branch selection --- .github/workflows/deploy.yml | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index f5f2aaa..f9a1935 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -27,25 +27,32 @@ jobs: mkdir -p ~/.ssh echo "${{ secrets.EC2_SSH_KEY }}" > ~/.ssh/daimon.pem chmod 600 ~/.ssh/daimon.pem - ssh-keyscan -H "${{ secrets.EC2_HOST_${{ matrix.instance }} }}" >> ~/.ssh/known_hosts + if [ "${{ matrix.instance }}" == "1" ]; then + ssh-keyscan -H "${{ secrets.EC2_HOST_1 }}" >> ~/.ssh/known_hosts + else + ssh-keyscan -H "${{ secrets.EC2_HOST_2 }}" >> ~/.ssh/known_hosts + fi - name: Deploy to EC2 Instance ${{ matrix.instance }} + env: + EC2_HOST: ${{ matrix.instance == 1 && secrets.EC2_HOST_1 || secrets.EC2_HOST_2 }} + DEPLOY_PATH: ${{ secrets.DEPLOY_PATH }} run: | - ssh -i ~/.ssh/daimon.pem ubuntu@${{ secrets.EC2_HOST_${{ matrix.instance }} }} << 'EOF' - cd ${{ secrets.DEPLOY_PATH }} + ssh -i ~/.ssh/daimon.pem ubuntu@$EC2_HOST << EOF + cd $DEPLOY_PATH git stash - git fetch origin feat/deploy-actions # TODO: Change this to main once testing is done - git reset --hard origin/feat/deploy-actions # TODO: Change this to main once testing is done + git fetch origin feat/deploy-actions + git reset --hard origin/feat/deploy-actions git stash pop || true bash stop_service.sh bash launch.sh - echo "Deployment completed to Instance ${{ matrix.instance }} at $(date)" + echo "Deployment completed to Instance ${{ matrix.instance }} at \$(date)" EOF - name: Deployment Status if: always() run: | - if [ ${{ job.status }} == 'success' ]; then + if [ "${{ job.status }}" == "success" ]; then echo "✅ Deployment successful to Instance ${{ matrix.instance }}" else echo "❌ Deployment failed for Instance ${{ matrix.instance }}" From a728e9d78f02a652957674f32e201c3861b1e244 Mon Sep 17 00:00:00 2001 From: moarshy Date: Sat, 22 Feb 2025 14:10:19 +0800 Subject: [PATCH 04/22] fix: Remove unnecessary git stash pop in deployment workflow --- .github/workflows/deploy.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index f9a1935..c0b3852 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -43,7 +43,6 @@ jobs: git stash git fetch origin feat/deploy-actions git reset --hard origin/feat/deploy-actions - git stash pop || true bash stop_service.sh bash launch.sh echo "Deployment completed to Instance ${{ matrix.instance }} at \$(date)" From 190897555c109053764373d7b097117ec0548fe7 Mon Sep 17 00:00:00 2001 From: moarshy Date: Sat, 22 Feb 2025 14:54:28 +0800 Subject: [PATCH 05/22] fix: Add sudo to git stash in deployment workflow --- .github/workflows/deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index c0b3852..dd46ba3 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -40,7 +40,7 @@ jobs: run: | ssh -i ~/.ssh/daimon.pem ubuntu@$EC2_HOST << EOF cd $DEPLOY_PATH - git stash + sudo git stash git fetch origin feat/deploy-actions git reset --hard origin/feat/deploy-actions bash stop_service.sh From 49c1f58f383a8b9d2287ebc0145bf404381f56a5 Mon Sep 17 00:00:00 2001 From: moarshy Date: Sat, 22 Feb 2025 15:09:36 +0800 Subject: [PATCH 06/22] fix: Update health check response message --- node/server/http_server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/server/http_server.py b/node/server/http_server.py index eeb180d..e602333 100644 --- a/node/server/http_server.py +++ b/node/server/http_server.py @@ -88,7 +88,7 @@ async def shutdown_event(): @self.app.get("/health") async def health_check(): - return {"status": "ok", "communication_protocol": "http"} + return {"status": "ok!!!", "communication_protocol": "http"} # Handle validation errors when request data doesn't match the expected Pydantic models # Logs the validation error details and request body, then returns a 422 response with the error info From e4cd53284a60b5135f1b6d04f7c36b881923813a Mon Sep 17 00:00:00 2001 From: moarshy Date: Sat, 22 Feb 2025 15:14:44 +0800 Subject: [PATCH 07/22] fix status for ws and wss --- .github/workflows/deploy.yml | 5 +++-- launch.sh | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index dd46ba3..0a4d620 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -39,12 +39,13 @@ jobs: DEPLOY_PATH: ${{ secrets.DEPLOY_PATH }} run: | ssh -i ~/.ssh/daimon.pem ubuntu@$EC2_HOST << EOF + sudo chown -R ubuntu:ubuntu $DEPLOY_PATH cd $DEPLOY_PATH sudo git stash git fetch origin feat/deploy-actions git reset --hard origin/feat/deploy-actions - bash stop_service.sh - bash launch.sh + sudo bash stop_service.sh + sudo bash launch.sh echo "Deployment completed to Instance ${{ matrix.instance }} at \$(date)" EOF diff --git a/launch.sh b/launch.sh index f0ca809..74469c8 100755 --- a/launch.sh +++ b/launch.sh @@ -1754,7 +1754,7 @@ startup_summary() { services+=("$(echo $NODE_COMMUNICATION_PROTOCOL | tr '[:lower:]' '[:upper:]')_Server_${port}") # Health check based on server type - if [ "${NODE_COMMUNICATION_PROTOCOL}" = "ws" ]; then + if [ "${NODE_COMMUNICATION_PROTOCOL}" = "ws" -o "${NODE_COMMUNICATION_PROTOCOL}" = "wss" ]; then # WebSocket health check using /health endpoint if curl -s http://localhost:$port/health > /dev/null; then statuses+=("✅") From 5e0533486f1c9211169d789ff35feacf9252c273 Mon Sep 17 00:00:00 2001 From: moarshy Date: Sat, 22 Feb 2025 15:21:52 +0800 Subject: [PATCH 08/22] docs: Update deployment documentation and workflow for main branch deployment - Update deploy-readme.md with comprehensive server setup and GitHub configuration instructions - Modify deploy.yml to prepare for main branch deployment - Simplify health check response in http_server.py --- .github/deploy-readme.md | 35 ++++++++++++++++++++++++++--------- .github/workflows/deploy.yml | 8 ++++---- node/server/http_server.py | 2 +- 3 files changed, 31 insertions(+), 14 deletions(-) diff --git a/.github/deploy-readme.md b/.github/deploy-readme.md index 6839eb4..292f807 100644 --- a/.github/deploy-readme.md +++ b/.github/deploy-readme.md @@ -12,19 +12,36 @@ The deployment workflow automates the following steps: ## Prerequisites -Before using this workflow, ensure you have the following setup: +### Initial Server Setup +Before using this workflow, you must manually set up each EC2 instance: -1. An Amazon EC2 instance running Ubuntu -2. The following GitHub repository secrets configured: +1. Launch Ubuntu EC2 instances +2. Set up the deployment environment on each instance: + - Clone the repository to the target deployment path + - Create and configure the `.env` file with required environment variables + - Install all necessary dependencies (Node.js, Python, etc.) + - Ensure `launch.sh` and `stop_service.sh` are executable (`chmod +x *.sh`) + - Test the application manually to verify the environment is properly configured + +### GitHub Configuration +After server setup, configure the following GitHub repository secrets: + +1. For single instance deployment: - `EC2_SSH_KEY`: The private SSH key for connecting to the EC2 instance - `EC2_HOST`: The hostname or IP address of your EC2 instance - - `DEPLOY_PATH`: The path on the EC2 instance where the application should be deployed + - `DEPLOY_PATH`: The path on the EC2 instance where the application is deployed + +2. For dual instance deployment: + - `EC2_SSH_KEY`: The private SSH key (same key for both instances) + - `EC2_HOST_1`: The hostname/IP for the first EC2 instance + - `EC2_HOST_2`: The hostname/IP for the second EC2 instance + - `DEPLOY_PATH`: The deployment path (must be same on both instances) ## Trigger Conditions The workflow triggers under two conditions: -- On push to the `feat/deploy-actions` branch -- When a pull request to the `feat/deploy-actions` branch is merged +- On push to the `main` branch +- When a pull request to the `main` branch is merged ## Deployment Process @@ -54,8 +71,8 @@ The workflow expects the following files to exist in your repository: ## Usage No manual intervention is needed for deployment. The workflow will automatically run when: -- Code is pushed to the `feat/deploy-actions` branch -- A pull request to the `feat/deploy-actions` branch is merged +- Code is pushed to the `main` branch +- A pull request to the `main` branch is merged ## Monitoring @@ -65,7 +82,7 @@ You can monitor deployments in the GitHub Actions tab of your repository. Each d ## Note -Currently, the workflow is configured to use the `feat/deploy-actions` branch. This will be updated to use the `main` branch once testing is completed. +The workflow is configured to deploy from the `main` branch. All deployments will happen either through direct pushes to `main` or when pull requests are merged into `main`. ## Troubleshooting diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 0a4d620..1523791 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -3,12 +3,12 @@ name: Deploy Application on: push: branches: - - feat/deploy-actions + - feat/deploy-actions # TODO: Change this to main once testing is done pull_request: types: - closed branches: - - feat/deploy-actions + - feat/deploy-actions # TODO: Change this to main once testing is done jobs: deploy: @@ -42,8 +42,8 @@ jobs: sudo chown -R ubuntu:ubuntu $DEPLOY_PATH cd $DEPLOY_PATH sudo git stash - git fetch origin feat/deploy-actions - git reset --hard origin/feat/deploy-actions + git fetch origin main + git reset --hard origin/main sudo bash stop_service.sh sudo bash launch.sh echo "Deployment completed to Instance ${{ matrix.instance }} at \$(date)" diff --git a/node/server/http_server.py b/node/server/http_server.py index e602333..eeb180d 100644 --- a/node/server/http_server.py +++ b/node/server/http_server.py @@ -88,7 +88,7 @@ async def shutdown_event(): @self.app.get("/health") async def health_check(): - return {"status": "ok!!!", "communication_protocol": "http"} + return {"status": "ok", "communication_protocol": "http"} # Handle validation errors when request data doesn't match the expected Pydantic models # Logs the validation error details and request body, then returns a 422 response with the error info From 0f497c8db799bf6d01c9bedc315c44539a39103c Mon Sep 17 00:00:00 2001 From: moarshy Date: Sat, 22 Feb 2025 15:23:01 +0800 Subject: [PATCH 09/22] docs: Update deployment documentation for main branch trigger --- .github/deploy-readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/deploy-readme.md b/.github/deploy-readme.md index 292f807..5e7c62e 100644 --- a/.github/deploy-readme.md +++ b/.github/deploy-readme.md @@ -1,6 +1,6 @@ # Application Deployment Workflow -This repository contains a GitHub Actions workflow for automated deployment to an Amazon EC2 instance. The workflow is triggered either by pushing to the `feat/deploy-actions` branch or when a pull request to this branch is merged. +This repository contains a GitHub Actions workflow for automated deployment to an Amazon EC2 instance. The workflow is triggered either by pushing to the `main` or when a pull request to merged to main. ## Workflow Overview From 954d62daa4a378afa56c30bbced2c558fa6479c0 Mon Sep 17 00:00:00 2001 From: moarshy Date: Sat, 22 Feb 2025 20:59:04 +0800 Subject: [PATCH 10/22] chore: Update deployment workflow to trigger on main branch --- .github/workflows/deploy.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 1523791..79caa47 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -3,12 +3,12 @@ name: Deploy Application on: push: branches: - - feat/deploy-actions # TODO: Change this to main once testing is done + - main pull_request: types: - closed branches: - - feat/deploy-actions # TODO: Change this to main once testing is done + - main jobs: deploy: From b9529a40d986af6d94756cf53a8960ca116ad8fe Mon Sep 17 00:00:00 2001 From: moarshy Date: Sat, 22 Feb 2025 20:59:15 +0800 Subject: [PATCH 11/22] feat: Add GitHub Actions workflow for A100 instance deployment - Created deploy-a100.yml workflow for deploying application to A100 instance - Configured workflow to trigger on push or merge to feat/deploy-actions branch - Implemented deployment steps with SSH-based deployment and Docker compose - Updated health check response in http_server.py --- .github/workflows/deploy-a100.yml | 53 +++++++++++++++++++++++++++++++ node/server/http_server.py | 2 +- 2 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/deploy-a100.yml diff --git a/.github/workflows/deploy-a100.yml b/.github/workflows/deploy-a100.yml new file mode 100644 index 0000000..597f54d --- /dev/null +++ b/.github/workflows/deploy-a100.yml @@ -0,0 +1,53 @@ +name: Deploy Application + +on: + push: + branches: + - feat/deploy-actions # TODO: Change to main later + pull_request: + types: + - closed + branches: + - feat/deploy-actions # TODO: Change to main later + +jobs: + deploy: + if: github.event.pull_request.merged == true || github.event_name == 'push' + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup SSH + uses: webfactory/ssh-agent@v0.8.0 + with: + ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }} + known-hosts: ${{ secrets.SSH_KNOWN_HOSTS }} + + - name: Deploy to A100 Instance + env: + HOST: ${{ secrets.A100_HOST_2 }} + DEPLOY_USER: ${{ secrets.A100_USER }} + DEPLOY_PATH: ${{ secrets.A100_DEPLOY_PATH }} + run: | + ssh $DEPLOY_USER@$HOST << 'EOF' + sudo chown -R $DEPLOY_USER:$DEPLOY_USER $DEPLOY_PATH + cd $DEPLOY_PATH + sudo git stash + git fetch origin main + git reset --hard origin/main + docker compose -f docker-compose.yml build --no-cache + ./docker-ctl down + sudo bash launch.sh + echo "Deployment completed at $(date)" + EOF + + - name: Deployment Status + if: always() + run: | + if [ "${{ job.status }}" == "success" ]; then + echo "✅ Deployment successful to A100 Instance" + else + echo "❌ Deployment failed for A100 Instance" + fi \ No newline at end of file diff --git a/node/server/http_server.py b/node/server/http_server.py index eeb180d..e602333 100644 --- a/node/server/http_server.py +++ b/node/server/http_server.py @@ -88,7 +88,7 @@ async def shutdown_event(): @self.app.get("/health") async def health_check(): - return {"status": "ok", "communication_protocol": "http"} + return {"status": "ok!!!", "communication_protocol": "http"} # Handle validation errors when request data doesn't match the expected Pydantic models # Logs the validation error details and request body, then returns a 422 response with the error info From b17569e5dde804256ccf4b8fc070b117d408bef1 Mon Sep 17 00:00:00 2001 From: moarshy Date: Sat, 22 Feb 2025 21:02:12 +0800 Subject: [PATCH 12/22] fix: Improve SSH configuration and deployment workflow for A100 instance --- .github/workflows/deploy-a100.yml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/deploy-a100.yml b/.github/workflows/deploy-a100.yml index 597f54d..ae9139c 100644 --- a/.github/workflows/deploy-a100.yml +++ b/.github/workflows/deploy-a100.yml @@ -19,11 +19,16 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 - - name: Setup SSH + - name: Setup SSH Config + run: | + mkdir -p ~/.ssh + echo "${{ secrets.SSH_KNOWN_HOSTS }}" > ~/.ssh/known_hosts + chmod 600 ~/.ssh/known_hosts + + - name: Setup SSH Key uses: webfactory/ssh-agent@v0.8.0 with: ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }} - known-hosts: ${{ secrets.SSH_KNOWN_HOSTS }} - name: Deploy to A100 Instance env: @@ -31,7 +36,7 @@ jobs: DEPLOY_USER: ${{ secrets.A100_USER }} DEPLOY_PATH: ${{ secrets.A100_DEPLOY_PATH }} run: | - ssh $DEPLOY_USER@$HOST << 'EOF' + ssh -o StrictHostKeyChecking=no $DEPLOY_USER@$HOST << 'EOF' sudo chown -R $DEPLOY_USER:$DEPLOY_USER $DEPLOY_PATH cd $DEPLOY_PATH sudo git stash From 9a16486ad266ded06072c7f4193327fec77d5555 Mon Sep 17 00:00:00 2001 From: moarshy Date: Sat, 22 Feb 2025 21:08:59 +0800 Subject: [PATCH 13/22] chore: Add debug logging to A100 deployment workflow - Include debug echo statements to trace deployment process - Log current user, directory, and deployment path - Add directory listing commands for troubleshooting --- .github/workflows/deploy-a100.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/.github/workflows/deploy-a100.yml b/.github/workflows/deploy-a100.yml index ae9139c..1d64c76 100644 --- a/.github/workflows/deploy-a100.yml +++ b/.github/workflows/deploy-a100.yml @@ -37,8 +37,23 @@ jobs: DEPLOY_PATH: ${{ secrets.A100_DEPLOY_PATH }} run: | ssh -o StrictHostKeyChecking=no $DEPLOY_USER@$HOST << 'EOF' + # Debug information + echo "Current user: $(whoami)" + echo "Current directory: $(pwd)" + echo "DEPLOY_PATH: $DEPLOY_PATH" + echo "Listing current directory:" + ls -la + + # Your other commands... + sudo mkdir -p $DEPLOY_PATH + echo "Listing DEPLOY_PATH directory:" + ls -la $DEPLOY_PATH + sudo chown -R $DEPLOY_USER:$DEPLOY_USER $DEPLOY_PATH cd $DEPLOY_PATH + echo "After cd to DEPLOY_PATH:" + pwd + ls -la sudo git stash git fetch origin main git reset --hard origin/main From 231bb41dae7c40407e980926788941fce5fc67b2 Mon Sep 17 00:00:00 2001 From: moarshy Date: Sat, 22 Feb 2025 21:11:56 +0800 Subject: [PATCH 14/22] refactor: Improve A100 deployment workflow SSH configuration - Explicitly pass environment variables to SSH command - Add error handling for unset DEPLOY_PATH - Simplify deployment path ownership and navigation - Remove deployment-specific commands for cleaner workflow --- .github/workflows/deploy-a100.yml | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/.github/workflows/deploy-a100.yml b/.github/workflows/deploy-a100.yml index 1d64c76..dfa259b 100644 --- a/.github/workflows/deploy-a100.yml +++ b/.github/workflows/deploy-a100.yml @@ -36,31 +36,27 @@ jobs: DEPLOY_USER: ${{ secrets.A100_USER }} DEPLOY_PATH: ${{ secrets.A100_DEPLOY_PATH }} run: | - ssh -o StrictHostKeyChecking=no $DEPLOY_USER@$HOST << 'EOF' - # Debug information + # Pass environment variables explicitly to the SSH command + ssh -o StrictHostKeyChecking=no $DEPLOY_USER@$HOST "DEPLOY_PATH='${DEPLOY_PATH}' bash -s" << 'EOF' echo "Current user: $(whoami)" echo "Current directory: $(pwd)" - echo "DEPLOY_PATH: $DEPLOY_PATH" - echo "Listing current directory:" - ls -la + echo "DEPLOY_PATH: ${DEPLOY_PATH}" - # Your other commands... - sudo mkdir -p $DEPLOY_PATH + if [ -z "${DEPLOY_PATH}" ]; then + echo "Error: DEPLOY_PATH is not set" + exit 1 + fi + + # Create and navigate to deploy path + sudo mkdir -p ${DEPLOY_PATH} echo "Listing DEPLOY_PATH directory:" - ls -la $DEPLOY_PATH + ls -la ${DEPLOY_PATH} - sudo chown -R $DEPLOY_USER:$DEPLOY_USER $DEPLOY_PATH - cd $DEPLOY_PATH + sudo chown -R $(whoami):$(whoami) ${DEPLOY_PATH} + cd ${DEPLOY_PATH} echo "After cd to DEPLOY_PATH:" pwd ls -la - sudo git stash - git fetch origin main - git reset --hard origin/main - docker compose -f docker-compose.yml build --no-cache - ./docker-ctl down - sudo bash launch.sh - echo "Deployment completed at $(date)" EOF - name: Deployment Status From 3438dfd8664cfe2c5b7b3fb959e1c6c12a9aab59 Mon Sep 17 00:00:00 2001 From: moarshy Date: Sat, 22 Feb 2025 21:13:25 +0800 Subject: [PATCH 15/22] refactor: Streamline A100 deployment workflow with direct git and docker commands - Simplify SSH deployment script to focus on core deployment steps - Remove debug logging and error handling - Add direct git fetch, reset, and docker compose build commands - Integrate docker-ctl and launch.sh for deployment --- .github/workflows/deploy-a100.yml | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/.github/workflows/deploy-a100.yml b/.github/workflows/deploy-a100.yml index dfa259b..11c29c3 100644 --- a/.github/workflows/deploy-a100.yml +++ b/.github/workflows/deploy-a100.yml @@ -36,27 +36,16 @@ jobs: DEPLOY_USER: ${{ secrets.A100_USER }} DEPLOY_PATH: ${{ secrets.A100_DEPLOY_PATH }} run: | - # Pass environment variables explicitly to the SSH command ssh -o StrictHostKeyChecking=no $DEPLOY_USER@$HOST "DEPLOY_PATH='${DEPLOY_PATH}' bash -s" << 'EOF' - echo "Current user: $(whoami)" - echo "Current directory: $(pwd)" - echo "DEPLOY_PATH: ${DEPLOY_PATH}" - - if [ -z "${DEPLOY_PATH}" ]; then - echo "Error: DEPLOY_PATH is not set" - exit 1 - fi - - # Create and navigate to deploy path - sudo mkdir -p ${DEPLOY_PATH} - echo "Listing DEPLOY_PATH directory:" - ls -la ${DEPLOY_PATH} - - sudo chown -R $(whoami):$(whoami) ${DEPLOY_PATH} - cd ${DEPLOY_PATH} - echo "After cd to DEPLOY_PATH:" - pwd - ls -la + sudo chown -R $DEPLOY_USER:$DEPLOY_USER $DEPLOY_PATH + cd $DEPLOY_PATH + sudo git stash + git fetch origin main + git reset --hard origin/main + docker compose -f docker-compose.yml build --no-cache + ./docker-ctl down + sudo bash launch.sh + echo "Deployment completed at $(date)" EOF - name: Deployment Status From e9e5992999d04f45c80496ce214c5ce0b18498e7 Mon Sep 17 00:00:00 2001 From: moarshy Date: Sat, 22 Feb 2025 21:30:19 +0800 Subject: [PATCH 16/22] feat: Enhance A100 deployment workflow with environment and Python setup - Add environment sourcing for conda/miniforge - Verify Python availability during deployment - Switch deployment to feat/deploy-actions branch - Use sudo with preserved environment for launch script - Improve deployment script robustness --- .github/workflows/deploy-a100.yml | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/.github/workflows/deploy-a100.yml b/.github/workflows/deploy-a100.yml index 11c29c3..302a7cf 100644 --- a/.github/workflows/deploy-a100.yml +++ b/.github/workflows/deploy-a100.yml @@ -37,14 +37,31 @@ jobs: DEPLOY_PATH: ${{ secrets.A100_DEPLOY_PATH }} run: | ssh -o StrictHostKeyChecking=no $DEPLOY_USER@$HOST "DEPLOY_PATH='${DEPLOY_PATH}' bash -s" << 'EOF' + # Load environment and Python + source ~/.bashrc + + # Ensure we're using conda/miniforge environment if needed + if [ -f ~/miniforge3/bin/activate ]; then + source ~/miniforge3/bin/activate + elif [ -f ~/miniconda3/bin/activate ]; then + source ~/miniconda3/bin/activate + fi + + # Navigate and setup deployment sudo chown -R $DEPLOY_USER:$DEPLOY_USER $DEPLOY_PATH cd $DEPLOY_PATH sudo git stash - git fetch origin main - git reset --hard origin/main + git fetch origin feat/deploy-actions + git reset --hard origin/feat/deploy-actions + + # Verify Python is available + which python + python --version + + # Your deployment commands docker compose -f docker-compose.yml build --no-cache ./docker-ctl down - sudo bash launch.sh + sudo -E bash launch.sh echo "Deployment completed at $(date)" EOF From 8a2a04af0c6f4301bd2b1e24a03b4694ee5e7267 Mon Sep 17 00:00:00 2001 From: moarshy Date: Sat, 22 Feb 2025 21:35:22 +0800 Subject: [PATCH 17/22] feat: Optimize A100 deployment script with refined environment and execution steps - Simplify conda/miniforge environment activation - Add explicit PATH export for miniforge - Make docker-ctl.sh executable - Streamline deployment commands - Remove redundant Python version checks --- .github/workflows/deploy-a100.yml | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/.github/workflows/deploy-a100.yml b/.github/workflows/deploy-a100.yml index 302a7cf..f3f919e 100644 --- a/.github/workflows/deploy-a100.yml +++ b/.github/workflows/deploy-a100.yml @@ -30,7 +30,7 @@ jobs: with: ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }} - - name: Deploy to A100 Instance + - name: Deploy to A100 Instance env: HOST: ${{ secrets.A100_HOST_2 }} DEPLOY_USER: ${{ secrets.A100_USER }} @@ -38,29 +38,24 @@ jobs: run: | ssh -o StrictHostKeyChecking=no $DEPLOY_USER@$HOST "DEPLOY_PATH='${DEPLOY_PATH}' bash -s" << 'EOF' # Load environment and Python + export PATH="/home/$USER/miniforge3/bin:$PATH" source ~/.bashrc - - # Ensure we're using conda/miniforge environment if needed - if [ -f ~/miniforge3/bin/activate ]; then - source ~/miniforge3/bin/activate - elif [ -f ~/miniconda3/bin/activate ]; then - source ~/miniconda3/bin/activate - fi + source /home/$USER/miniforge3/bin/activate # Navigate and setup deployment sudo chown -R $DEPLOY_USER:$DEPLOY_USER $DEPLOY_PATH cd $DEPLOY_PATH + sudo git stash git fetch origin feat/deploy-actions git reset --hard origin/feat/deploy-actions - # Verify Python is available - which python - python --version - + # Make scripts executable + chmod +x ./docker-ctl.sh + # Your deployment commands docker compose -f docker-compose.yml build --no-cache - ./docker-ctl down + ./docker-ctl.sh down sudo -E bash launch.sh echo "Deployment completed at $(date)" EOF From 31173e0ed1634fff4d0968a86487c508b6493d49 Mon Sep 17 00:00:00 2001 From: moarshy Date: Sat, 22 Feb 2025 21:39:21 +0800 Subject: [PATCH 18/22] feat: Refine A100 deployment workflow with improved environment handling and deployment steps - Switch git fetch and reset to main branch - Add Python version and location checks - Implement conditional requirements.txt installation - Preserve Python environment during launch script execution - Enhance deployment script reliability and logging --- .github/workflows/deploy-a100.yml | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/.github/workflows/deploy-a100.yml b/.github/workflows/deploy-a100.yml index f3f919e..c988209 100644 --- a/.github/workflows/deploy-a100.yml +++ b/.github/workflows/deploy-a100.yml @@ -30,7 +30,7 @@ jobs: with: ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }} - - name: Deploy to A100 Instance + - name: Deploy to A100 Instance env: HOST: ${{ secrets.A100_HOST_2 }} DEPLOY_USER: ${{ secrets.A100_USER }} @@ -40,23 +40,41 @@ jobs: # Load environment and Python export PATH="/home/$USER/miniforge3/bin:$PATH" source ~/.bashrc + + # Explicitly activate conda environment source /home/$USER/miniforge3/bin/activate + # Check Python and pip + echo "Python version:" + python --version + echo "Python location:" + which python + echo "Pip location:" + which pip + # Navigate and setup deployment sudo chown -R $DEPLOY_USER:$DEPLOY_USER $DEPLOY_PATH cd $DEPLOY_PATH + # Git operations sudo git stash - git fetch origin feat/deploy-actions - git reset --hard origin/feat/deploy-actions + git fetch origin main + git reset --hard origin/main + # Install required Python packages if needed + if [ -f requirements.txt ]; then + pip install -r requirements.txt + fi + # Make scripts executable chmod +x ./docker-ctl.sh # Your deployment commands docker compose -f docker-compose.yml build --no-cache ./docker-ctl.sh down - sudo -E bash launch.sh + + # Run launch.sh with Python environment preserved + sudo -E PATH=$PATH bash launch.sh echo "Deployment completed at $(date)" EOF From 4df1126843528c2f94edc43e2131796c8e52d558 Mon Sep 17 00:00:00 2001 From: moarshy Date: Sat, 22 Feb 2025 21:43:04 +0800 Subject: [PATCH 19/22] feat: Update A100 deployment workflow to fetch from feat/deploy-actions branch --- .github/workflows/deploy-a100.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy-a100.yml b/.github/workflows/deploy-a100.yml index c988209..901d3bb 100644 --- a/.github/workflows/deploy-a100.yml +++ b/.github/workflows/deploy-a100.yml @@ -58,8 +58,8 @@ jobs: # Git operations sudo git stash - git fetch origin main - git reset --hard origin/main + git fetch origin feat/deploy-actions + git reset --hard origin/feat/deploy-actions # Install required Python packages if needed if [ -f requirements.txt ]; then From 978602663faba7b0bf3aed34699d7e04efa020f9 Mon Sep 17 00:00:00 2001 From: moarshy Date: Sun, 23 Feb 2025 19:04:35 +0800 Subject: [PATCH 20/22] feat: Add EC2 deployment workflow with multi-instance support - Create new GitHub Actions workflow for EC2 deployment - Implement matrix strategy to support multiple EC2 instances - Add dynamic host and SSH key selection based on instance number - Include deployment steps for fetching, resetting, and launching services - Enhance deployment status reporting with instance-specific messaging --- .github/workflows/deploy-a100.yml | 11 +++++++---- .github/workflows/{deploy.yml => deploy-ec2.yml} | 0 2 files changed, 7 insertions(+), 4 deletions(-) rename .github/workflows/{deploy.yml => deploy-ec2.yml} (100%) diff --git a/.github/workflows/deploy-a100.yml b/.github/workflows/deploy-a100.yml index 901d3bb..d7e19c3 100644 --- a/.github/workflows/deploy-a100.yml +++ b/.github/workflows/deploy-a100.yml @@ -14,6 +14,9 @@ jobs: deploy: if: github.event.pull_request.merged == true || github.event_name == 'push' runs-on: ubuntu-latest + strategy: + matrix: + instance: [1, 2] steps: - name: Checkout repository @@ -30,9 +33,9 @@ jobs: with: ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }} - - name: Deploy to A100 Instance + - name: Deploy to A100 Instance ${{ matrix.instance }} env: - HOST: ${{ secrets.A100_HOST_2 }} + HOST: ${{ matrix.instance == 1 && secrets.A100_HOST_1 || secrets.A100_HOST_2 }} DEPLOY_USER: ${{ secrets.A100_USER }} DEPLOY_PATH: ${{ secrets.A100_DEPLOY_PATH }} run: | @@ -82,7 +85,7 @@ jobs: if: always() run: | if [ "${{ job.status }}" == "success" ]; then - echo "✅ Deployment successful to A100 Instance" + echo "✅ Deployment successful to A100 Instance ${{ matrix.instance }}" else - echo "❌ Deployment failed for A100 Instance" + echo "❌ Deployment failed for A100 Instance ${{ matrix.instance }}" fi \ No newline at end of file diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy-ec2.yml similarity index 100% rename from .github/workflows/deploy.yml rename to .github/workflows/deploy-ec2.yml From f26f33b78bff690a03d1c1b393ebae15d77201ff Mon Sep 17 00:00:00 2001 From: moarshy Date: Sun, 23 Feb 2025 19:05:28 +0800 Subject: [PATCH 21/22] chore: Update A100 deployment workflow to target main branch --- .github/workflows/deploy-a100.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy-a100.yml b/.github/workflows/deploy-a100.yml index d7e19c3..8a6c18f 100644 --- a/.github/workflows/deploy-a100.yml +++ b/.github/workflows/deploy-a100.yml @@ -3,12 +3,12 @@ name: Deploy Application on: push: branches: - - feat/deploy-actions # TODO: Change to main later + - main pull_request: types: - closed branches: - - feat/deploy-actions # TODO: Change to main later + - main jobs: deploy: From 0d45a22b6154340fec024f9f6928bd44fbca17ac Mon Sep 17 00:00:00 2001 From: moarshy Date: Sun, 23 Feb 2025 19:13:42 +0800 Subject: [PATCH 22/22] docs: Comprehensive update to deployment documentation --- .github/deploy-readme.md | 247 ++++++++++++++++++++++++--------------- 1 file changed, 154 insertions(+), 93 deletions(-) diff --git a/.github/deploy-readme.md b/.github/deploy-readme.md index 5e7c62e..3f1e502 100644 --- a/.github/deploy-readme.md +++ b/.github/deploy-readme.md @@ -1,100 +1,161 @@ -# Application Deployment Workflow +# GitHub Actions Deployment Documentation -This repository contains a GitHub Actions workflow for automated deployment to an Amazon EC2 instance. The workflow is triggered either by pushing to the `main` or when a pull request to merged to main. - -## Workflow Overview - -The deployment workflow automates the following steps: -1. Checks out the repository -2. Sets up SSH access to the EC2 instance -3. Deploys the application to EC2 -4. Reports the deployment status +This repository contains deployment workflows for both EC2 and A100 instances. The deployment process is automated through GitHub Actions and triggers on pushes or merged pull requests to the main branch. ## Prerequisites -### Initial Server Setup -Before using this workflow, you must manually set up each EC2 instance: - -1. Launch Ubuntu EC2 instances -2. Set up the deployment environment on each instance: - - Clone the repository to the target deployment path - - Create and configure the `.env` file with required environment variables - - Install all necessary dependencies (Node.js, Python, etc.) - - Ensure `launch.sh` and `stop_service.sh` are executable (`chmod +x *.sh`) - - Test the application manually to verify the environment is properly configured - -### GitHub Configuration -After server setup, configure the following GitHub repository secrets: - -1. For single instance deployment: - - `EC2_SSH_KEY`: The private SSH key for connecting to the EC2 instance - - `EC2_HOST`: The hostname or IP address of your EC2 instance - - `DEPLOY_PATH`: The path on the EC2 instance where the application is deployed - -2. For dual instance deployment: - - `EC2_SSH_KEY`: The private SSH key (same key for both instances) - - `EC2_HOST_1`: The hostname/IP for the first EC2 instance - - `EC2_HOST_2`: The hostname/IP for the second EC2 instance - - `DEPLOY_PATH`: The deployment path (must be same on both instances) - -## Trigger Conditions - -The workflow triggers under two conditions: -- On push to the `main` branch -- When a pull request to the `main` branch is merged - -## Deployment Process - -The deployment process follows these steps: - -1. **Repository Checkout**: Fetches the latest code from the repository -2. **SSH Setup**: - - Creates SSH directory - - Installs the SSH private key - - Adds the EC2 host to known hosts -3. **Application Deployment**: - - Connects to EC2 via SSH - - Navigates to the deployment directory - - Stashes any local changes - - Fetches and resets to the latest code - - Attempts to reapply stashed changes - - Stops the existing service - - Launches the new version -4. **Status Reporting**: Reports whether the deployment was successful or failed - -## Required Files - -The workflow expects the following files to exist in your repository: -- `stop_service.sh`: Script to stop the currently running service -- `launch.sh`: Script to start the application - -## Usage - -No manual intervention is needed for deployment. The workflow will automatically run when: -- Code is pushed to the `main` branch -- A pull request to the `main` branch is merged - -## Monitoring - -You can monitor deployments in the GitHub Actions tab of your repository. Each deployment will show: -- Complete logs of the deployment process -- Final deployment status (✅ success or ❌ failure) - -## Note - -The workflow is configured to deploy from the `main` branch. All deployments will happen either through direct pushes to `main` or when pull requests are merged into `main`. - -## Troubleshooting - -If deployment fails, check: -1. EC2 instance is running and accessible -2. SSH key is correctly configured in GitHub secrets -3. All required scripts (`stop_service.sh` and `launch.sh`) exist and are executable -4. Deployment path exists on the EC2 instance -5. GitHub Actions logs for specific error messages +### Deployment Path +All instances must use the standardized deployment path: +``` +/home/ubuntu/naptha/naptha-node +``` + +### Server Requirements +- Ubuntu OS (recommended: Ubuntu 22.04 LTS) +- Docker and Docker Compose installed +- For A100 instances: Python with Miniforge environment +- Proper permissions set up for deployment path + +## Initial Server Setup + +### Create deployment directory: +```bash +mkdir -p /home/ubuntu/naptha/naptha-node +chown -R ubuntu:ubuntu /home/ubuntu/naptha +``` + +### Install dependencies: +```bash +# Docker and Docker Compose +sudo apt update +sudo apt install docker.io docker-compose +``` + +## SSH Authentication Setup + +### For EC2 Instances (.pem method) +- Use your existing EC2 .pem key +- Add the content to GitHub Secrets as `EC2_SSH_KEY` + +### For A100 Instances (SSH key method) + +1. Generate deployment SSH key pair: +```bash +ssh-keygen -t ed25519 -C "github-actions-deploy" +# Save as 'github-actions-deploy' +``` + +2. Add public key to authorized_keys on each A100 instance: +```bash +cat github-actions-deploy.pub >> ~/.ssh/authorized_keys +chmod 600 ~/.ssh/authorized_keys +``` + +## GitHub Secrets Configuration + +### Required Secrets for EC2 +- `EC2_SSH_KEY`: The .pem file content +- `EC2_HOST_1`: First EC2 instance hostname/IP +- `EC2_HOST_2`: Second EC2 instance hostname/IP +- `DEPLOY_PATH`: `/home/ubuntu/naptha/naptha-node` + +### Required Secrets for A100 +- `SSH_PRIVATE_KEY`: Content of github-actions-deploy private key +- `SSH_KNOWN_HOSTS`: Content of generated known_hosts entries +- `A100_HOST_1`: First A100 instance hostname/IP +- `A100_HOST_2`: Second A100 instance hostname/IP +- `A100_USER`: SSH username for A100 instances +- `A100_DEPLOY_PATH`: `/home/ubuntu/naptha/naptha-node` + +## Repository Requirements + +### Required Files +- `docker-compose.yml`: Docker services configuration +- `docker-ctl.sh`: Docker service management script +- `launch.sh`: Main deployment script + +### File Permissions +```bash +chmod +x docker-ctl.sh launch.sh +``` + +## Workflow Operation + +### Trigger Conditions +- Push to main branch +- Merged pull request to main branch + +### Deployment Process + +#### EC2 Deployment +- SSH connection using .pem key +- Code checkout and deployment +- Service restart + +#### A100 Deployment +- SSH setup with generated keys +- Python environment activation +- Docker-based deployment: + - Build containers + - Service management + - Launch application + +## Monitoring and Troubleshooting + +### Deployment Status +- Monitor in GitHub Actions tab +- Each instance shows separate status +- Success/failure indicators for each step + +### Common Issues and Solutions + +#### SSH Connection Failed +```bash +# Check SSH connection manually +ssh -i your-key.pem ubuntu@EC2_HOST +# or +ssh -i github-actions-deploy A100_USER@A100_HOST +``` + +#### Python Not Found (A100) +```bash +# Verify Python installation +which python +python --version +``` + +#### Docker Issues +```bash +# Check Docker status +sudo systemctl status docker +# Check Docker Compose +docker-compose --version +``` + +### Logging +- GitHub Actions provides detailed logs +- Instance-specific logs in `/var/log` +- Docker logs via `docker-ctl.sh logs` ## Security Considerations -- The SSH key is stored securely in GitHub secrets -- SSH key permissions are set to 600 (read/write for owner only) -- Host key verification is enabled for the EC2 instance +### SSH Key Management +- Keys stored as GitHub Secrets +- Proper file permissions (600) +- Regular key rotation recommended + +### Access Control +- Minimal required permissions +- Separate keys for different environments +- No sensitive data in repository + +## Additional Notes + +### Deployment Path Structure +``` +/home/ubuntu/naptha/naptha-node/ +├── docker-compose.yml +├── docker-ctl.sh +├── launch.sh +└── [other application files] +```