bucketpilot/Docs

Setting up a Windows server

OpenSSH isn't installed by default, an administrator's key doesn't go in their own .ssh folder, and Windows accepts filenames it then stores somewhere else.

Turn OpenSSH Server on first

This is the step that catches almost everyone, because nothing about the symptom points at it: OpenSSH Server is an optional feature on Windows. A perfectly healthy machine that has never had it installed looks exactly like one that's switched off — the connection simply gets no answer.

In PowerShell as Administrator, on the Windows machine:

powershell
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
Start-Service sshd
Set-Service sshd -StartupType Automatic
New-NetFirewallRule -Name sshd -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22

Then check it's listening — Get-Service sshd should say Running.

If a connection test times out, this is the first thing to rule out. If it says the port refused the connection, the machine is reachable and it's the service that's missing or stopped — same fix.

Where the key actually goes

⚠️ An administrator's key does not go in that account's .ssh folder. OpenSSH on Windows reads one shared file for every account in the Administrators group, and silently ignores C:\Users\<name>\.ssh\authorized_keys for them. A key in the wrong file produces no error anywhere — it just never authenticates, which is indistinguishable from a wrong key.

For an administrator account the key belongs in C:\ProgramData\ssh\administrators_authorized_keys, and that file's permissions must grant only Administrators and SYSTEM:

powershell
$f = "C:\ProgramData\ssh\administrators_authorized_keys"
Add-Content $f (Get-Content "$env:USERPROFILE\.ssh\id_ed25519.pub") -Encoding ascii
icacls $f /inheritance:r /grant "Administrators:F" /grant "SYSTEM:F"

Run that as written — it copies the key out of your .pub file, so there's nothing to paste and nothing to edit. Then confirm with Get-Content $f: you should see a line beginning ssh-ed25519 AAAAC3… and ending with your comment.

Two ways this goes wrong, both of which look like a rejected key:

  • •The file holds a placeholder instead of your key. If Get-Content $f shows AAAA..., something copied an example rather than the real thing. Delete that line and re-run the command above.
  • •The file is UTF-16. Written with > or Out-File instead of the -Encoding ascii above, Windows PowerShell saves it in a form sshd can't read, and not one key in it works.

For a standard (non-administrator) account the ordinary path is right: C:\Users\<name>\.ssh\authorized_keys.

Or use a password. On Windows that's often genuinely simpler — no shared file and no ACL to get right. Passwords are encrypted at rest and never returned by any API. The username is the account name for a local account (Administrator), or DOMAIN\user / [email protected] for a domain account.

Names it won't store, and names it stores somewhere else

A key in a bucket can be almost any text. A Windows filename can't — and the interesting part isn't what Windows refuses, it's what Windows accepts and then does something else with. BucketPilot checks every name before writing it, per file, and keeps the rest of the run going.

Accepted, and worse for it:

  • •A colon. report:final.txt is accepted, and the colon opens an NTFS alternate data stream — the bytes end up hidden inside a file called report, and a naive copy reports success for something that exists nowhere you'll look. Refused before writing, with the reason.
  • •Capitalisation. Report.pdf and report.pdf are two objects in a bucket and one file on Windows. Copying both would silently overwrite one and report two successes. The second is refused, and it names the first.
  • •Reserved device names. aux.txt, con.txt, nul, com1 and friends are accepted on current Windows and refused by older versions and plenty of applications. Reported as a warning, not an error — refusing what your server accepts would be us overruling your machine.

Refused, but with a misleading message if you ask Windows directly: the characters " * < > ? |, names ending in a dot or a space (Windows strips both, so the file would arrive under a different name), and paths over the length limit. Windows reports all of these as "No such file", which reads as the source having gone missing.

Path length. The limit is 260 characters unless long paths have been deliberately enabled. Note that a job allows 246, not 260: it writes to a temporary name and renames it into place, so a failure can never leave a half-written file — and that temporary name is 14 characters longer. A name the file browser accepts and a job refuses is that difference, not an inconsistency.

Check before you run. On a migration into a Windows server, Check names on the job page lists everything that wouldn't arrive as itself — unwritable names, case collisions and reserved names — before the run starts, while there's still time to rename them at the source.

Drives, indexing and re-scans

A drive opened on a Windows server browses like any other. Two differences are worth knowing before you set one up.

Don't root a drive at a whole drive. C:\ isn't a folder — it's Windows itself, every installed program, and every other user's files. BucketPilot will browse it, but it won't index it, so there's no search, no file-type or size breakdown, and no size alerts on it. The switch is shown and disabled, with the reason next to it. Root the drive at the folder you actually care about — /C:/inetpub/wwwroot, /D:/shares — and index that. The same applies to /, which on Windows means every drive at once. More on this

Re-scans only look at what changed. A Windows drive is walked by a single PowerShell process on the server rather than by thousands of round trips, and a re-run asks only for files written or created since the last scan — so a re-scan of a large, mostly-unchanged drive finishes in seconds. A full walk still runs periodically, because only a full pass can notice that something was deleted.

The first scan of a drive is always a full one, and hourly auto-sync is safe on Windows for the same reason it is on Linux.

© 2026 BucketPilot