Use OnionShare for encrypted peer-to-peer file transfer without intermediaries: it creates a Tor onion address that the recipient accesses directly from your machine, keeping files off all servers. Alternatively, use age encryption combined with SFTP or rsync to send encrypted files directly to the recipient’s server, or use the age-encrypted-backup pattern for offline transfer via USB drives. All three methods avoid cloud services entirely while keeping data encrypted end-to-end.
Table of Contents
- Why Avoid Third-Party File Sharing Services
- Prerequisites
- Best Practices for Secure File Transfer
- Troubleshooting
Why Avoid Third-Party File Sharing Services
Cloud file sharing services create multiple attack surfaces. The service operator can read your files, their servers can be breached, and metadata about your communications remains visible. Additionally, many services impose file size limits or require account creation. When dealing with sensitive documents, backups, code repositories, or personal media, you deserve better control over your data.
Peer-to-peer encrypted file transfer keeps your data on your machines until the exact moment of transfer. No cloud storage, no intermediate servers, and no persistent copies anywhere except on the intended recipient’s device.
Prerequisites
Before you begin, make sure you have the following ready:
- A computer running macOS, Linux, or Windows
- Terminal or command-line access
- Administrator or sudo privileges (for system-level changes)
- A stable internet connection for downloading tools
Step 1 - Use age Encryption for File Transfer
The age encryption tool (age-encryption.org) provides modern, secure file encryption using X25519 public keys or passphrase-based encryption. It’s designed as a replacement for age-old PGP with simpler syntax and better defaults.
Installing age
On macOS:
brew install age
On Linux:
sudo apt install age
Encrypting Files with age
Generate a keypair for the recipient:
age-keygen -o recipient_key.txt
cat recipient_key.txt
Public key - age1EXAMPLE...
Encrypt a large file using the recipient’s public key:
age -r age1EXAMPLE... largefile.zip > largefile.zip.encrypted
For passphrase-based encryption (when you can’t exchange keys):
age -p -o largefile.zip.encrypted largefile.zip
Enter passphrase when prompted
Decrypting Files
Recipient decrypts using their private key:
age -d -i recipient_key.txt largefile.zip.encrypted > largefile.zip
Or with a passphrase:
age -d -o decrypted_largefile.zip largefile.zip.encrypted
The encrypted file can now be sent through any channel, email attachment, USB drive, or temporary file hosting, without exposing the contents.
Step 2 - Use OpenPGP for Large File Encryption
OpenPGP remains the standard for encrypted file transfer. Modern implementations handle large files efficiently with proper streaming.
Encrypting with GPG
Generate a keypair if you don’t have one:
gpg --full-generate-key
Select RSA 4096, no expiration for simplicity
Encrypt a large file:
gpg --encrypt --armor --recipient recipient@example.com largefile.tar.gz
Output - largefile.tar.gz.asc
The recipient decrypts with:
gpg --decrypt largefile.tar.gz.asc > largefile.tar.gz
For streaming very large files without buffering everything in memory, GPG handles this automatically with its symmetric key encryption mode:
gpg --symmetric --cipher-algo AES256 largefile.iso
Step 3 - Onion Share: Peer-to-Peer Through Tor
Onion Share creates a temporary Tor hidden service that lets recipients download files directly from your computer. The file never touches a third-party server, transfers occur entirely peer-to-peer through the Tor network.
Basic Onion Share Usage
Install Onion Share:
brew install onionshare
Launch the GUI or use the CLI:
onionshare --file largefile.zip
Onion Share displays a unique .onion URL. Share this URL with your recipient (who needs Tor Browser). When they visit, they can download the file directly from your machine. The link expires automatically when transfer completes or after a configurable timeout.
For CLI usage with specific options:
onionshare --persistent --title "Secure Transfer" --schedule 1h largefile.zip
This creates a link valid for one hour that can be used multiple times.
Step 4 - Build Custom Transfer Scripts
For automated workflows or integration into applications, build custom peer-to-peer transfer solutions.
Simple Web Server Transfer with Encryption
Create a self-destructing transfer script:
#!/usr/bin/env python3
import http.server
import socketserver
import os
import threading
import time
import hashlib
PORT = 8000
FILE_PATH = "secure_file.zip"
MAX_DOWNLOADS = 1
download_count = 0
download_lock = threading.Lock()
class TransferHandler(http.server.SimpleHTTPRequestHandler):
def do_GET(self):
global download_count
with download_lock:
if download_count >= MAX_DOWNLOADS:
self.send_error(403, "Transfer limit reached")
return
download_count += 1
# Verify hash to ensure file integrity
self.send_response(200)
self.send_header('Content-Type', 'application/zip')
self.send_header('Content-Disposition', f'attachment; filename="{os.path.basename(FILE_PATH)}"')
self.end_headers()
with open(FILE_PATH, 'rb') as f:
self.wfile.write(f.read())
print(f"File transferred. Server shutting down.")
threading.Timer(1, lambda: os._exit(0)).start()
def log_message(self, format, *args):
pass # Silence logging
Generate one-time token
token = hashlib.sha256(str(time.time()).encode()).hexdigest()[:8]
print(f"Starting transfer server for {FILE_PATH}")
print(f"Token: {token}")
print("Press Ctrl+C to stop")
with socketserver.TCPServer(("", PORT), TransferHandler) as httpd:
httpd.serve_forever()
Before running this, encrypt the file using age or GPG. The recipient needs the encryption key through a separate secure channel.
Using scp with Jump Hosts
For direct transfers between servers:
Transfer through an intermediate bastion host
scp -o "ProxyJump bastion@example.com" largefile.tar.gz user@internal-server:/path/
Or set up persistent port forwarding
ssh -L 2222:internal-server:22 bastion@example.com
Then in another terminal:
scp -P 2222 largefile.tar.gz localhost:/path/
Combine with encrypted archives for additional security:
Create encrypted archive
tar czf - largefile/ | age -p -o archive.tar.gz.age
Extract on recipient side
age -d -o - archive.tar.gz.age | tar xzf - -C /destination/
Best Practices for Secure File Transfer
When transferring sensitive files, follow these guidelines:
Use independent channels for keys and files. If you send an encrypted file via email, share the decryption key through Signal, a phone call, or in person. This prevents compromise of a single channel from exposing your data.
Verify file integrity. Always share a checksum separately:
sha256sum largefile.zip > checksums.txt
Set expiration on transfers. When using Onion Share or similar tools, configure automatic link expiration. The recipient should download and verify immediately.
Consider forward secrecy. Tools like Signal and similar messaging apps provide automatic forward secrecy, the same file sent through these channels gets new encryption keys for each session. For files, age with ephemeral keys or GPG with proper key management provides similar properties when keys rotate.
Troubleshooting
Configuration changes not taking effect
Restart the relevant service or application after making changes. Some settings require a full system reboot. Verify the configuration file path is correct and the syntax is valid.
Permission denied errors
Run the command with sudo for system-level operations, or check that your user account has the necessary permissions. On macOS, you may need to grant terminal access in System Settings > Privacy & Security.
Connection or network-related failures
Check your internet connection and firewall settings. If using a VPN, try disconnecting temporarily to isolate the issue. Verify that the target server or service is accessible from your network.
Frequently Asked Questions
How long does it take to send large encrypted files without uploading?
For a straightforward setup, expect 30 minutes to 2 hours depending on your familiarity with the tools involved. Complex configurations with custom requirements may take longer. Having your credentials and environment ready before starting saves significant time.
What are the most common mistakes to avoid?
The most frequent issues are skipping prerequisite steps, using outdated package versions, and not reading error messages carefully. Follow the steps in order, verify each one works before moving on, and check the official documentation if something behaves unexpectedly.
Do I need prior experience to follow this guide?
Basic familiarity with the relevant tools and command line is helpful but not strictly required. Each step is explained with context. If you get stuck, the official documentation for each tool covers fundamentals that may fill in knowledge gaps.
Is this approach secure enough for production?
The patterns shown here follow standard practices, but production deployments need additional hardening. Add rate limiting, input validation, proper secret management, and monitoring before going live. Consider a security review if your application handles sensitive user data.
Where can I get help if I run into issues?
Start with the official documentation for each tool mentioned. Stack Overflow and GitHub Issues are good next steps for specific error messages. Community forums and Discord servers for the relevant tools often have active members who can help with setup problems.
Related Articles
- Magic Wormhole Encrypted File Transfer How To Send Files
- How To Send Encrypted Attachments That Recipients Can Open
- Secure File Sharing Tools Comparison: E2E Encrypted
- How to Encrypt Files Before Cloud
- Best Encrypted Cloud Storage Free Tier 2026
- Copilot Completions Extremely Slow on Large Python Files Fix
Built by theluckystrike. More at zovo.one