How to Expose SFTP Server Files via Web Interface with Secure Authentication


2 views

When building a secure file distribution system, we need to satisfy several technical requirements simultaneously:

  • End-to-end encryption for all file transfers
  • Support for multiple access protocols (SFTP/Web/CURL)
  • User authentication for both automated and manual access
  • Linux-based server implementation

Here are three proven approaches to expose SFTP files through a web interface:

1. SFTP-to-HTTP Proxy with NGINX

This solution uses NGINX as a reverse proxy with authentication:


location /protected/ {
    auth_basic "Restricted Access";
    auth_basic_user_file /etc/nginx/.htpasswd;
    
    proxy_pass http://localhost:8022/;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
}

Combine this with a simple Python bridge script:


from flask import Flask, send_file
import paramiko

app = Flask(__name__)

@app.route('/files/<path:filename>')
def serve_file(filename):
    ssh = paramiko.SSHClient()
    ssh.connect('localhost', username='sftpuser', password='password')
    sftp = ssh.open_sftp()
    return send_file(sftp.open(filename), as_attachment=True)

2. Ready-made Web Clients

Several open-source projects provide web interfaces for SFTP:

  • FileRun: PHP-based with excellent mobile support
  • Pydio: Enterprise-grade file sharing platform
  • Nextcloud+SFTP: Plugin for Nextcloud to mount SFTP

3. Custom Solution with libssh

For maximum control, build a custom web interface using libssh:


#include <libssh/sftp.h>
#include <stdio.h>

int list_files(ssh_session session) {
    sftp_session sftp = sftp_new(session);
    if (sftp == NULL) return -1;
    
    sftp_dir dir = sftp_opendir(sftp, "/remote/path");
    if (dir == NULL) return -1;
    
    sftp_attributes file;
    while ((file = sftp_readdir(sftp, dir)) != NULL) {
        printf("%s\n", file->name);
        sftp_attributes_free(file);
    }
    sftp_closedir(dir);
    sftp_free(sftp);
    return 0;
}

The authentication system should work across all access methods:


# PAM configuration for unified auth
auth required pam_unix.so
auth optional pam_ldap.so
account required pam_unix.so

Essential security measures:

  • Implement rate limiting for authentication attempts
  • Use TLS 1.3 for web interface
  • Set proper umask (0027) for uploaded files
  • Regularly audit sftp chroot environments

For high-volume systems:


# In sshd_config
Match Group clients
    ChrootDirectory /var/sftp/%u
    ForceCommand internal-sftp
    AllowTcpForwarding no
    X11Forwarding no
    MaxSessions 10
    MaxStartups 10:30:60

When building a secure file distribution system, we face a fundamental architectural challenge: bridging the gap between the SSH/SFTP protocol stack and web protocols. While SFTP (SSH File Transfer Protocol) provides excellent security through SSH's encryption and authentication mechanisms, it's primarily designed for programmatic access rather than web browser interactions.

Here are three viable approaches to solve this problem:

  1. SFTP-to-Web Gateway: Build a proxy service that translates web requests to SFTP commands
  2. Dual Protocol Server: Implement both SFTP and WebDAV services sharing the same authentication backend
  3. API-First Approach: Create REST endpoints that internally use SFTP while providing web-friendly access

Here's a practical example using Python's Flask framework as an SFTP-to-web gateway:


from flask import Flask, request, send_file
import paramiko
from io import BytesIO

app = Flask(__name__)

@app.route('/files/<path:filepath>', methods=['GET'])
def get_file(filepath):
    username = request.authorization.username
    password = request.authorization.password
    
    try:
        transport = paramiko.Transport(('sftp.example.com', 22))
        transport.connect(username=username, password=password)
        sftp = paramiko.SFTPClient.from_transport(transport)
        
        file_obj = BytesIO()
        sftp.getfo(filepath, file_obj)
        file_obj.seek(0)
        
        transport.close()
        return send_file(file_obj, as_attachment=True, download_name=filepath.split('/')[-1])
    except Exception as e:
        return str(e), 401

if __name__ == '__main__':
    app.run(ssl_context='adhoc')

For higher performance, you can configure Nginx with the ngx_http_auth_request_module:


server {
    listen 443 ssl;
    server_name files.example.com;

    location / {
        auth_request /auth;
        root /srv/sftp/users/$remote_user;
    }

    location = /auth {
        internal;
        proxy_pass http://auth-service:5000/validate;
        proxy_pass_request_body off;
        proxy_set_header Content-Length "";
        proxy_set_header X-Original-URI $request_uri;
    }
}
  • Always use TLS for web access (HTTPS)
  • Implement rate limiting to prevent brute force attacks
  • Consider adding IP whitelisting for sensitive files
  • Regularly rotate credentials and monitor access logs

For clients who need programmatic access, you can provide multiple endpoints:


# SFTP Access
sftp username@sftp.example.com:/userfiles/report.pdf

# Web Access
curl -u username:password https://files.example.com/report.pdf

# API Access
curl -X POST https://api.example.com/token -d '{"user":"...","pass":"..."}'
curl -H "Authorization: Bearer token" https://api.example.com/files/report.pdf

This multi-protocol approach ensures all client needs are met while maintaining security through a unified authentication system.