Skip to content

FTP

FTP accounts per webapp.

All endpoints below are mounted under /api. Authentication: Authorization: Bearer <token> unless noted as public.

Endpoint count: 7

Endpoints

Method Path Handler Guards
GET /api/ftp/accounts getFTPAccountsByUsername RequirePermission(db, "websites_management")
POST /api/ftp/accounts createFTPAccountByUsername RequirePermission(db, "websites_management")
DELETE /api/ftp/accounts/:id deleteFTPAccount RequirePermission(db, "websites_management")
PATCH /api/ftp/accounts/:id updateFTPAccount RequirePermission(db, "websites_management")
GET /api/ftp/status getFTPStatus RequirePermission(db, "websites_management")
GET /api/ftp/webapps/:id/accounts getFTPAccounts RequirePermission(db, "websites_management")
POST /api/ftp/webapps/:id/accounts createFTPAccount RequirePermission(db, "websites_management")

Source

Handlers for this section live in api/routes/handlers_*.go in the StarkOne source. Each handler binds its request body with gin.ShouldBindJSON(&req) and responds with a flat (non-enveloped) JSON body - there is no { "data": ... } wrapper. List endpoints return { "accounts": [...] }, create endpoints return { "success": true, "username": ... }, and delete/update return { "success": true }. See each endpoint below for its exact shape.

On error:

{ "error": { "code": "string", "message": "string" } }

Reference

GET /api/ftp/accounts

Lists FTP accounts for a site identified by its site username, by scanning the FTP password file for entries prefixed with <username>_.

Guards: RequirePermission(db, "websites_management")

Query parameters

Name Type Optional Description
username string no Site username whose FTP accounts to list. Used to look up the webapp and to filter password-file entries by the <username>_ prefix.

Response - 200 OK

This handler returns a flat (non-enveloped) body. home_dir is read from each per-user vsftpd config file's local_root= line. If the password file cannot be read, accounts is an empty array.

{
  "accounts": [
    { "username": "user1_backup", "home_dir": "/home/user1/domains/example.com/public_html" }
  ]
}

Errors

Status Code Meaning
400 bad_request username query parameter is missing.
404 not_found No webapp exists with the given site username.

Example

curl -X GET "https://panel.example.com:2087/api/ftp/accounts?username=user1" \
  -H "Authorization: Bearer $TOKEN"

POST /api/ftp/accounts

Creates an FTP account for a site (identified by site_user in the body), hashing the password with openssl passwd -1, appending it to the FTP password file, and writing a per-user vsftpd config.

Guards: RequirePermission(db, "websites_management")

Request body

{
  "username": "string (required)",
  "password": "string (required)",
  "home_dir": "string (optional)",
  "site_user": "string (required)"
}
Field Type Required Description
username string yes FTP sub-username. Must match ^[a-zA-Z0-9_]+$ (English letters, digits, underscore only). The stored account becomes <site_user>_<username>.
password string yes Plaintext password; hashed via openssl passwd -1 before storage.
home_dir string no Home directory. Absolute path (leading /) is used as-is; a relative path is resolved under /home/<site_user>/<home_dir>. If empty, defaults to /home/<site_user>/domains/<domain>/public_html.
site_user string yes Site username used to look up the webapp domain and to prefix the FTP account name.

Response - 200 OK

Flat (non-enveloped) body. username is the fully-qualified stored FTP username.

{ "success": true, "username": "user1_backup" }

Errors

Status Code Meaning
400 bad_request Request body failed to bind (missing required field or invalid JSON).
400 invalid_username username contains characters outside [a-zA-Z0-9_].
400 exists An FTP account with this name already exists in the password file.
404 not_found No webapp exists for the given site_user.
500 hash_error openssl passwd failed to produce a hash.
500 file_error The FTP password file could not be opened for writing.

Side effects

  • Runs openssl passwd -1 <password> to hash the password.
  • Appends <ftpUser>:<hash> to /etc/starkone/ftp-passwords (mode 0600).
  • Creates /etc/vsftpd/users if missing and writes /etc/vsftpd/users/<ftpUser> with local_root and guest_username.

Example

curl -X POST https://panel.example.com:2087/api/ftp/accounts \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"username":"backup","password":"s3cret","site_user":"user1","home_dir":"public_html"}'

DELETE /api/ftp/accounts/:id

Deletes an FTP account by removing its line from the password file and deleting its per-user vsftpd config.

Guards: RequirePermission(db, "websites_management")

Path parameters

Name Type Description
id string The fully-qualified FTP username (e.g. user1_backup). Despite the name, this is the username, not a numeric ID - storage is file-based.

Response - 200 OK

Flat (non-enveloped) body.

{ "success": true }

Errors

Status Code Meaning
400 bad_request The :id path segment is empty.
404 not_found The password file does not exist, or no matching account line was found.

Side effects

  • Rewrites /etc/starkone/ftp-passwords (mode 0600) with the matching line removed.
  • Removes /etc/vsftpd/users/<username>.

Example

