Last updated: February 5, 2025

<span aria-hidden="true" id="exporting-files-to-sftp-servers-via-web-browsers"></span>

# Exporting files to SFTP servers via web browsers

![Tim Koschützki](/assets/images/teammates/avatar-tim-kos-1.jpg?dpl=dpl_B2d4XACVUtA1h8m6kRxZhWsda77Q)

#### Tim Koschützki

Co-founder · Berlin, Germany · Show bio

[](https://x.com/tim%5Fkos)[](https://github.com/tim-kos)

Exporting files to SFTP servers directly from web browsers can be challenging because browsers do not natively support the SFTP protocol. In this DevTip, we explain a practical approach that bridges this gap by using JavaScript on the front end and Node.js on the back end to securely upload files to an SFTP server.

<span aria-hidden="true" id="introduction"></span>

## Introduction

Transferring files securely from web applications to remote servers via SFTP is a common requirement but not one that can be handled directly within a web browser. This guide provides a step-by-step process to implement SFTP file exports in your web application, addressing both front-end and back-end considerations.

<span aria-hidden="true" id="understanding-the-challenge"></span>

## Understanding the challenge

Web browsers are limited by security restrictions and the inherent nature of the SFTP protocol, which prevents direct communication with SFTP servers. By setting up a back-end service that manages the SFTP communication while the front end collects and sends the file data, we overcome these limitations effectively.

<span aria-hidden="true" id="setting-up-the-frontend"></span>

## Setting up the frontend

Begin by creating a simple HTML page that enables users to select files for export:

```html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>SFTP File Export</title>
  </head>
  <body>
    <input type="file" id="fileInput" accept=".pdf,.jpg,.png,.doc,.docx" />
    <button id="uploadButton">Export to SFTP</button>

    <script>
      const fileInput = document.getElementById('fileInput')
      const uploadButton = document.getElementById('uploadButton')
      const MAX_FILE_SIZE = 5 * 1024 * 1024 // 5MB

      uploadButton.addEventListener('click', async () => {
        const file = fileInput.files[0]
        if (!file) {
          alert('Please select a file.')
          return
        }

        if (file.size > MAX_FILE_SIZE) {
          alert('File size exceeds 5MB limit.')
          return
        }

        const formData = new FormData()
        formData.append('file', file)

        try {
          const response = await fetch('/upload', {
            method: 'POST',
            body: formData,
          })

          if (!response.ok) {
            throw new Error(`HTTP error! status: ${response.status}`)
          }

          const data = await response.json()
          alert('File exported successfully.')
        } catch (error) {
          console.error('Error:', error)
          alert('File export failed: ' + error.message)
        }
      })
    </script>
  </body>
</html>

```

<span aria-hidden="true" id="building-the-backend-api-with-nodejs"></span>

## Building the backend API with Node.js

We use Node.js for the back end due to its strong support for asynchronous operations and its rich ecosystem of packages for handling HTTP and SFTP protocols. The following steps demonstrate how to create a simple Express server that manages file uploads and performs SFTP transfers.

First, initialize a new Node.js project:

```bash
mkdir sftp-upload
cd sftp-upload
npm init -y

```

Install the required dependencies:

```bash
npm install express@4.18.x multer@1.4.5-lts.1 ssh2-sftp-client@11.0.0 dotenv@16.x express-rate-limit@7.x

```

Create an `index.js` file:

```javascript
require('dotenv').config()
const express = require('express')
const multer = require('multer')
const SftpClient = require('ssh2-sftp-client')
const path = require('path')
const fs = require('fs')
const rateLimit = require('express-rate-limit')

const app = express()

// Create uploads directory if it doesn't exist
if (!fs.existsSync('uploads')) {
  fs.mkdirSync('uploads')
}

// Configure rate limiting for the upload endpoint
const limiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 100, // limit each IP to 100 requests per windowMs
})

app.use('/upload', limiter)

// Configure multer with disk storage
const storage = multer.diskStorage({
  destination: 'uploads/',
  filename: function (req, file, cb) {
    cb(null, file.fieldname + '-' + Date.now() + path.extname(file.originalname))
  },
})

// Add file filter for security
const fileFilter = (req, file, cb) => {
  const allowedTypes = [
    'application/pdf',
    'image/jpeg',
    'image/png',
    'application/msword',
    'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
  ]
  if (allowedTypes.includes(file.mimetype)) {
    cb(null, true)
  } else {
    cb(new Error('Invalid file type'), false)
  }
}

const upload = multer({
  storage: storage,
  fileFilter: fileFilter,
  limits: {
    fileSize: 5 * 1024 * 1024, // 5MB limit
  },
})

app.post('/upload', upload.single('file'), async (req, res) => {
  if (!req.file) {
    return res.status(400).json({ error: 'No file uploaded' })
  }

  const sftp = new SftpClient()
  try {
    if (!process.env.SFTP_HOST || !process.env.SFTP_USERNAME) {
      throw new Error('Missing SFTP configuration')
    }

    await sftp.connect({
      host: process.env.SFTP_HOST,
      port: parseInt(process.env.SFTP_PORT || '22', 10),
      username: process.env.SFTP_USERNAME,
      password: process.env.SFTP_PASSWORD,
      readyTimeout: 10000,
      retries: 3,
    })

    const remotePath = `/remote/path/${req.file.filename}`
    await sftp.put(req.file.path, remotePath)

    // Clean up uploaded file
    fs.unlinkSync(req.file.path)

    res.json({ message: 'File exported successfully' })
  } catch (err) {
    console.error(err)
    res.status(500).json({ error: 'File export failed: ' + err.message })

    // Clean up uploaded file on error
    if (req.file && fs.existsSync(req.file.path)) {
      fs.unlinkSync(req.file.path)
    }
  } finally {
    sftp.end()
  }
})

const port = process.env.PORT || 3000
app.listen(port, () => {
  console.log(`Server started on http://localhost:${port}`)
})

