Steps for CI CD
Step 1: Generate an SSH key pair for GitHub Actions to access your Linux server
On your local machine (or any secure environment), run:
ssh-keygen -t rsa -b 4096 -C "github-deploy-key"
When prompted:
- File to save the key: Press Enter to accept default (
~/.ssh/id_rsa) - Passphrase: Leave empty (or set one if you prefer extra security)
This will generate:
~/.ssh/id_rsa→ Private key (you’ll add this to GitHub Secrets)~/.ssh/id_rsa.pub→ Public key (you’ll add this to your Linux server)
Result:
montcalm@montcalm:~$ ssh-keygen -t rsa -b 4096 -C "github-deploy-key"
Generating public/private rsa key pair.
Enter file in which to save the key (/home/montcalm/.ssh/id_rsa): cicd
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in cicd
Your public key has been saved in cicd.pub
The key fingerprint is:
SHA256:nwnZwEUe6KVejIYDQ+Mw0EXQeGZehha7JsxLPF5AuAQ github-deploy-key
The key's randomart image is:
+---[RSA 4096]----+
|E+=B*o o+ |
|.oo+Xoo..o.. |
|...*o= oo=. |
|.+ ...o =+o |
| B + +S.. |
| o * .o o |
| o + |
| |
| |
+----[SHA256]-----+
montcalm@montcalm:~/.ssh$ find ~ -name "cicd.pub"
/home/montcalm/cicd.pub
Step 2 Add the public key to your Linux server’s authorized_keys
This allows GitHub Actions to SSH into your server using the key you just created.
✅ Run this command to append the public key:
cat ~/cicd.pub >> ~/.ssh/authorized_keys
🔸 This assumes you're logged in as the user who will receive the SSH connection (e.g., montcalm).
🔒 Set correct permissions:
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
Once done, confirm that the public key is added and permissions are set. Then we’ll move to Step 3: Add the private key to GitHub Secrets.
Check if your public key is in authorized_keys
Run this command:
cat ~/.ssh/authorized_keys
Look for a line that starts with ssh-rsa and ends with github-deploy-key. It should match the contents of your cicd.pub file. To double-check, you can also run:
grep "github-deploy-key" ~/.ssh/authorized_keys
If it returns a line, your key is in there.
montcalm@montcalm:~$ cat ~/.ssh/authorized_keys
ssh-rsa <- removed-->D8VPI5YonMIXPJd3oZz3Bj8pd7fXSeJ+ZWTOdxb0M9VjPzLSWUQ== github-deploy-key
montcalm@montcalm:~$ grep "github-deploy-key" ~/.ssh/authorized_keys
ssh-rsa <- removed--> onMIXPJd3oZz3Bj8pd7fXSeJ+ZWTOdxb0M9VjPzLSWUQ== github-deploy-key
🧪 Step 3: Add the private key to GitHub Secrets
This allows GitHub Actions to authenticate with your server during deployment.
✅ Steps:
- Open your GitHub repository in a browser.
- Go to Settings → Secrets and variables → Actions.
- Click New repository secret.
Set:
- Name: SSH_PRIVATE_KEY
- Value: Paste the contents of your private key file (cicd)
🔍 To get the private key content, run: cat ~/cicd
⚠️ Important: Do not include any extra spaces or line breaks. The key should start with:
-----BEGIN RSA PRIVATE KEY-----
and end with:
-----END RSA PRIVATE KEY-----