curl -X DELETE https://panel.example.com:2087/api/ftp/accounts/user1_backup \
  -H "Authorization: Bearer $TOKEN"

PATCH /api/ftp/accounts/:id

Updates an FTP account's password and/or home directory; each field is applied only if non-empty.

Guards: RequirePermission(db, "websites_management")

Path parameters

Name Type Description
id string The fully-qualified FTP username (e.g. user1_backup). File-based storage, so this is the username, not a numeric ID.

Request body

Both fields are optional. Neither carries binding:"required"; an empty body binds successfully and results in no changes.

{
  "password": "string (optional)",
  "home_dir": "string (optional)"
}
Field Type Required Description
password string no If non-empty, hashed via openssl passwd -1 and replaces the account's password-file line.
home_dir string no If non-empty, sets a new local_root. Absolute paths used as-is; relative paths resolved under /home/<guest_username>/<home_dir>, where guest_username is read from the existing per-user config.

Response - 200 OK

Flat (non-enveloped) body.

{ "success": true }

Errors

Status Code Meaning
400 bad_request The :id path segment is empty, or request body failed to bind.
404 not_found A password was supplied but no matching account line was found.
500 hash_error openssl passwd failed to produce a hash.

Side effects

  • If password set: runs openssl passwd -1 and rewrites /etc/starkone/ftp-passwords (mode 0600) with the updated line.
  • If home_dir set: rewrites /etc/vsftpd/users/<username> (mode 0644) with the new local_root.

Example

curl -X PATCH https://panel.example.com:2087/api/ftp/accounts/user1_backup \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"password":"newpass","home_dir":"/home/user1/files"}'

GET /api/ftp/status

Reports whether the FTP plugin is enabled, whether the FTP service is running, and whether FTPS is configured.

Guards: RequirePermission(db, "websites_management")

Response - 200 OK

Flat (non-enveloped) body. enabled comes from the plugins table (id = 'ftp'). running is true if systemctl is-active reports active for vsftpd or proftpd. ftps is true if /etc/vsftpd.conf contains ssl_enable=YES.

{ "enabled": true, "running": true, "ftps": true }

Errors

None returned explicitly; the handler always responds 200.

Example

curl -X GET https://panel.example.com:2087/api/ftp/status \
  -H "Authorization: Bearer $TOKEN"

GET /api/ftp/webapps/:id/accounts

Lists FTP accounts for a webapp identified by its numeric ID, by scanning the password file for entries prefixed with the site username.

Guards: RequirePermission(db, "websites_management")

Path parameters

Name Type Description
id integer Numeric webapp ID. Used to look up the site username, which prefixes the FTP account names to filter on.

Response - 200 OK

Flat (non-enveloped) body. home_dir is read from each per-user vsftpd config's local_root= line. If the password file cannot be read, accounts is an empty array.

{
  "accounts": [
    { "username": "user1_backup", "home_dir": "/home/user1/domains/example.com/public_html" }
  ]
}

Errors

Status Code Meaning
400 bad_request The :id path segment is not a valid integer.
404 not_found No webapp exists with the given ID.

Example

curl -X GET https://panel.example.com:2087/api/ftp/webapps/42/accounts \
  -H "Authorization: Bearer $TOKEN"

POST /api/ftp/webapps/:id/accounts

Creates an FTP account for a webapp identified by its numeric ID, hashing the password, appending it to the password file, and writing a per-user vsftpd config.

Guards: RequirePermission(db, "websites_management")

Path parameters

Name Type Description
id integer Numeric webapp ID. Used to look up the site domain and username.

Request body

{
  "username": "string (required)",
  "password": "string (required)",
  "home_dir": "string (optional)"
}
Field Type Required Description
username string yes FTP sub-username. Must match ^[a-zA-Z0-9_]+$. The stored account becomes <site_username>_<username>.
password string yes Plaintext password; hashed via openssl passwd -1 before storage.
home_dir string no Home directory. Absolute path used as-is; relative path resolved under /home/<site_username>/<home_dir>. If empty, defaults to /home/<site_username>/domains/<domain>/public_html.

Response - 200 OK

Flat (non-enveloped) body. username is the fully-qualified stored FTP username.

{ "success": true, "username": "user1_backup" }

Errors

Status Code Meaning
400 bad_request The :id path segment is not a valid integer, or request body failed to bind.
400 invalid_username username contains characters outside [a-zA-Z0-9_].
400 exists An FTP account with this name already exists in the password file.
404 not_found No webapp exists with the given ID.
500 hash_error openssl passwd failed to produce a hash.
500 file_error The FTP password file could not be opened for writing.

Side effects

  • Runs openssl passwd -1 <password> to hash the password.
  • Appends <ftpUser>:<hash> to /etc/starkone/ftp-passwords (mode 0600).
  • Creates /etc/vsftpd/users if missing and writes /etc/vsftpd/users/<ftpUser> with local_root and guest_username.

Example

curl -X POST https://panel.example.com:2087/api/ftp/webapps/42/accounts \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"username":"backup","password":"s3cret","home_dir":"public_html"}'