```

Create a `.env` file in the root of your project to store your SFTP credentials securely:

```bash
SFTP_HOST=your-sftp-host.com
SFTP_PORT=22
SFTP_USERNAME=your-username
SFTP_PASSWORD=your-password  # Consider using key-based authentication for enhanced security
PORT=3000

```

###### Note

Never commit your `.env` file to version control. Add it to your `.gitignore` file.

<span aria-hidden="true" id="security-considerations"></span>

## Security considerations

A robust file transfer implementation requires strong security practices. Consider the following measures:

* **File Validation:** Rigorously check file types, enforce file size limits, and validate file names to prevent malicious uploads.
* **Rate Limiting:** Use tools such as `express-rate-limit` to restrict the number of requests, protecting your server from abuse.
* **SFTP Security:**
  * Use connection timeouts.
  * Prefer key-based authentication over passwords when possible.
  * Ensure that your SFTP server utilizes strong encryption.
* **Error Handling and Cleanup:** Implement comprehensive error handling, including cleanup of temporary files and secure logging of errors.
* **Environment Variables:** Store sensitive credentials in environment variables rather than hard-coding them.
* **HTTPS:** Serve your application over HTTPS to encrypt data in transit.

<span aria-hidden="true" id="testing-the-file-export-functionality"></span>

## Testing the file export functionality

Start the Node.js server:

```bash
node index.js

```

Then, open the HTML file in your browser, select a file to export, and click the "Export to SFTP" button. If configured correctly, the file will be securely transferred to your SFTP server.

<span aria-hidden="true" id="conclusion"></span>

## Conclusion

This guide demonstrates a secure and effective solution for exporting files to SFTP servers from web applications using JavaScript and Node.js. By addressing file validation, rate limiting, secure SFTP practices, and error handling, you can build a robust file export system.

For a more comprehensive solution that includes file processing and transformation, consider using[Transloadit](/index.md) with its [SFTP export Robot](/docs/robots/sftp-store.md).

\#sftp#file-upload#web-browser#nodejs#file-exporting-service

### 👩‍💻 Join 20k+ developers

Sign up for our [monthly newsletter](/newsletters.md) to receive direct links to 3 exclusive tech — and 2 product updates. No less, no more.

Your email:

Get access

## File uploading and encoding. Made simple.

Transloadit streamlines file handling for developers, trusted by brands like Coursera and The New York Times. We’re known for a reliable API, top-notch support, and a strong commitment to open source, with projects like [Uppy⁠](https://uppy.io) and [Tus⁠](https://tus.io) setting standards in file processing.

[Sign up](/c/)[Book a Demo](https://survey.typeform.com/to/kRg47Xi5)

No credit card needed · 5 GB included in the free plan

Cancel anytime
