Abstrax

Projects

The project group sets up a web application: it can create the project directory, record the intended owner, write an nginx virtual host, and save the project's state. Project state is stored as JSON in:

/etc/abstrax/projects/<name>.json
abstrax project <action> [arguments] [flags]

Permissions

add, remove, modify, enable, disable, and reload require root. The read-only commands list and info do not require root.

Project names

A project name may contain letters, digits, underscores, and hyphens, up to 64 characters.

Runtimes and web servers

A project has a runtime and a web server backend.

Runtime Flag Notes
Static --static The default if no runtime flag is given
PHP --php Uses PHP-FPM; set --php-version (default 8.5) and --public-dir
Node.js --node Proxies to a local port set with --proxy-port; set --node-version (default 24)
Ruby --ruby Proxies to a local port set with --proxy-port; set --ruby-version (default 4.0)

The web server defaults to nginx. The --apache flag selects Apache, but Apache support is not yet implemented; use nginx.

Application code

project commands set up server-side infrastructure: the project directory, intended ownership (recorded in state), nginx virtual host, and runtime. They do not deploy application source code.

After creating a project, deploy your code separately — for example with CI/CD, git clone/git pull, rsync, or another deployment tool. Abstrax does not clone repositories or check out branches as part of project add.

Ownership

Abstrax supports two project ownership modes. No separate isolation flag is required — the mode is inferred from whether you supply --user.

Shared web user mode (default)

When you omit --user, Abstrax uses shared web user mode:

Setting Value
Project owner www-data
Project group www-data
Runtime user www-data (via the system PHP-FPM pool)
Default path /var/www/<name>
sudo abstrax project add example.com
# path: /var/www/example.com, owner: www-data:www-data

This preserves existing behaviour. Commands and paths you used before continue to work unchanged.

User isolated mode

When you explicitly pass --user, Abstrax selects user isolated mode automatically:

Setting Value
Project owner the supplied Linux user
Project group that user's primary group
Runtime user the same user (dedicated PHP-FPM pool for PHP projects)
Default path <resolved home directory>/<name>
sudo abstrax project add example.com --user=mike
# path: /home/mike/example.com (home resolved from the system account)

Abstrax resolves the user's real home directory, UID, GID, and primary group from the operating system. It does not use SUDO_USER unless you pass that name explicitly with --user.

Path precedence

User Path Result
omitted omitted /var/www/<name>, www-data:www-data, shared mode
supplied omitted <home>/<name>, user isolated mode
omitted supplied explicit path, www-data:www-data, shared mode
supplied supplied explicit path, user isolated mode

An explicit --path always wins. Without --path, user isolated projects are created under the resolved home directory; shared mode projects use /var/www/<name>.

Path examples (all four combinations)

# 1. No user, no path → /var/www/example, www-data:www-data
sudo abstrax project add example

# 2. User, no path → /home/mike/example, mike:mike
sudo abstrax project add example --user=mike

# 3. Path, no user → /srv/sites/example, www-data:www-data
sudo abstrax project add example --path=/srv/sites/example

# 4. User and path → /srv/sites/example, mike:mike (with validation)
sudo abstrax project add example --user=mike --path=/srv/sites/example

Custom paths in user isolated mode

  • Paths inside the selected user's home directory are allowed (for example /home/mike/projects/example).
  • Paths inside another user's home directory are rejected.
  • Paths outside the user's home are allowed only when inside an approved shared project root configured in /etc/abstrax/config.json.
  • Abstrax never recursively chowns an existing directory owned by another user.
  • Abstrax never uses the approved root itself or a user's home directory as the project directory.

Approved shared project roots

Configure approved roots for user isolated projects outside home directories:

sudo abstrax config set projects.approved_roots /srv/sites /srv/www

Or edit /etc/abstrax/config.json:

{
  "projects": {
    "approved_roots": ["/srv/sites", "/srv/www"]
  }
}

