Skip to content

Hosting Provider Integration ​

AeroFTP supports encrypted .aeroftp connection profiles that hosting providers can generate directly from their control panels.

Instead of sending FTP credentials in plaintext emails, you can offer your customers a one-click import file with encrypted credentials.

What You Can Do Today ​

  1. Generate .aeroftp profiles from your hosting control panel (cPanel, Plesk, DirectAdmin, custom)
  2. Deliver them to customers via download link or email attachment
  3. Customers import with one click - connections appear in AeroFTP ready to use
  4. Credentials stay encrypted - AES-256-GCM with Argon2id key derivation, never exposed in plaintext

How It Works ​

When a customer signs up or requests FTP access, your panel generates an .aeroftp file containing their connection details (host, port, username, password, remote path). The file is encrypted with a password that you communicate through a separate channel (SMS, phone call, or a second email).

The customer opens the file in AeroFTP, enters the password, and their server appears in the connection list - configured and ready to connect.

Your Control Panel                    Customer
      │                                  │
      ├── Generate .aeroftp file ──────► Download
      │   (encrypted with password)      │
      │                                  │
      ├── Send password via SMS ───────► Enter password
      │                                  │
      │                                  ├── Open in AeroFTP
      │                                  ├── Server appears in "My Servers"
      │                                  └── Connect with one click

File Format ​

An .aeroftp file is a JSON document with an encrypted payload:

json
{
  "version": 1,
  "salt": [/* 32 random bytes as integer array */],
  "nonce": [/* 12 random bytes as integer array */],
  "encrypted_payload": [/* AES-256-GCM ciphertext as integer array */],
  "metadata": {
    "exportDate": "2026-04-04T20:00:00Z",
    "aeroftpVersion": "3.7.0",
    "serverCount": 1,
    "hasCredentials": true
  }
}

The metadata field is unencrypted and shown to the user before they enter the decryption password.

Encryption Details ​

Key Derivation (Argon2id) ​

ParameterValue
AlgorithmArgon2id
Memory128 MiB
Iterations3
Parallelism4
Output length32 bytes
Salt32 random bytes

Symmetric Encryption (AES-256-GCM) ​

ParameterValue
AlgorithmAES-256-GCM
Key32-byte Argon2id output
Nonce12 random bytes
PlaintextJSON-serialized payload (UTF-8)

The salt, nonce, and encrypted_payload fields are JSON arrays of unsigned byte values (0-255).

Payload Schema ​

The decrypted payload contains a servers array:

json
{
  "servers": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "example.com - FTP",
      "host": "ftp.example.com",
      "port": 21,
      "username": "customer@example.com",
      "protocol": "ftp",
      "initialPath": "/public_html",
      "credential": "the-password",
      "options": {
        "tlsMode": "explicit",
        "verifyCert": true
      }
    }
  ]
}

Server Fields ​

