Skip to main content

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.

  1. In Solution Explorer, expand Properties > PublishProfiles.
  2. Open your .pubxml file (e.g., FolderProfile.pubxml).
  3. Add a custom Target at the end of the file, before the closing </Project> tag:
<Target Name="CustomActionsAfterPublish" AfterTargets="AfterPublish">
  <Exec Command="powershell -ExecutionPolicy Bypass -File &quot;$(ProjectDir)Scripts\RestartLinuxService.ps1&quot;" />
</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 &quot;$(ProjectDir)Scripts\RestartLinuxService.ps1&quot;" />
</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.