Nginx and PHP in user isolated mode

  • Nginx continues to run as www-data.
  • Abstrax sets the other execute bit (chmod o+x) on existing directories along the path from the user's home to the project so nginx can traverse without filesystem ACLs. This does not grant read access to private home files. Deeper paths inside the project (for example a public directory) are created by your deployment tool and must be readable by the web server once your application is deployed.
  • PHP runs as the project user through a dedicated PHP-FPM pool with a project-specific Unix socket.
  • Socket permissions use listen.mode = 0660 with listen.group = www-data (not 0666).

Project removal

project remove reverses the correct mode:

  • Shared mode: removes the nginx vhost (by default) and project state; existing behaviour is unchanged.
  • User isolated mode: also removes the dedicated PHP-FPM pool and the socket configuration. It does not delete the user's home directory, remove the Linux user, or revert traverse permissions on shared parent directories (other projects in the same home may still need them).

Ownership mode and managed resources are read from project state (/etc/abstrax/projects/<name>.json), not guessed from the filesystem.

Legacy --group flag

In shared mode you may pass --group to record a group in project state. In user isolated mode the primary group is always derived from the selected user.

project add

Create a new project.

abstrax project add <name> [flags]

If --path is not given, the default depends on ownership mode: /var/www/<name> in shared mode, or <home>/<name> when --user is set.

Flag Default Description
--path /var/www/<name> when --user is omitted; <home>/<name> when --user is set Project root path
--nginx true Use nginx (default)
--apache false Use Apache (not yet implemented)
--no-vhost false Do not create a virtual host
--domains Comma-separated domain names
--port 80 HTTP port
--web-root Custom web root directory
--user Linux user for a user-owned project (omit for shared www-data mode)
--group www-data in shared mode Project group for shared mode only
--ssl false Enable SSL (requires certbot)
--email Email for the SSL certificate
--redirect-http true Redirect HTTP to HTTPS
--php false PHP application
--node false Node.js application
--ruby false Ruby application
--static false Static site (default behaviour)
--php-version 8.5 PHP version
--node-version 24 Node.js version
--ruby-version 4.0 Ruby version
--public-dir Public directory relative to the project path
--proxy-port 0 Local port to proxy to (Node.js/Ruby)

Domains are validated. Each must be a well-formed domain name.

If a virtual host will be created (the default), Abstrax checks that the requested web server is installed. When nginx is missing, the command stops with a message pointing you to sudo abstrax web install. Use --no-vhost to create the project directory without this check.

Runtime installation

When you choose a PHP, Node.js, or Ruby runtime, Abstrax checks that the requested version is installed on the server before creating the project. Static projects skip this check.

If the runtime is missing, you see a message like:

PHP 8.5 is not installed on this server.
Abstrax can install PHP 8.5.
Install PHP 8.5 now? [y/N]

The version shown is the one you passed with --php-version, --node-version, or --ruby-version, or the default for that runtime if you omitted the flag.

  • Answer yes (or pass global --yes) and Abstrax installs the runtime, then continues with project creation.
  • Answer no and the command fails with an error; nothing is changed.

The same check runs for project modify when the project uses a PHP, Node.js, or Ruby runtime (for example when you change --php-version to a version that is not yet installed).

Runtime How Abstrax checks What it installs
PHP php{version}-fpm package php{version}-fpm, php{version}-cli, plus extensions from config php.extensions; enables and starts PHP-FPM
Node.js node --version major matches NodeSource repository for the requested major, then nodejs
Ruby ruby --version matches major.minor ruby{version} via apt, or ruby-full as a fallback

PHP extensions are configured server-wide with abstrax config (default: mysql, xml, curl, mbstring, zip, bcmath, gd, intl, redis, sqlite3; pcntl and posix are included in php*-cli). See Config.

Use --dry-run to preview the prompt and installation steps without making changes.

Examples

# Shared static site (default mode)
sudo abstrax project add myapp \
  --domains=myapp.com,www.myapp.com --static

# User isolated PHP application in the user's home
sudo abstrax project add myapp --user=mike \
  --domains=myapp.com --php --public-dir=public

# Shared PHP application with custom path
sudo abstrax project add myapp --path=/var/www/myapp \
  --domains=myapp.com --php --public-dir=public