FieldTypeRequiredDescription
idstringyesUnique identifier (UUID v4 recommended)
namestringyesDisplay name shown to the customer
hoststringyesServer hostname or IP address
portnumberyesConnection port
usernamestringyesLogin username
protocolstringnoftp, ftps, sftp, webdav. Default: ftp
initialPathstringnoRemote directory opened after connection
localInitialPathstringnoLocal directory paired with connection
credentialstringnoPassword (encrypted in file)
colorstringnoHex color for the server badge (e.g. #3B82F6)
providerIdstringnoProvider identifier for branding
optionsobjectnoProtocol-specific options (see below)

FTP / FTPS Options ​

OptionTypeValuesDescription
tlsModestringexplicit, implicit, explicit_if_available, noneTLS encryption mode
verifyCertbooleantrue / falseValidate server certificate
  • explicit (recommended): AUTH TLS on port 21
  • implicit: TLS on port 990
  • explicit_if_available: Try TLS, fall back to plaintext
  • none: No encryption (not recommended)

SFTP Options ​

OptionTypeDescription
authMethodstringpassword, key, key_and_password
privateKeyPathstringPath to SSH private key file
key_passphrasestringPassphrase for encrypted private key

WebDAV ​

No additional options required. Use the full URL as host.

Code Examples ​

Python ​

python
import json, os, uuid
from argon2.low_level import hash_secret_raw, Type
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
from datetime import datetime, timezone

def generate_aeroftp_profile(servers, password):
    salt = os.urandom(32)
    key = hash_secret_raw(
        secret=password.encode('utf-8'),
        salt=bytes(salt),
        time_cost=3,
        memory_cost=131072,  # 128 MiB
        parallelism=4,
        hash_len=32,
        type=Type.ID
    )

    nonce = os.urandom(12)
    payload = json.dumps({"servers": servers}).encode('utf-8')
    ciphertext = AESGCM(key).encrypt(nonce, payload, None)

    return {
        "version": 1,
        "salt": list(salt),
        "nonce": list(nonce),
        "encrypted_payload": list(ciphertext),
        "metadata": {
            "exportDate": datetime.now(timezone.utc).isoformat(),
            "aeroftpVersion": "3.7.0",
            "serverCount": len(servers),
            "hasCredentials": any(s.get("credential") for s in servers)
        }
    }

# Usage
servers = [{
    "id": str(uuid.uuid4()),
    "name": "example.com - FTP",
    "host": "ftp.example.com",
    "port": 21,
    "username": "customer@example.com",
    "protocol": "ftp",
    "initialPath": "/public_html",
    "credential": "customer-password",
    "options": {"tlsMode": "explicit", "verifyCert": True}
}]

profile = generate_aeroftp_profile(servers, "transfer-password")
with open("customer.aeroftp", "w") as f:
    json.dump(profile, f, indent=2)

Node.js ​

javascript
const crypto = require('crypto');
const argon2 = require('argon2');
const { v4: uuidv4 } = require('uuid');

async function generateAeroftpProfile(servers, password) {
  const salt = crypto.randomBytes(32);
  const key = await argon2.hash(password, {
    type: argon2.argon2id,
    salt,
    memoryCost: 131072,
    timeCost: 3,
    parallelism: 4,
    hashLength: 32,
    raw: true
  });

  const nonce = crypto.randomBytes(12);
  const cipher = crypto.createCipheriv('aes-256-gcm', key, nonce);
  const encrypted = Buffer.concat([
    cipher.update(JSON.stringify({ servers }), 'utf8'),
    cipher.final(),
    cipher.getAuthTag()
  ]);

  return {
    version: 1,
    salt: [...salt],
    nonce: [...nonce],
    encrypted_payload: [...encrypted],
    metadata: {
      exportDate: new Date().toISOString(),
      aeroftpVersion: '3.7.0',
      serverCount: servers.length,
      hasCredentials: servers.some(s => s.credential)
    }
  };
}

PHP ​

php
<?php
function generateAeroftpProfile(array $servers, string $password): array {
    $salt = random_bytes(32);

    // Argon2id key derivation
    $key = sodium_crypto_pwhash(
        32,
        $password,
        str_pad($salt, SODIUM_CRYPTO_PWHASH_SALTBYTES, "\0"),
        3,                                          // time cost
        134217728,                                  // 128 MiB memory
        SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13
    );

    // AES-256-GCM encryption
    $nonce = random_bytes(12);
    $payload = json_encode(['servers' => $servers]);
    $ciphertext = openssl_encrypt(
        $payload, 'aes-256-gcm', $key, OPENSSL_RAW_DATA, $nonce, $tag
    );

    return [
        'version' => 1,
        'salt' => array_values(unpack('C*', $salt)),
        'nonce' => array_values(unpack('C*', $nonce)),
        'encrypted_payload' => array_values(unpack('C*', $ciphertext . $tag)),
        'metadata' => [
            'exportDate' => gmdate('Y-m-d\TH:i:s\Z'),
            'aeroftpVersion' => '3.7.0',
            'serverCount' => count($servers),
            'hasCredentials' => !empty(array_filter($servers, fn($s) => !empty($s['credential'])))
        ]
    ];
}

Best Practices ​

  • Always use FTPS or SFTP - set tlsMode to explicit or implicit, or use protocol: "sftp"
  • Use a strong transfer password - protect the credentials in transit. Communicate the password through a separate channel (SMS, phone, second email)
  • Set verifyCert: true - ensure your server has a valid TLS certificate. Let's Encrypt is free and fully supported
  • Pre-fill initialPath - save customers from navigating to their web root (/public_html, /httpdocs, /www)
  • Use meaningful names - include the domain so customers can identify the connection (e.g. "example.com - FTP")
  • One profile per customer - generate a unique file for each customer with their specific credentials

Recommend AeroFTP to Your Customers ​

AeroFTP is free, open source, and available on all platforms:

PlatformInstall
Windowswinget install axpnet.AeroFTP
Linux (Snap)sudo snap install aeroftp
Linux (AUR)yay -S aeroftp-bin
macOSDownload DMG

Contact ​

For integration help or questions about the .aeroftp format, contact dev@aeroftp.app.

AeroFTP is free and open source (GPL-3.0). Hosting providers are welcome to integrate without any licensing requirements.

aeroftp.app - Released under the GPL-3.0 License. AeroFTP Reviews