Visual Studio - Publish to Linux and Restart Service
To stop and restart a Linux service automatically when publishing from Visual Studio to a local folder, you must modify your Publish Profile (.pubxml) to include post-publish commands. Since Visual Studio runs on Windows, these commands typically trigger a script (like PowerShell or a WinSCP script) to remotely execute the systemctl commands on the Linux server.
NOTE: In the exercise our service is called api.service
1. Update the Publish Profile
Visual Studio doesn't have a built-in "Post-publish" box in the UI for folder publishing, so you must edit the .pubxml file manually.
- In Solution Explorer, expand
Properties>PublishProfiles. - Open your
.pubxmlfile (e.g.,FolderProfile.pubxml). - Add a custom
Targetat the end of the file, before the closing</Project>tag:
<Target Name="CustomActionsAfterPublish" AfterTargets="AfterPublish">
<Exec Command="powershell -ExecutionPolicy Bypass -File "$(ProjectDir)Scripts\RestartLinuxService.ps1"" />
</Target>
2. Generate SSH Key on Your Windows Machine (once)
Open PowerShell as your normal user and run:
ssh-keygen -t ed25519 -C "visualstudio-publish-key"
# Press Enter for default location (~/.ssh/id_ed25519)
# Leave passphrase empty (for fully automated) or set one (then use ssh-agent)
3. Copy the Public Key to Your Linux Server (as root or your user)
# Replace with your actual server
type $HOME\.ssh\id_ed25519.pub | ssh root@linux-server "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys && chmod 700 ~/.ssh"
Enter the root password one time during this setup.
4. Create Your RestartLinuxService.ps1 Script
Since your publish target is a folder, you likely still need to move the files to Linux and then restart the service. You can use PowerShell with SSH to handle this.
Create or replace the script with this clean version (no password needed):
# RestartLinuxService.ps1
# Run after Visual Studio publish to stop/restart the systemd service
$server = "linux-server"
$user = "root" # or a sudo-enabled user
Write-Host "Stopping api.service on $server..." -ForegroundColor Yellow
ssh -o StrictHostKeyChecking=no -o BatchMode=yes "${user}@${server}" "sudo systemctl stop api.service"
# Optional: If you also want to sync files here (instead of relying only on VS publish folder profile)
# Write-Host "Syncing files..."
# scp -r -o StrictHostKeyChecking=no "C:\Path\To\Your\Publish\Output\*" "${user}@${server}:/path/to/your/app/"
Write-Host "Restarting api.service on $server..." -ForegroundColor Green
ssh -o StrictHostKeyChecking=no -o BatchMode=yes "${user}@${server}" "sudo systemctl restart api.service"
# Verify status (optional)
ssh -o StrictHostKeyChecking=no -o BatchMode=yes "${user}@${server}" "sudo systemctl status api.service --no-pager -l"
Notes:
- -o BatchMode=yes fails fast if something is wrong (no interactive prompts).
- -o StrictHostKeyChecking=no skips the host key prompt on first run (you can remove it after the first successful connection).
- Make sure the Linux user (root or a dedicated deploy user) can run sudo systemctl without a password. On the Linux server, edit sudoers:
sudo visudo
Add a line like:
deployuser ALL=(ALL) NOPASSWD: /usr/bin/systemctl stop api.service, /usr/bin/systemctl restart api.service, /usr/bin/systemctl status api.service
Your existing .pubxml target stays exactly the same as in step 1
<Target Name="CustomActionsAfterPublish" AfterTargets="AfterPublish">
<Exec Command="powershell -ExecutionPolicy Bypass -File "$(ProjectDir)Scripts\RestartLinuxService.ps1"" />
</Target>
6. Alternative: If You Must Use Password (Not Recommended)
If key auth is blocked (e.g., company policy), you can use sshpass (install via Chocolatey: choco install sshpass) or a simple PowerShell wrapper.
Using sshpass (install once):
# In RestartLinuxService.ps1
$password = "YourSuperSecretPassword" # <-- WARNING: Plain text! Very insecure
$server = "linux-server"
$user = "root"
sshpass -p $password ssh -o StrictHostKeyChecking=no "${user}@${server}" "sudo systemctl restart api.service"
Even worse for security: store the password encrypted with ConvertFrom-SecureString and load it at runtime, but it's still risky for automated builds.
Bonus Tips
- Run as non-root — Create a dedicated deploy user on Linux with limited sudo rights.
- File sync — The publish profile in Visual Studio can already target a network share or use Web Deploy / Folder publish with rsync/scp in the profile. Then your script only needs to handle stop → restart.
- Error handling — Add try/catch and check $LASTEXITCODE after each ssh call.
- Test first — Run the .ps1 manually from PowerShell before relying on the publish step.