File Transfer from Host to Linux Virtual Machine

A guide to transferring files using Python HTTP server and client scripts

Overview

This guide explains how to transfer files from a host PC (IP: 192.168.1.20) to a Linux Virtual Machine (VM, IP: 192.168.1.22) using Python scripts. The VM runs a server (`file_server.py`) to receive files, and the host runs a client (`file_client.py`) to send them over HTTP on port 8000. Wireless LAN adapter Wi-Fi:
IPv4 Address: 192.168.1.20
Subnet Mask: 255.255.255.0
Default Gateway: 192.168.1.1

Requirements

Setup

On the VM (Server)

  1. Save the file_server.py script to a directory (e.g., /home/YourName).
  2. Ensure the upload directory (/tmp/uploads) has write permissions.
  3. Install dependencies: sudo apt install python3 lsof.
  4. This code works without openning port 8000, but if you encounter a “Connection refused” error when running the client script, you may need to open port 8000 on the VM's firewall.
    If needed, open port 8000: sudo ufw allow 8000.
    You might need to open port 8000 on your Linux VM using sudo ufw allow 8000 because the Python server script (file_server.py) listens for incoming connections on port 8000 to receive files from the host PC. If the port is blocked by the VM's firewall, the host's client script (file_client.py) won't be able to connect, resulting in a “Connection refused” error. Here's a concise explanation of why this step might be necessary and how it fits into your file transfer setup.

On the Host (Client)

  1. Save the file_client.py script to a directory.
  2. Install requests: pip install requests.
  3. Update the server_url to http://192.168.1.22:8000 and file_path to your file's path.

Why sudo ufw allow 8000?

The command sudo ufw allow 8000 configures the firewall to permit incoming connections on port 8000:

Here's a breakdown of the command:

Verification

Confirm that port 8000 is open and the server is reachable:

Security Considerations

IP Table Setup

Code

file_server.py (Run on VM)

import os
import socket
import subprocess
from http.server import HTTPServer, BaseHTTPRequestHandler

UPLOAD_DIR = "/tmp/uploads"  # Changed to /tmp for better permissions

def get_ip_address():
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s.connect(("8.8.8.8", 80))
        ip = s.getsockname()[0]
        s.close()
        return ip
    except Exception as e:
        return f"Could not determine IP: {e}"

def kill_process_on_port(port):
    try:
        result = subprocess.run(['lsof', '-i', f':{port}'], capture_output=True, text=True)
        lines = result.stdout.splitlines()
        for line in lines[1:]:
            pid = line.split()[1]
            subprocess.run(['kill', '-9', pid])
            print(f"Killed process {pid} on port {port}")
    except subprocess.CalledProcessError:
        print(f"No process found on port {port}")

def check_directory_permissions(directory):
    try:
        os.makedirs(directory, exist_ok=True)
        test_file = os.path.join(directory, ".test_write")
        with open(test_file, 'w') as f:
            f.write("test")
        os.remove(test_file)
        return True
    except PermissionError:
        print(f"Permission denied: Cannot write to {directory}")
        return False
    except Exception as e:
        print(f"Error checking permissions for {directory}: {e}")
        return False

class FileUploadHandler(BaseHTTPRequestHandler):
    def do_POST(self):
        content_length = int(self.headers['Content-Length'])
        filename = self.headers.get('X-Filename', 'uploaded_file')
        file_path = os.path.join(UPLOAD_DIR, filename)

        try:
            with open(file_path, 'wb') as f:
                f.write(self.rfile.read(content_length))
            self.send_response(200)
            self.send_header('Content-type', 'text/plain')
            self.end_headers()
            self.wfile.write(b'File uploaded successfully')
        except Exception as e:
            self.send_response(500)
            self.send_header('Content-type', 'text/plain')
            self.end_headers()
            self.wfile.write(f'Upload failed: {str(e)}'.encode())

def run(server_class=HTTPServer, handler_class=FileUploadHandler, port=8000):
    if not check_directory_permissions(UPLOAD_DIR):
        print(f"Cannot proceed: No write permissions for {UPLOAD_DIR}")
        return

    kill_process_on_port(port)
    
    ip = get_ip_address()
    print(f"Server IP address: {ip}")
    
    server_address = ('0.0.0.0', port)
    httpd = server_class(server_address, handler_class)
    print(f'Server running on port {port}')
    httpd.serve_forever()

if __name__ == '__main__':
    run()

file_client.py (Run on Host)

import requests
import os

def upload_file(file_path, server_url):
    if not os.path.isfile(file_path):
        print(f"File {file_path} does not exist")
        return

    filename = os.path.basename(file_path)
    with open(file_path, 'rb') as f:
        headers = {'X-Filename': filename}
        response = requests.post(server_url, headers=headers, data=f)
    
    if response.status_code == 200:
        print("File uploaded successfully")
    else:
        print(f"Upload failed: {response.text}")

if __name__ == '__main__':
    server_url = 'http://10.0.2.xx:8000'  # VM's IP address
    file_path = '/path/to/your/file.txt'  # Adjust to your file's path
    upload_file(file_path, server_url)

Usage

On the VM

  1. Run the server: python3 file_server.py.
  2. The server will display the VM's IP (e.g., 10.0.2.xx) and confirm port 8000 is free.
  3. Files will be saved to /tmp/uploads.

On the Host

  1. Update file_path in file_client.py to your file's path (e.g., '/home/user/file.txt' or 'C:/Users/YourName/file.txt').
  2. Run the client: python3 file_client.py.
  3. Check the VM's /tmp/uploads directory for the transferred file.

Troubleshooting

Networking Notes

The host (192.168.252.1) and VM (10.0.2.xx) may be on different subnets due to Bridged networking. If the host cannot reach the VM: