Uploading a website is the single most common reason anyone still touches FTP. It is also where the most avoidable mistakes happen — files in the wrong directory, a broken site visible to the world for ten minutes, or a .env full of database credentials sitting in a public folder.
Find the web root first
Connecting drops you in your account’s home directory, which is usually not what the web server serves. Look for one of these:
| Directory | Typical host |
|---|---|
public_html | cPanel, most shared hosting |
httpdocs | Plesk |
www | Some VPS setups, older panels |
/var/www/html | Default Apache/nginx on a self-managed server |
htdocs | XAMPP, some legacy hosts |
The test is simple: the folder containing the index.html or index.php your visitors already see is the web root. Upload a file called test.txt and try https://yourdomain.com/test.txt. If it loads, you found it. Delete it afterwards.
Save that path in your site settings so every session opens there. In Upstream this is the remote path field on the site.
What to upload — and what never to
Upload the built output, not your working directory. For a static site generator or a bundler that means the contents of dist/, build/, _site or public, not the project root.
Things that should never reach a public server:
.git/— the entire history of your project, including any credential ever committed.https://yourdomain.com/.git/configis one of the first paths automated scanners try.node_modules/— thousands of files, none of them needed at runtime for a static site, and it will make your upload take twenty times longer..envand config files with real credentials..DS_Store— harmless but it leaks your folder structure, and it is everywhere on a Mac.- Source maps for production, if you would rather not publish readable source.
A .syncignore file handles this permanently rather than requiring vigilance:
.git/
node_modules/
.DS_Store
.env
*.map
Upstream applies exclusions on both sides, so an excluded file is neither uploaded nor pulled back down.
Do not upload straight over a live site
Copying 400 files over a running site means that for the duration, visitors see a mix of old and new — a new HTML file referencing a CSS bundle that has not arrived yet. On a slow connection that window is minutes long.
Two ways to avoid it:
Upload to a staging folder, then swap. Put the new build in public_html_new, verify it, then rename the directories. The switch is one rename, effectively instant.
Upload assets first, HTML last. Static assets are usually content-hashed and additive, so they can arrive early without breaking anything. Upload CSS, JS and images, then the HTML that references them. The old pages keep working until the moment they are replaced.
Permissions, briefly
The rule that covers almost every case:
- Directories: 755 — owner can write, everyone can enter and read.
- Files: 644 — owner can write, everyone can read.
- Scripts that must execute: 755.
- Never 777. It means anyone on the server can modify the file. It is the traditional “fix” for permission errors and it is how a shared host turns into someone else’s malware host.
Config files with secrets are better at 600 where the setup allows it.
Note that permissions are a POSIX concept: they apply to FTP, FTPS and SFTP on a Unix server, but a Windows-hosted FTP server may ignore them entirely.
Verify before you walk away
Load the site in a private window — not your normal browser, which is full of cached assets that will hide a missing file. Check a page you changed, a page you did not, and one asset that should have been replaced. Then look at the dates in the remote pane: a file with yesterday’s timestamp did not upload.
Step by step
- Build your site locally and confirm the output folder is the one you mean to publish.
- Connect over SFTP if your host offers SSH, otherwise FTPS. Save the site so the remote path opens at your web root.
- Add a
.syncignoreexcluding.git/,node_modules/,.DS_Storeand any file holding credentials. - Upload assets first, HTML last — or upload to a staging folder and rename it into place.
- Check permissions: 755 for directories, 644 for files, never 777.
- Verify in a private browser window, and check the timestamps in the remote pane for anything that did not transfer.
Questions people ask
Where do I upload my website files?
Into the web root — public_html on cPanel hosts, httpdocs on Plesk, /var/www/html on a typical self-managed server. The folder containing the index file your visitors already see is the right one.
Why does my site show “Index of /” instead of my page?
There is no index file in that directory, so the server is listing its contents. Either the file is named something else, it landed one directory too deep, or it is Index.html on a case-sensitive server that expects index.html.
Do I need to upload node_modules?
No. For a static site nothing in it is needed at runtime. For a Node application, dependencies are installed on the server with npm install rather than uploaded.
Why did my CSS not update?
Either the file did not transfer — check its timestamp on the server — or your browser is serving a cached copy. Test in a private window before assuming the upload failed.
What file permissions should I use?
755 for directories, 644 for files, 755 for scripts that need to execute. Avoid 777 entirely; it lets any user on the server write to your file.
Is it safe to upload over a live website?
It works, but visitors during the upload can see an inconsistent mix of old and new files. Uploading to a staging directory and renaming it into place avoids the window entirely.