Let me know once it’s added, and we’ll move to Step 4: Add server IP and username to GitHub Secrets.
Step 4: Add server IP and username to GitHub Secrets
This lets GitHub Actions know where and how to connect to your server.
✅ Add two more secrets:
- Go to your GitHub repo → Settings → Secrets and variables → Actions
- Click New repository secret twice to add:
| Secret Name | Value | | SERVER_IP | Your server’s public IP address | | SERVER_USER | The SSH username (e.g. ubuntu, root, or your custom user) |
🔐 These values are used by the GitHub Actions workflow to establish the SSH connection.
Repository Secrets vs Environment Secrets
✅ For our case: Use Repository Secrets
Since we’re setting up deployment for the whole repository (not tied to a specific environment like staging or production), you should add the secrets under:
Settings → Secrets and variables → Actions → Repository secrets
🧪 When to use Environment Secrets?
Use Environment Secrets only if:
- You have multiple environments (e.g. staging, production)
- You want to restrict access or add approval workflows per environment
So for now, stick with Repository Secrets. Once you’ve added SSH_PRIVATE_KEY, SERVER_IP, and SERVER_USER, we’re ready to move to Step 5: Create the GitHub Actions workflow file.
.
🛠️ Step 5: Create the GitHub Actions Workflow File (Windows Server)
Here’s a basic example that:
- Runs on every push to the main branch
- Connects to your Windows Server via SSH
- Runs PowerShell commands remotely
📄 .github/workflows/deploy.yml
name: Deploy to Windows Server
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up SSH key
run: |
mkdir -p ~/.ssh
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
- name: Add server to known_hosts
run: |
ssh-keyscan -H ${{ secrets.SERVER_IP }} >> ~/.ssh/known_hosts
- name: Deploy via SSH
run: |
ssh ${{ secrets.SERVER_USER }}@${{ secrets.SERVER_IP }} powershell -Command "
cd 'C:\\path\\to\\your\\app';
git pull;
./build.ps1;
Restart-Service -Name 'W3SVC';
"
🧩 What You Need to Customize
- C:\path\to\your\app: Replace with the actual path to your app on the Windows Server
- git pull: You can replace this with any PowerShell command — like restarting a service, copying files, etc.
🧩 Customize These Parts
| Section | What to Replace With |
|---|---|
| C:\path\to\your\app | Your actual app directory on the Windows Server |
| ./build.ps1 | Your PowerShell build or deployment script |
| Restart-Service -Name 'W3SVC' | Restart IIS (W3SVC = World Wide Web Publishing Service) |
You can also restart other services like SQL Server, custom apps, or use Start-Process to launch executables.
🛠️ Step 6: Create build.ps1 for Windows Deployment This PowerShell script will:
- Restore dependencies
- Build the project
- Publish the output
- Copy the published files to your deployment folder
📄 build.ps1
# Set paths
$projectPath = "C:\path\to\your\app"
$publishPath = "C:\path\to\your\app\publish"
$deployPath = "C:\inetpub\wwwroot\YourApp"
# Restore, build, and publish
Write-Host "Restoring packages..."
dotnet restore $projectPath
Write-Host "Building project..."
dotnet build $projectPath --configuration Release
Write-Host "Publishing project..."
dotnet publish $projectPath -c Release -o $publishPath
# Stop IIS (optional)
Write-Host "Stopping IIS..."
Stop-Service -Name 'W3SVC'
# Deploy
Write-Host "Deploying files..."
Remove-Item -Recurse -Force $deployPath\*
Copy-Item -Recurse -Force $publishPath\* $deployPath
# Start IIS
Write-Host "Starting IIS..."
Start-Service -Name 'W3SVC'
Write-Host "Deployment complete!"
🔧 Customize These Paths
| Variable | Replace with... |
|---|---|
| $projectPath | Path to your Blazor project .csproj |
| $publishPath | Temporary folder for published output |
| $deployPath | IIS root folder (e.g. wwwroot) |
🚀 Step 7: Trigger Remote Deployment from GitHub Actions
Now that you have a build.ps1 script on your Windows Server, we’ll configure GitHub Actions to:
- Build and publish your Blazor app locally (on GitHub runner)
- Use WinRM or PowerShell Remoting to run build.ps1 on your Windows Server
🔐 Prerequisites
Make sure your Windows Server is ready:
- ✅ WinRM enabled and accessible from GitHub Actions
- ✅ A user account with permission to deploy
- ✅ build.ps1 script placed on the server (e.g. C:\scripts\build.ps1)
🧪 Sample GitHub Actions Workflow (.github/workflows/deploy.yml)
name: Deploy Blazor App
on:
push:
branches:
- main
jobs:
deploy:
runs-on: windows-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Run remote PowerShell script
uses: jakejarvis/winrm-action@v1
with:
url: http://your-server-ip:5985/wsman
username: 'YourUsername'
password: ${{ secrets.WINRM_PASSWORD }}
command: 'powershell -ExecutionPolicy Bypass -File C:\scripts\build.ps1'
🛡️ Security Tips
- Store your password in GitHub Secrets as WINRM_PASSWORD
- Use HTTPS for WinRM if possible (https://your-server-ip:5986/wsman)
- Restrict access to the server by IP or firewall rules
🧠 What Is WinRM?
Windows Remote Management (WinRM) is Microsoft’s implementation of the WS-Management protocol, which allows administrators to remotely manage Windows machines using PowerShell and other tools.
🔍 Key Features
- Remote PowerShell execution: Run scripts and commands on another Windows machine without logging in via Remote Desktop.
- Secure communication: Uses HTTP (port 5985) or HTTPS (port 5986) to send management data.
- Built-in to Windows: Available by default on most Windows versions since Server 2008 and Windows 7.
🛠️ What Is It Used For?
- 🔧 Software deployment
- 📊 Performance monitoring
- 🛡️ System configuration and troubleshooting
- 📁 File and service management across servers
Unlike RDP, which gives you a full desktop view, WinRM is command-line based and ideal for automation and scripting.