# PHP application with a specific version
sudo abstrax project add myapp --path=/var/www/myapp \
  --domains=myapp.com --php --php-version=8.4 --public-dir=public

# Node.js application (reverse proxy, uses default Node.js 24)
sudo abstrax project add myapp --path=/var/www/myapp \
  --domains=myapp.com --node --proxy-port=3000

# Node.js application with a specific version
sudo abstrax project add myapp --path=/var/www/myapp \
  --domains=myapp.com --node --node-version=22 --proxy-port=3000

# Ruby application (reverse proxy, uses default Ruby 4.0)
sudo abstrax project add myapp --path=/var/www/myapp \
  --domains=myapp.com --ruby --proxy-port=3000

# Ruby application with a specific version
sudo abstrax project add myapp --path=/var/www/myapp \
  --domains=myapp.com --ruby --ruby-version=3.4 --proxy-port=3000

Example output

Project myapp created.
  Path:       /var/www/myapp
  Web server: nginx
  Domains:    myapp.com, www.myapp.com
  Vhost:      /etc/nginx/sites-available/abstrax-myapp

project remove

Remove a project. This is a destructive command and asks for confirmation unless --yes is given. By default the project files are kept and the nginx virtual host is removed.

sudo abstrax project remove <name> [flags]
Flag Default Description
--remove-vhost true Remove the nginx virtual host
--remove-ssl false Remove the SSL certificate
--delete-files false Delete the project files
--keep-files true Keep the project files (default)
--force false Force removal without confirmation
sudo abstrax project remove myapp --remove-vhost
sudo abstrax project remove myapp --delete-files --force

project modify

Change a project's configuration.

sudo abstrax project modify <name> [flags]
Flag Description
--path Change the project root path
--domains Replace the domain list (comma-separated)
--add-domain Add a single domain
--remove-domain Remove a single domain
--php-version Change the PHP version
--node-version Change the Node.js version
--ruby-version Change the Ruby version
--public-dir Change the public directory
--proxy-port Change the proxy port
sudo abstrax project modify myapp --add-domain=www.myapp.com

project list

List managed projects. Does not require root.

abstrax project list
NAME    PATH              WEB SERVER   RUNTIME   DOMAINS
myapp   /var/www/myapp    nginx        php       myapp.com, www.myapp.com

project info

Show details for a project. Does not require root.

abstrax project info myapp
  Name:          myapp
  Path:          /var/www/myapp
  Web server:    nginx
  Runtime:       php
  PHP version:   8.5
  Public dir:    public
  Domains:       myapp.com, www.myapp.com
  SSL:           no
  Vhost:         /etc/nginx/sites-available/abstrax-myapp
  Owner:         www-data
  Created:       2024-01-01 12:00:00
  Updated:       2024-01-01 12:00:00

project inspect

Inspect a project using the stable v1 API designed for plugins and automation. Does not require root.

abstrax project inspect myapp --json
{
  "api_version": "v1",
  "project": {
    "name": "myapp",
    "path": "/var/www/myapp",
    "user": "www-data",
    "runtime": {
      "type": "php",
      "version": "8.5"
    },
    "domains": ["myapp.com", "www.myapp.com"],
    "services": [
      {
        "name": "worker",
        "type": "worker"
      }
    ]
  }
}

This API exposes non-secret information only. The existing project info --json output remains unchanged for backward compatibility.

project service

Restart or reload project-owned supervisor services. Requires root.

sudo abstrax project service restart <project> <service>
sudo abstrax project service reload <project> <service>

Services must belong to the project — either recorded in project state or named abstrax-<project>-<service> in supervisor. These commands do not wrap arbitrary systemctl calls.

Enable, disable, and reload

sudo abstrax project enable <name>
sudo abstrax project disable <name>
sudo abstrax project reload <name>
  • enable enables the project's nginx virtual host (symlinks it into sites-enabled). The virtual host file is named abstrax-<name> in /etc/nginx/sites-available.
  • disable removes that symlink.
  • reload reloads nginx for the project.