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.
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. Create the Remote Restart 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 a script (e.g., RestartLinuxService.ps1) in your project:
# 1. Stop the service remotely
ssh user@linux-server "sudo systemctl stop myapp.service"
# 2. (Optional) Sync files if not already done by a tool like WinSCP
# scp -r C:\Path\To\Publish\* user@linux-server:/var/www/myapp/
# 3. Restart the service
ssh user@linux-server "sudo systemctl restart myapp.service"
3. 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)
4. 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.
5. Update Your RestartLinuxService.ps1 Script
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>
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 stop api.service"
# ... same for restart
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.